CListCtrl - Wie färbt man den Header?



  • Hallo,

    meine ListCtrl sieht wie folgt aus.

    pList->InsertColumn(0,_T("No."),LVCFMT_LEFT,50);
    pList->InsertColumn(1,_T("Text"),LVCFMT_LEFT,100);
    pList->SetBkColor(BK_COLOR);

    Befüllt wird die Liste mit

    pList->InsertItem(0,"1");
    pList->SetItemText(0,1, "wert1");
    pList->InsertItem(1,"2");
    pList->SetItemText(1,1, "wert2");
    pList->InsertItem(2,"3");
    pList->SetItemText(2,1, "wert3");

    Leider werden nur die Zeilen 1 bis 3 gefärbt. 😞 Wie kann ich die Spaltenüberschriften "No." und "Text" mit der Hintergrundfarbe färben? Im Augenblick habe ich immer das StandardWindows grau.


  • Mod

    Man muss den Header subclassen und am besten CustomDraw (NM_CUSTOMDRAW verwenden...

    In deisem Artikel steht einiges grundsätzliches:
    http://www.codeproject.com/KB/combobox/headerctrl.aspx

    Zumindest knnast Du damit die Header Control Notifications behandeln. NM_CUSTOMDRAW beispiele müsstest Du Dir noch suchen, die gibt es kaum für CHeaderCtrl.

    Und das ist ein Ownerdraw sample (ist aber IMHO zu kompliziert):
    http://www.codeproject.com/KB/combobox/skinlist.aspx



  • Danke für die Links

    Leider klappt die Umsetzung noch nicht ganz. Die Hintergrundfarbe wird zwar jetzt richtig gesetzt, aber die Schrift ist jetzt auch in der Hintergrundfarbe und nicht schwarz.

    void MyProgram::OnNMCustomdrawListPrint(NMHDR *pNMHDR, LRESULT *pResult)
    {
    LPNMCUSTOMDRAW pNMCD = reinterpret_cast<LPNMCUSTOMDRAW>(pNMHDR);

    CHeaderCtrl * hCtrl = m_ListPrint.GetHeaderCtrl();
    CDC *cdc = hCtrl->GetWindowDC();
    CRect r;
    hCtrl->GetClientRect(&r);
    CBrush b;

    b.CreateSolidBrush(BK_COLOR);
    cdc->FillRect(&r, &b);

    CPaintDC dc(this);

    b.DeleteObject();

    *pResult = 0;

    }



  • Du solltest unbedingt CDC::FromHandle mit dem HDC aus LPNMCUSTOMDRAW nutzen, da werden etwaige TempMaps im idle processing der app automatisch wieder gelöscht. Zudem sollte man i.d.R. dwDrawStage überprüfen und nur an der 'richtigen' Stelle zeichnen in deinem Fall wäre wohl CDDS_PREPAINT einen Versuch wert. Über uItemState lässt sich zudem der Zustand des Items überprüfen, grayed, focused, etc.

    Edit: ich sehe gerade, daß du auch noch an der falschen Stelle zeichnest. Du mußt dein eigenes HeaderControl von CHeaderCtrl ableiten und dort auf CustomDraw reagieren. Siehe auch Beitrag von Martin Richter.



  • Klasse von CHeaderCtrl ableiten:

    class CColorHeaderCtrl : public CHeaderCtrl
    {
    // Konstruktion
    public:
    	CColorHeaderCtrl();
            virtual ~CColorHeaderCtrl();
    
    	//{{AFX_VIRTUAL(CColorHeaderCtrl)
    	//}}AFX_VIRTUAL
    
    	//{{AFX_MSG(CColorHeaderCtrl)
    	afx_msg void OnPaint();
    	afx_msg void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct);
    	//}}AFX_MSG
    
    	DECLARE_MESSAGE_MAP()
    };
    

    in cpp:

    BEGIN_MESSAGE_MAP(CColorHeaderCtrl, CHeaderCtrl)
    	//{{AFX_MSG_MAP(CColorHeaderCtrl)
    	ON_WM_PAINT()
    	ON_WM_DRAWITEM()
    	//}}AFX_MSG_MAP
    END_MESSAGE_MAP()
    
    void CColorHeaderCtrl::OnPaint() 
    {
    	CPaintDC dc(this); // device context for painting
    
    	CRect rect, rectItem, clientRect;
    	GetClientRect(&rect);
    	GetClientRect(&clientRect);
    
    	COLORREF	clrButtonBG, clrButtonTEXT;
    
    	clrButtonBG	= 0x00FF0000; //Hintergrund BLAU
    	clrButtonTEXT	= 0x00FFFFFF; //Text WEISS
    
    	//get the existing font
    	CFont *pFont = GetFont();
    	CFont* def_font = dc.SelectObject(pFont);
    
    	dc.FillSolidRect(&rect, clrButtonBG);
    	int nItems = GetItemCount();
    
    	for(int i = 0; i <nItems; i++)
    	{
    		TCHAR buf1[256];
    		HD_ITEM hditem1;
    
    		hditem1.mask = HDI_TEXT | HDI_FORMAT | HDI_ORDER;
    		hditem1.pszText = buf1;
    		hditem1.cchTextMax = 255;
    		GetItem( i, &hditem1 );
    
    		GetItemRect(i, &rect);
    
    		//make sure we draw the start piece
    		//on the first item so it has a left border
    
    		//Trennlinie zeichnen (rechts)
    		dc.FillSolidRect(rect.right,
    						 rect.top,
    						 1,
    						 rect.bottom,
    						 clrButtonTEXT);
    
    		//Get all the info for the current
    		//item so we can draw the text to it
    		//in the desired font and style
    		GetItemRect(i, &rectItem);
    
    		UINT uFormat = DT_SINGLELINE | DT_NOPREFIX | DT_TOP |DT_CENTER | DT_END_ELLIPSIS ;
    
    		dc.SetBkMode(TRANSPARENT);
    		rectItem.DeflateRect(2,2,2,2);
    
    		TCHAR buf[256];
    		HD_ITEM hditem;
    
    		dc.SetTextColor(clrButtonTEXT);
    		dc.SetBkColor(clrButtonBG);
    
    		hditem.mask = HDI_TEXT | HDI_FORMAT | HDI_ORDER;
    		hditem.pszText = buf;
    		hditem.cchTextMax = 255;
    		GetItem( i, &hditem );
    
    		dc.DrawText(buf, &rectItem, uFormat);
    	}	
    
    	dc.SelectObject(def_font);
    }
    
    void CColorHeaderCtrl::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) 
    {
    }
    

    Neue Klasse von CListCtrl ableiten (MFC-Klasse):

    class CColorListCtrl : public CListCtrl
    {
    // Konstruktion
    public:
    	CColorListCtrl();
    
    	CColorHeaderCtrl	m_cColorHeaderCtrl;
    

    in cpp:

    void CColorListCtrl::PreSubclassWindow() 
    {
    	//use our custom CHeaderCtrl as long as there
    	//is a headerctrl object to subclass
    
    	if (GetHeaderCtrl())
    	   m_cColorHeaderCtrl.SubclassWindow(GetHeaderCtrl()->m_hWnd);
    
    	CListCtrl::PreSubclassWindow();
    }
    

    Im Programm verwendest du CColorListCtrl anstatt CListCtrl



  • Ich häng' mich mal hier mit ein um keinen neuen Thread zu öffnen.
    Ich habe es ähnlich in meiner Applikation gemacht zusätzlich ändere ich noch die Header Höhe über HDM_LAYOUT. Btw: Wenn OnPaint überladen ist, wird DrawItem nicht mehr ausgeführt.

    Unter Vista läuft alles super, auf virtuellen Maschinen und auch echten System XP, 2003 gibt es einen Zeichenfehler. und zwar wird das HeaderCtrl - ListCtrl liegt auch MainFrame - nicht mehr gezeichnet wenn z.B. ein modaler Dialog bzw. MessageBox aufgerufen wird. Es ist dann alles weiß. Abhilfe schafft

    this->m_HeaderCtrl.Invalidate();
    

    im OnPaint Event des ListCtrl. Weiß jemand woran das liegt?


Log in to reply