Knowledge Base Nr: 00137 OwnerDrawListBox.cpp - http://www.swe-kaiser.de

Downloads:

MFC: sample einer ownerdraw listbox.
in diesem beispiel werden mehrzeilige items mit verschiedenfarbigen Texten aufgebaut.

  
//CListBox ersetzen durch COwnerDrawListBox
//
// Resource: Property settings:
// ------------------
// Has Strings = Yes
// Owner Draw = variable
// Want key input = Yes
// No integral height = YES
// Notify = YES

//sample usage
void CTestOwnerDrawLBView::OnInitialUpdate()
{
CFormView::OnInitialUpdate();
ResizeParentToFit();

const COLORREF R = RGB(255,0,0);
const COLORREF G = RGB(0,255,0);
const COLORREF B = RGB(0,0,255);
const COLORREF S = RGB(0,0,0);

m_lb.AddItemInfo("header1", R, 1, 0);
m_lb.AddItemInfo("header2", G, 12, 1);
m_lb.AddItemInfo("header3", B, 24, 2);
m_lb.AddItemInfo("header4", S, 36, 2);

m_lbHead.Clone(&m_lb, TRUE);

m_lb.AddString("lulli1\tpauler\tmuh\ttest");
m_lb.AddString("vieh\totto\tkuli\tlottel");
m_lb.AddString("amen\tfrau\tkaiser\tneu");
m_lb.AddString("the\tquick\tbrown\tfox");
m_lb.AddString("jumps\tover\tthe\tlaszy dog");
}

// OwnerDrawListbox.h : header file
//
//
// Property settings:
// ------------------
// Has Strings = Yes
// Owner Draw = variable
// Want key input = Yes
// No integral height = YES
// Notify = YES


#ifndef __COwnerDrawListBox_H_
#define __COwnerDrawListBox_H_

/////////////////////////////////////////////////////////////////////////////
// COwnerDrawListBox window

const ROWOFFSET = 2;

class COwnerDrawListBox : public CListBox
{
protected:
CStringArray m_arHead;
CDWordArray m_arCref;
CWordArray m_arRow;
CWordArray m_arCol;

int m_nItemHeight, m_nItemWidth;

int m_wRowCount; //rows per item

virtual BOOL FormatAndDrawItem(CDC *pDC, int nIndex, LPRECT lpRect);
virtual BOOL FormatAndDrawString(CDC *pDC, LPCTSTR lpszStr, LPRECT lpRect);

public:
COwnerDrawListBox();
virtual ~COwnerDrawListBox();

//customize the items
void AddItemInfo(LPCSTR lpszHead, COLORREF cref, WORD wCol, WORD wRow);
void Clone(COwnerDrawListBox* pSource, BOOL bInsertHeader);

//manage entries
int LoadFromFile(LPCSTR fileName); //0 = success

// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(COwnerDrawListBox)
public:
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
virtual int CompareItem(LPCOMPAREITEMSTRUCT lpCompareItemStruct);
virtual void DeleteItem(LPDELETEITEMSTRUCT lpDeleteItemStruct);
virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);
//}}AFX_VIRTUAL

// Generated message map functions
protected:
//{{AFX_MSG(COwnerDrawListBox)
//}}AFX_MSG

DECLARE_MESSAGE_MAP()
};

/////////////////////////////////////////////////////////////////////////////

#endif //__COwnerDrawListBox_H_


// OwnerDrawListbox.cpp : implementation file
//

#include "stdafx.h"
#include "OwnerDrawListbox.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// COwnerDrawListBox

COwnerDrawListBox::COwnerDrawListBox() : m_nItemHeight(0)
{
}


COwnerDrawListBox::~COwnerDrawListBox()
{
}


BEGIN_MESSAGE_MAP(COwnerDrawListBox, CListBox)
//{{AFX_MSG_MAP(COwnerDrawListBox)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// COwnerDrawListBox message handlers

int COwnerDrawListBox::LoadFromFile(LPCSTR fileName)
{
const maxLine = 400;
char line[maxLine];
FILE* fp = fopen(fileName, "rt");
if (fp == NULL)
return 1;

while (! feof(fp))
{
fgets(line, maxLine, fp);

//cut white spaces on line end
for (int i= strlen(line) - 1; i>=0; i--)
{
if (isspace(line[i]))
line[i] = 0;
else
break;
}

AddString(line);
}

fclose(fp);

return 0;
}

void COwnerDrawListBox::AddItemInfo(LPCSTR lpszHead, COLORREF cref, WORD wCol, WORD wRow)
{
if (wRow > m_wRowCount)
m_wRowCount = wRow;

m_arHead.Add(lpszHead);
m_arCref.Add(cref);
m_arRow.Add(wRow);
m_arCol.Add(wCol);
}

void COwnerDrawListBox::DrawItem(LPDRAWITEMSTRUCT lpDIS)
{
//TRACE("id:%d action:%x state:%x \n", lpDIS->itemID, lpDIS->itemAction, lpDIS->itemState);
if (lpDIS->itemID < 0)
return;

CDC *pDC = CDC::FromHandle(lpDIS->hDC);

enum DRAWMODES {M_NONE, M_NORMAL, M_SELECTED } nDrawMode = M_NONE;

if (lpDIS->itemAction & ODA_DRAWENTIRE)
nDrawMode = M_NORMAL;

if (!(lpDIS->itemState & ODS_SELECTED) &&
(lpDIS->itemAction & ODA_SELECT))
nDrawMode = M_NORMAL;

if ((lpDIS->itemState & ODS_SELECTED) &&
(lpDIS->itemAction & (ODA_SELECT | ODA_DRAWENTIRE)))
nDrawMode = M_SELECTED;

LPRECT lpRect = &(lpDIS->rcItem);

switch(nDrawMode)
{
case M_NORMAL:
pDC->BitBlt(0, lpRect->top, lpRect->right, lpRect->bottom-lpRect->top, NULL, 0, 0, WHITENESS); // DSTINVERT);
break;

case M_SELECTED: //show selection as rectangle
pDC->BitBlt(0, lpRect->top, lpRect->right, lpRect->bottom-lpRect->top, NULL, 0, 0, WHITENESS); // DSTINVERT);
pDC->Rectangle(lpRect->left+1, lpRect->top+1, lpRect->right-1, lpRect->bottom-1);
pDC->BitBlt(0, lpRect->top, m_nItemWidth, lpRect->bottom-lpRect->top, NULL, 0, 0, BLACKNESS); // DSTINVERT);
pDC->BitBlt(lpRect->right-m_nItemWidth, lpRect->top, lpRect->right, lpRect->bottom-lpRect->top, NULL, 0, 0, BLACKNESS); // DSTINVERT);
break;
}

if (nDrawMode != M_NONE)
{
BOOL bSucc = FormatAndDrawItem(pDC, lpDIS->itemID, lpRect);
ASSERT(bSucc);
}

if ((lpDIS->itemState & ODS_FOCUS) || (lpDIS->itemAction & ODA_FOCUS))
{
// Item has got the focus
pDC->DrawFocusRect(lpRect);
}
}

int COwnerDrawListBox::CompareItem(LPCOMPAREITEMSTRUCT cs)
{
// return -1 = item 1 sorts before item 2
// return 0 = item 1 and item 2 sort the same
// return 1 = item 1 sorts after item 2

//simply compare the strings
int nRes = strcmp((char *)cs->itemData1, (char *)cs->itemData2);

return nRes;
}

void COwnerDrawListBox::DeleteItem(LPDELETEITEMSTRUCT ds)
{
CListBox::DeleteItem(ds);
}

void COwnerDrawListBox::MeasureItem(LPMEASUREITEMSTRUCT mis)
{
//multiply height of 'A' by the count of rows
if (m_nItemHeight <= 0) //calculate only at the first time
{
CDC *pDC = GetDC();

CSize size = pDC->GetTextExtent("A");
m_nItemWidth = size.cx;
m_nItemHeight = size.cy;
}

mis->itemHeight = (m_wRowCount + 1) * m_nItemHeight + ROWOFFSET*2;

return;
}


BOOL COwnerDrawListBox::FormatAndDrawString(CDC *pDC, LPCTSTR lpszStr, LPRECT lpRect)
{
CString str(lpszStr);

int nPart = 0;
CString strPart;

int nMinSize = m_arHead.GetSize();

while (nPart <= nMinSize)
{
int nPos = str.Find('\t');

if (nPos >= 0)
strPart = str.Left(nPos);
else
strPart = str;

int x = m_nItemWidth * m_arCol[nPart];
int y = m_nItemHeight * m_arRow[nPart] + ROWOFFSET;
ASSERT(m_arRow[nPart] <= m_wRowCount);

//strPart.Format("%d:%d:%d", nPart, m_arCol[nPart], m_arRow[nPart]);

pDC->SetTextColor(m_arCref[nPart]);
pDC->ExtTextOut(x, // x-coordinate of reference point
lpRect->top + y, // y-coordinate of reference point
ETO_CLIPPED , // | ETO_OPAQUE, // text-output options
lpRect, // optional clipping and/or opaquing rectangle
strPart, // points to string
NULL ); // pointer to array of intercharacter spacing values

if (nPos < 0)
break;

str = str.Mid(nPos+1);
nPart++;
}

return TRUE;
}

BOOL COwnerDrawListBox::FormatAndDrawItem(CDC *pDC, int nIndex, LPRECT lpRect)
{
CString str;
GetText(nIndex, str);

BOOL bSucc = FormatAndDrawString(pDC, str, lpRect);

return bSucc;
}

void COwnerDrawListBox::Clone(COwnerDrawListBox* pSource, BOOL bInsertHeader)
{
m_nItemHeight = pSource->m_nItemHeight;
m_nItemWidth = pSource->m_nItemWidth;

m_wRowCount = pSource->m_wRowCount;

m_arHead.Copy(pSource->m_arHead);
m_arCref.Copy(pSource->m_arCref);
m_arRow.Copy(pSource->m_arRow);
m_arCol.Copy(pSource->m_arCol);

int nHeaderCount = m_arHead.GetSize();
if (nHeaderCount == 0)
return;

CString strHeader;

strHeader += m_arHead[0];
for (int n=1; n<m_arHead.GetSize(); n++)
strHeader += "\t" + m_arHead[n];

AddString(strHeader);
}