NM_CUSTOMDRAW mit ListView



  • Hallo C/C++ Forum!
    Ich habe mich mittlerweile etwa 5 Stunden intensivst mit diesem Problem rumgeschlagen und komme einfach nicht weiter!

    Ich habe in meinem Hauptfenster (nicht in einem Dialog - deshalb muss ich nicht SetWindowLong benutzen) ein ListView. Das erstelle ich so:

    InitCommonControls();
    
    HWND hLV = CreateWindow(	WC_LISTVIEW, "",
    							WS_CHILD|WS_VISIBLE|LVS_REPORT|LVS_SINGLESEL,
    							50,220,	350,220,
    							hWnd, (HMENU)ID_QUEUE, GetModuleHandle(NULL), NULL);
    
    SendMessage(hLV, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);		
    SendMessage(hLV, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), 0);
    
    ListView_SetBkColor(	hLV, (COLORREF)RGB(214,223,247));
    
    CreateListViewColumn(hLV, 0, "Col1",		160);
    CreateListViewColumn(hLV, 1, "Col2",		50);
    CreateListViewColumn(hLV, 2, "Col3",			40);
    CreateListViewColumn(hLV, 3, "Col4",		100);
    

    CreateListViewColumn stammt von mir und macht nix anderes als Columns zu erstellen. Funktioniert auch. Ich glaube nicht, dass der Fehler dort liegt (kann es eigentlich ausschließen) aber wenns nötig wird liefer ich den Code nach.

    Nun möchte ich die Farben des ListViews ändern. Dafür benutze ich NM_CUSTOMDRAW weil es mir wichtig ist, dass auch das ausgewählte Item anders gefärbt ist.

    Ich habe schon sehr viel rumprobiert und benutze momentan diese Methode:

    case WM_NOTIFY:
    	{
    		switch (LOWORD(wParam))
    		{
    		// ================================================================
    		case ID_QUEUE:
    			switch ( ((LPNMHDR)lParam)->code )
    			{
    
    			case NM_CUSTOMDRAW:
    				{
    					LPNMLVCUSTOMDRAW	lpCD = (LPNMLVCUSTOMDRAW)lParam;
    
    					// ========================================================
    					switch (lpCD->nmcd.dwDrawStage)
    					{
    					case CDDS_PREPAINT:
    						//SetWindowLong(hWnd, DWL_MSGRESULT, CDRF_NOTIFYITEMDRAW);
    						return CDRF_NOTIFYITEMDRAW;
    
    					case CDDS_ITEMPREPAINT:
    						if (lpCD->nmcd.dwItemSpec == SendMessage(GetDlgItem(hWnd, ID_QUEUE), LVM_GETNEXTITEM, -1, LVNI_SELECTED))
    						{
    							lpCD->clrText	= RGB(255,255,255);
    							lpCD->clrTextBk	= RGB(101,122,216);	
    						}
    						else
    						{
    							lpCD->clrText	= RGB(000,000,000);
    							lpCD->clrTextBk	= RGB(214,223,247);
    						}
    						if (lpCD->nmcd.uItemState & CDIS_HOT)
    							lpCD->clrText = RGB(255,0,0);
    						return CDRF_NEWFONT | CDRF_NOTIFYPOSTPAINT;
    
    					/*case CDDS_ITEMPOSTPAINT:
    						return CDRF_SKIPDEFAULT;
    						if ( lpCD->nmcd.uItemState & CDIS_FOCUS )
    							return CDRF_SKIPDEFAULT;*/
    
    						break;
    					}
    					return CDRF_DODEFAULT;
    					// ========================================================
    
    				}
    
    			default:
    				return false;
    			}
    		// ================================================================
    		}
    
    		return false;
    	}
    

    Das klappt auch ausgezeichnet und so wie sein soll - nur: das ausgewählte Item wird mit diesem Standard-blauer-Balken-mit-weißer-Schrift-und-gestricheltem-Rahmen-dieses-Item-ist-ausgewählt-Dingsbums übermalt! Allerdings nur, wenn das ListView den Focus hat. Liegt der Focus woanders sieht es genau so aus wie ich es haben will.

    Wie schaff ich es nun, das Standard-blauer-Balken-... abzustellen oder auch mit einer eigenen Version zu überschreiben?

    Bitte (wenns geht!) keine MFC-Beispiele (ich benutze reine WinAPI) und keine Links auf Tutorials (die hab ich eh schon alle durch).

    Tausend Dank!!



  • moin meister ...

    der returnwert ist mit das entscheidende ! siehe Kommentare ...
    habe noch eigene Schrift, weil manchmal soll rekursiv gezeichnet werden

    Funktion hat aber nen Fehler, der in meinem Fall nicht auftritt, wenn die Spalten zusammengeschoben werden, wird der Text nicht mit "..." abgeschnitten.

    LRESULT DoNotifyList(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
    	LPNMLISTVIEW	pnm			= (LPNMLISTVIEW)lParam;
    	HBRUSH			hBrushBack	= NULL;
    	HBRUSH			hBrushFrame = NULL;
    	RECT			rc;
    
    	switch (pnm->hdr.code)
    	{
    		case NM_CUSTOMDRAW:
    		{
    			LPNMLVCUSTOMDRAW	lplvcd	= (LPNMLVCUSTOMDRAW)lParam;
    			HWND				hLV		= GetDlgItem(hwnd, wParam);
    			LVITEM				lvi;
    
    			if(lplvcd->nmcd.dwDrawStage == CDDS_PREPAINT)
    				return CDRF_NOTIFYITEMDRAW;
    
    			if(lplvcd->nmcd.dwDrawStage == CDDS_ITEMPREPAINT)
    			{	
    				// BEISPIEL: zeigt an das nur die Farbe geändert wurde, sonst nicht selber zeichnen
    				//if(lplvcd->nmcd.lItemlParam==0)
    				//	return(CDRF_DODEFAULT);
    
    				//lplvcd->clrText = RGB(255, 0, 0);
    				//return CDRF_NEWFONT;
    
    				// in allen Fällen ist Hitergrundmodus TRANSPARENT
    				SetBkMode(lplvcd->nmcd.hdc, TRANSPARENT); 
    
    				int iSubItem= 0;
    				while( iSubItem < Header_GetItemCount(ListView_GetHeader(hLV)) )
    				{
    					// Text holen
    					TCHAR wcBuffer[256] = {0};
    					lvi.iItem = lplvcd->nmcd.dwItemSpec;
    					lvi.iSubItem = iSubItem;
    					lvi.mask = LVIF_TEXT;
    					lvi.pszText = wcBuffer;
    					lvi.cchTextMax = sizeof(wcBuffer) - 1; 
    					if( !ListView_GetItem(hLV, &lvi) )
    						break;
    
    					if( iSubItem == 0)
    					{
    						// unterschiedliche Farben für selektiert
    						if( ListView_GetItemState(hLV, lplvcd->nmcd.dwItemSpec, LVIS_SELECTED) & LVIS_SELECTED)
    						{
    							// selektiert
    							hBrushBack = CreateSolidBrush(RGB(200, 200, 200));
    							SetTextColor(lplvcd->nmcd.hdc, RGB(0, 0, 0));
    						}
    						else
    						{
    							// nicht selectiert
    							hBrushBack = CreateSolidBrush(RGB(255,255,255));
    							SetTextColor(lplvcd->nmcd.hdc, RGB(0, 0, 0));
    						}
    
    						// Item
    						ListView_GetItemRect(hLV, lplvcd->nmcd.dwItemSpec, &lplvcd->nmcd.rc, LVIR_BOUNDS);
    						// etwas vom Rand einrücken
    						lplvcd->nmcd.rc.left += 2;
    						// Hintergrund zeichnen				
    						if( ListView_GetItemState(hLV, lplvcd->nmcd.dwItemSpec, LVIS_SELECTED) & LVIS_SELECTED)
    						{
    							memcpy(&rc, &lplvcd->nmcd.rc, sizeof(rc));
    							rc.left += 2;
    
    							// Rahmen zeichnen
    							HPEN hPenOld = (HPEN)SelectObject(lplvcd->nmcd.hdc, CreatePen(PS_SOLID, 1, RGB(0,0,0)));
    							Rectangle(lplvcd->nmcd.hdc, rc.left, rc.top, rc.right, rc.bottom);
    							DeleteObject(SelectObject(lplvcd->nmcd.hdc, (HGDIOBJ)hPenOld));
    
    							// Hintergrund füllen, ohne Rahmen zu überpinseln
    							memcpy(&rc, &lplvcd->nmcd.rc, sizeof(rc));
    							rc.left += 3;
    							rc.right -= 1;
    							rc.top += 1;
    							rc.bottom -= 1;
    							FillRect(lplvcd->nmcd.hdc, &rc, hBrushBack);	
    							DeleteObject(hBrushBack);
    						}
    						else
    						{
    							// Hintergrund füllen, muß Rahmen wenn vorhanden überdecken !!!
    							memcpy(&rc, &lplvcd->nmcd.rc, sizeof(rc));
    							rc.left += 2;
    							FillRect(lplvcd->nmcd.hdc, &rc, hBrushBack);	
    							DeleteObject(hBrushBack);
    						}
    
    						// noch etwas mehr einrücken 
    						memcpy(&rc, &lplvcd->nmcd.rc, sizeof(rc));
    						rc.left += 4;
    						// Text zeichen
    						DrawText(lplvcd->nmcd.hdc, lvi.pszText, lstrlen(lvi.pszText), &rc, DT_LEFT|DT_VCENTER);
    					}
    					else
    					{
    						// SubItems 
    						ListView_GetSubItemRect(hLV, lplvcd->nmcd.dwItemSpec, iSubItem, LVIR_BOUNDS, &lplvcd->nmcd.rc); 
    						// etwas einrücken
    						lplvcd->nmcd.rc.left += 6;
    						// Text zeichnen
    						DrawText(lplvcd->nmcd.hdc, lvi.pszText, lstrlen(lvi.pszText), &lplvcd->nmcd.rc, DT_LEFT|DT_VCENTER);
    					}
    					iSubItem++;
    				}
    				// zeigt an, daß alles selber gezeichnet wurde
    				return CDRF_SKIPDEFAULT;
    			}
    		}
    
    	default:
    		break;
    	}
    	return 0;
    }
    


  • Mhh... Schonmal vielen Dank für deine Mühe, RED-BARON. Was du da machst ist jetzt das komplette Teil selber zeichnen (soweit ich das erkennen kann). Genau darum wollt ich mich eigentlich drücken 🙂
    Gibt es nicht noch eine andere Lösung?


Anmelden zum Antworten