Ownerdraw Code funktioniert, ist er aber auch richtig?



  • Hallo,

    habs nun endlich hinbekommen meinem Button komplett selbst zu zeichnen und augenscheinlich funktioniert auch alles, jedoch kenn ich mich mit den Draw Routinen nur sehr bescheiden aus, deshalb meine Frage ist der Code auch "safe" oder kann es zu irgendwelchen Leaks kommen? Also hier der Code:

    case WM_DRAWITEM:{
    		HDC			hDC;
    		HBRUSH		hBrush;
    		RECT			rc, rc_icon, rc_color;
    		UINT			state, flag;
    		LPDRAWITEMSTRUCT	di;
    
    		di = (LPDRAWITEMSTRUCT)lParam;
    		state = di->itemState;
    		hDC = GetDC(di->hwndItem);
    		rc = di->rcItem;
    		rc_color = rc_icon = rc;
    		rc_color.left += 6;
    		rc_color.top += 6;
    		rc_color.right -= 17;
    		rc_color.bottom -= 6;
    		rc_icon.left += 5;
    		rc_icon.top += 5;
    		hBrush = CreateSolidBrush(GetSysColor(CTLCOLOR_DLG));
    		FillRect(hDC, &rc, hBrush);
    		hBrush = CreateSolidBrush(RGB(0, 0, 255));
    		if(state & ODS_SELECTED){
    			rc_color.left++;
    			rc_color.top++;
    			rc_color.right++;
    			rc_color.bottom++;
    			rc_icon.left++;
    			rc_icon.top++;
    			flag = EDGE_SUNKEN;
    		}else{
    			flag = EDGE_RAISED;
    		}
    		DrawEdge(hDC, &rc, flag, BF_RECT);
    		if(state & ODS_FOCUS){
    			rc.top += 3;
    			rc.left += 3;
    			rc.right -= 3;
    			rc.bottom -= 3;
    			DrawFocusRect(hDC, &rc);
    		}
    		FillRect(hDC, &rc_color, hBrush);
    		DrawIconEx(hDC, rc_icon.left, rc_icon.top, hIcon, 0, 0, 0, 0, DI_NORMAL);
    		ReleaseDC(di->hwndItem, hDC);
    		return 1;
    	}
    


  • Was Du mit CreateSolidBrush erstellst musst Du auch mit DeleteObject
    wieder frei geben.


  • Mod

    Soweit ich das sehe ist das OK.

    Nur es gibt einfachere Funktionen Buttons zu zeichen:
    DrawFrameControl
    und
    DrawThemeBackground (wenn themeing eingeschaltet ist.



  • Der Aufruf von GetDC/ReleaseDC ist eigentlich unnötig, weil der DC schon fertig in DRAWITEMSTRUCT (di->hDC) daherkommt.


  • Mod

    sri schrieb:

    Der Aufruf von GetDC/ReleaseDC ist eigentlich unnötig, weil der DC schon fertig in DRAWITEMSTRUCT (di->hDC) daherkommt.

    Wie wahr! 👍 Gut aufgepasst...
    Es kann sogar zu Fehlfunktionen führen, denn das List-Ctrl könnte auf die Idee kommen den DC weiter zu nutzen...



  • Ich hab den hDC, also GetDC(...) und ReleaseDC(..), jetzt entfernt. Weiterhin hab ich nach jedem Aufruf von FillRect(...) den Brush mit DeleteObject(...) gelöscht und DrawFrameControl(..) zum Zeichnen des Buttos verwendet. Erwartungsgmäß funktioniert der Code einwandfrei, danke für die Hinweise. Hier nochmal der überarbeitete Code, ich hoffe der ist nun optimal?

    void OwnerDraw_ColorButton(LPARAM lParam, COLORREF mycolor){
    
    	HBRUSH		hBrush;
    	RECT			rc_icon, rc_color;
    	LPDRAWITEMSTRUCT	di;
    
    	di = (LPDRAWITEMSTRUCT)lParam;
    	rc_color = rc_icon = di->rcItem;
    	rc_color.left += 6;
    	rc_color.top += 6;
    	rc_color.right -= 17;
    	rc_color.bottom -= 6;
    	rc_icon.left += 5;
    	rc_icon.top += 5;
    	if(di->itemState & ODS_SELECTED){
    		rc_color.left++;
    		rc_color.top++;
    		rc_color.right++;
    		rc_color.bottom++;
    		rc_icon.left++;
    		rc_icon.top++;
    		DrawFrameControl(di->hDC, &di->rcItem, DFC_BUTTON, DFCS_BUTTONPUSH | DFCS_PUSHED);
    	}else{
    		DrawFrameControl(di->hDC, &di->rcItem, DFC_BUTTON, DFCS_BUTTONPUSH);
    	}
    	if(di->itemState & ODS_FOCUS){
    		di->rcItem.top += 3;
    		di->rcItem.left += 3;
    		di->rcItem.right -= 3;
    		di->rcItem.bottom -= 3;
    		DrawFocusRect(di->hDC, &di->rcItem);
    	}
    	hBrush = CreateSolidBrush(mycolor);
    	FillRect(di->hDC, &rc_color, hBrush);
    	DeleteObject(hBrush);
    	DrawIconEx(di->hDC, rc_icon.left, rc_icon.top, hIcon, 0, 0, 0, 0, DI_NORMAL);
    }
    

Anmelden zum Antworten