Eigener Button - Frage zum Style/zur Funktion



  • Hi Leute,

    ich habe mich hier im WinAPI-Forum mal ein bischen umgesehen und auch ein paar hilfreiche Beiträge zu Owner Draw Buttons gefunden.
    Ich weiss jetzt nicht mehr, wo geneu er war, doch ich habe von einem Beitrag einen Lösungsvorschlag von jemandem übrnommen und etwas geändert.

    Kurze Info vorab. Es soll ein eigener Button erstellt werden, mit folgenden Zuständen:

    Normaler Zustand: http://s14.directupload.net/images/131204/5g8vfcaq.jpg
    Bei Mous-Over: http://s14.directupload.net/images/131204/x4vlbize.jpg
    Beim Klick: http://s1.directupload.net/images/131204/voauclft.jpg

    Die Bilder sind ScreenShots beim Ausführen des Programms.
    Hier der Code:

    //Button-Status
     	bool	defstatus = (s_draw->itemState & ODS_DEFAULT);
    	bool	selstatus = (s_draw->itemState & ODS_SELECTED);
    	bool	focstatus = (s_draw->itemState & ODS_FOCUS);
     	bool	disabled = (s_draw->itemState & ODS_DISABLED);
    
    	//Koordinaten
    	RECT	rect = s_draw->rcItem;
    
    	HDC	       	hDC = s_draw->hDC;
    	Graphics	grafik(hDC);
    
    	//Bilder
    	Image		bild1(L"\\Code1.png");
    	Image		bild2(L"\\Code2.png");
    	Image		bild3(L"\\Code3.png");
    
    	PAINTSTRUCT ps;
    	ps.fErase	= false;
    	ps.rcPaint	= rect;
    	ps.hdc		= hDC;
    
    	BeginPaint(hButton, &ps);
    	{
    		grafik.DrawImage(&bild1, 0, 0, 200, 100);
    
    		if(defstatus == true)
    			grafik.DrawImage(&bild1, 0, 0, 200, 100);
    		else if(selstatus == true)
    			grafik.DrawImage(&bild2, 0, 0, 200, 100);
    		else if(focstatus == true)
    			grafik.DrawImage(&bild3, 0, 0, 200, 100);
    	}
    	EndPaint(hButton, &ps);
    
    	//Aufräumen
    	ReleaseDC(s_draw->hwndItem, hDC);
    
    	return true;
    

    Meine Fragen:

    1. Ich möchte, das Bild1 im normalen Zustand angezeigt wird. Bild2 soll nur dann angezeigt werden,
    wenn die Maus drüber ist. Und Bild3 nur dann, wenn geklickt wurde.

    Jetzt ist es bei mir aber so, das er erst zu Bild2(Grün) wechselt, wenn ich das erste mal geklickt habe und nicht bei mous-over.
    Dann bleibt er auch bei Bild2(Grün). Wenn ich klicke, wechselt er zu Bild3(Blau), bis ich die Maustaste loslasse.
    Dann wechselt er wieder zu Grün. Was muss ich machen?

    2. Ihr seht ja auf den Bildern das weiße Rechteck, welches den Button darstellt. Wie kann ich das weg machen?
    Ich dachte, das bei Owner Draw Buttons garnichts vom Button gezeichnet wird.

    Hoffe ich habe mich ausreichend verständlich ausgedrückt & ihr könnt mir helfen.

    PS: Ich sagte bereits, das ich den Code zum Teil von einem anderen Beitrag hier habe. Wenn jemand mir einen anderen Lösungsweg empfehlt, wäre ich auch darüber dankbar.


  • Mod

    1. Suche "non rectangular button", sollte Dichnicht überfordern.
    2. Scheiß bitte den ReleaseDC raus. Was soll der Dort? Du hast doch BeginPaint und EndPaint...
    3. Macht es wenig Sinn (im Sinne der Performance) bei jedem Paint alle Bilder zu laden, selbst wenn Du diese nicht brauchst. Bzw. solltest Du die Grafik bur einmal laden...



  • ja genau ... sch* ihn einfach raus 😉

    ... oh mann ... wie unqualifiziert ... aber der musste einfach sein :p


  • Mod

    OK. Ein echt guter Typo.

    schMeiß... 🤡



  • Ne Leute, ich werd ihn nicht raussch***en 🕶

    So jetzt zurück zum Thema.
    @Martin Richter
    Meinst du mit non rectangular button Regions, oder was?

    3. Macht es wenig Sinn (im Sinne der Performance) bei jedem Paint alle Bilder zu laden, selbst wenn Du diese nicht brauchst. Bzw. solltest Du die Grafik bur einmal laden...

    Der Code steht in der DrawItem-Funktion, die bei WM_DRAWITEM aufgerufen wird.


  • Mod

    need help schrieb:

    Der Code steht in der DrawItem-Funktion, die bei WM_DRAWITEM aufgerufen wird.

    Und auch da macht es keinen Sinn. Und dann macht dort weder BeginPaint,EndPaintnoch ReleaseDC Sinn!



  • Und auch da macht es keinen Sinn. Und dann macht dort weder BeginPaint,EndPaint noch ReleaseDC Sinn!

    Geb ich dir völlig recht. Ich benutze diese Projektmappe lediglich für Versuche. Da ich den Code zum Teil von nem anderen Beitrag kopiert hab,
    habe ich auch nicht so darauf geachtet, wie "unschön" der Code ist. Mir war nur wichtig, das es funktioniert.
    Ich weiss, das ist echt blöd von mir, werde es auch noch umschreiben.

    Jedoch bleiben meine Fragen immer noch offen(siehe ersten Post).

    Wie kann ich die 3 Zustände korrekt anzeigen(Fehler siehe ersten Post).
    Und kann man den weissen Rechteck vom Button entfernen?


  • Mod

    Du hast doch schon eine Antwort.
    Der weiße Bereich entsteht doch dadurch, dass Dien Bild nicht den Bereich des Buttons füllt.

    Also entweder einen "non rectangular control" bauen. (Habe ich schon gechrieben GidF). Oder den Hintergrund korrekt vorbereiten und nur den "eigentlichen Button" transparent in den Hintergrund zeichnen.



  • Du hast doch schon eine Antwort.
    Der weiße Bereich entsteht doch dadurch, dass Dien Bild nicht den Bereich des Buttons füllt.

    Ach so, ich hatte gehofft, das man den Button irgendwie ganz "ausblenden" könnte. Naja, danke.

    Also entweder einen "non rectangular control" bauen. (Habe ich schon gechrieben GidF). Oder den Hintergrund korrekt vorbereiten und nur den "eigentlichen Button" transparent in den Hintergrund zeichnen.

    Ok, werd ich dann so machen.

    Kleine Frage noch. Es gibt ja diese Item-States wie ODS_DEFAULT oder ODS_SELECTED.
    Wie genau kann ich es machen, dass auch ein eigenes Bild für den fall, das sich die Maus darüber befindet, angezeigt wird?


  • Mod

    need help schrieb:

    Kleine Frage noch. Es gibt ja diese Item-States wie ODS_DEFAULT oder ODS_SELECTED.
    Wie genau kann ich es machen, dass auch ein eigenes Bild für den fall, das sich die Maus darüber befindet, angezeigt wird?

    ODS_HOTLIGHT gibt es IMHO nutr für Comboboxen.

    Aber wo hast Du den hier ein Problem?
    1. Kannst Du beim Zeichnen prüfen ob der Cursor im/auf dem Button steht.
    2. Kannst Du DeinenButton subclassen und so auch mitbekommen wenn die Maus über den Button fährt.
    3. Gibt es TrackMouseEvent mit dem man sogar mit bekommt, dass das Fenster verlassen wird. Da gibt es auch WM_MOUSEHOVER etc...



  • Soweit ich das jetzt verstanden habe(MSDN), sendet TrackMouseEvent unter anderem die Messages WM_MOUSEHOVER & WM_MOUSELEAVE,
    die ich dann bequem abfangen und dem entsprechend darauf reagieren kann.

    Ich bin mir jetzt aber nicht ganz sicher, wo ich die Funktion TrackMouseEvent aufrufen soll. Etwa bei WM_PAINT? Wäre
    toll, wenn du mir da weiterhelfen würdest.



  • in WM_MOUSEMOVE



  • Stimmt, hatte ich total vergessen.



  • Leute, ich komme echt nicht klar. Ich versuche schon die ganze Zeit mit Regions und GDI+(Graphics::Image) meinen Button zu zeichnen. Doch ich weiss nicht,
    wie genau ich das machen muss.

    case WM_DRAWITEM:
    		{
    			pdis = (LPDRAWITEMSTRUCT)lParam;
            }
    

    Ich weiss einfach nicht, wie ich weiter vorgehen muss. Habe mit HRGN und SetWindowRgn() herumprobiert. Wenn ich zum Beispiel eine Ellipse setze,
    dann wird es auch angezeigt, jedoch auch das weisse Rechteck des Buttons.

    Ich weiss, für euch ist es lästig, aber kann mir jemand bitte sagen, wie ich mein Vorhaben umsetzen kann?
    Habe mir auch schon manches im Netzt angeschaut, z.b. das http://www.rohitab.com/discuss/topic/26786-irregular-shaped-buttonswin32/.



  • Hast Du den Button-Style BS_OWNERDRAW gesetzt, sonst erhälst Du nie WM_DRAWITEM?



  • Achte darauf, dass Du das HRGN-Handle nach erfolgreichem SetWindowRgn nicht löschst. Das System übernimmt das Handle und legt keine Kopie an.



  • Hast Du den Button-Style BS_OWNERDRAW gesetzt, sonst erhälst Du nie WM_DRAWITEM?

    Klar hab ich.

    Achte darauf, dass Du das HRGN-Handle nach erfolgreichem SetWindowRgn nicht löschst. Das System übernimmt das Handle und legt keine Kopie an.

    Ja, darauf achte ich auch.

    Wie schon oben geschrieben, wird das Region auch angezeigt, wenn ich z.b. eine Ellipse mit SetWindowRgn() setzte. Nur das Problem ist,
    das diese Ellipse im weissen Rechteck des Buttons ist, dieser also nicht verschwindet. Weiss jemand da weiter?

    Außerdem, kann mir jemand sagen, wie ich ein Bild(Graphics::Image) mit Alpha(PNG)
    durch Regions oder so als meinen Button definieren kann?
    Bei mir klappt es wie schon gesagt nicht.


  • Mod

    Hast Du WS_CLIPCHILDREN definiert? Dann zeichnet das Parent nicht den Untergrund.
    Ansonsten wenn die Region wirklich korrekt gesetzt ist zeichnet das Parent auch den Untergrund.

    Ansonsten habe Ich Dir Transparent BLT schon genannt...



  • Hast Du WS_CLIPCHILDREN definiert?

    Ja, habe ich. Ich habe jetzt mal zum Testen folgenden Code Kopiert:

    case WM_DRAWITEM:
    		{
    			LPDRAWITEMSTRUCT lpdiControl = (LPDRAWITEMSTRUCT)lParam;
    
                if(lpdiControl->CtlType == ODT_BUTTON)
    			{
                    HRGN hrgnButton1 = CreateRectRgn(0, 0, 0, 0);
                    GetWindowRgn(lpdiControl->hwndItem, hrgnButton1);
                    RECT rcClient; GetClientRect(lpdiControl->hwndItem, &rcClient);
    
                    FillRect(lpdiControl->hDC, &lpdiControl->rcItem, (HBRUSH)GetStockObject(DKGRAY_BRUSH));
    
                    if(lpdiControl->itemState & ODS_SELECTED)
    				{
                        rcClient.top += 1, rcClient.left += 1;
                        HRGN hrgnButton2 = CreateEllipticRgnIndirect(&rcClient);
                        FillRgn(lpdiControl->hDC, hrgnButton1, (HBRUSH)GetStockObject(BLACK_BRUSH));
                        FillRgn(lpdiControl->hDC, hrgnButton2, (HBRUSH)GetStockObject(BLACK_BRUSH));
                        DeleteObject(hrgnButton2);
                    }
    				else
    				{
                        rcClient.bottom -= 1, rcClient.right -= 1;
                        HRGN hrgnButton2 = CreateEllipticRgnIndirect(&rcClient);
                        FillRgn(lpdiControl->hDC, hrgnButton1, (HBRUSH)GetStockObject(DKGRAY_BRUSH));
                        FillRgn(lpdiControl->hDC, hrgnButton2, (HBRUSH)GetStockObject(DKGRAY_BRUSH));
                        DeleteObject(hrgnButton2);
                    }
    			}
    		}
    

    Den Code habe ich von http://www.rohitab.com/discuss/topic/26786-irregular-shaped-buttonswin32/ vom Beispiel von Napalm.

    Bei mir sieht das so aus:
    Normal -> http://s7.directupload.net/images/131206/ha2h3inv.jpg
    Geklickt -> http://s14.directupload.net/images/131206/blg3rsgv.jpg

    Wie man sieht, wird das ganze Rechteck mit der Farbe gefüllt, die ich bei der Ellipse als Normal-Zustand habe.

    Vielleicht mach ich auch nur einen dummen Fehler. Wäre also über Antworten glücklich!


  • Mod

    Wie Du unschwer sehen kannst Hast Du nicht das Fenster selbst auf eine abweichende Region gesetzt. Sondern Du zeicnest nur in diese Region.



  • Wie Du unschwer sehen kannst Hast Du nicht das Fenster selbst auf eine abweichende Region gesetzt. Sondern Du zeicnest nur in diese Region.

    Ok, stimmt. Jetzt klappt es. Jedoch komme ich irgendwie nicht mit meinen Bildern(PNG's) weiter.

    Du hast mir ja vorgeschlagen, das ich es mit TransparentBlt() versuchen sollte. Jedoch wird dort eine bestimmte Farbe angegeben,
    die als transparent zu setzen ist. Ich habe hier aber PNG's mit Alpha, die ich benutzen möchte(Geht ja mit GDI+).

    Ich würde es gerne mit AlphaBlend() und der BLENDFUNCTION-Struktur machen. Bis hier hin komme ich noch klar. Jedoch komme ich nicht darauf,
    wie ich dann die HDC an meinen Button verknüpfe, so das nur mein Bild zu sehen ist und dass garnichts vom Button("weisses Rechteck") angezeigt wird.

    Hoffe ihr versteht, was ich meine und könnt mir helfen.

    ⚠ PS: Sorry, das ich erst jetzt antworte, jedoch konnte ich nicht vorher.


Anmelden zum Antworten