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);
}