Kein Hintergrund bei Tree-View
-
Ist doch so: ein Tree-View sollte im Normalzustand einen weissen Hintergrund haben. So ist das auch bei mir - aber nur solange bis ich die C++ Klasse, die mein Tree-View-Fenster kapselt, in eine bestimmte Fensterliste einlinke (normalerweise kommen alle "Windowklassen" meines Programms in diese Liste - die anderen Controls vertragen das ohne Probleme). Aber der Hintergrund des Tree View wird dann schwarz oder behält die Farbe des ParentFensters (je nachdem was ich bei WM_ERASEBACKGROUND zurückgebe). Ich schliesse daraus, dass der Hintergrund überhaupt nicht mehr gemalt wird. Die TVItems & zugehörigen Lines aber schon, ebenso wie der NC Bereich (ThickFrame). Auch wird das WM_PAINT brav an den WindowProc des Tree View weitergeleitet, so dass ich mir nicht erklären kann, was falsch sein soll.
Hat jemand eine Idee?
-
hgf schrieb:
Auch wird das WM_PAINT brav an den WindowProc des Tree View weitergeleitet,
Wie das? Du brauchst doch eigentlich nur Nachrichten zu dispatchen, was muss man da noch weiterleiten?
Aber zum Problem: Für mich hört es sich nach ausgiebigem Gebrauch von WS_CLIPCHILDREN, bzw. WS_CLIPSIBLINGS, an. Schau Dir mal die Z-Order der Windows an und hole gegebenenfalls das TreeView und/ oder dessen Parent weiter nach oben.
-
Wie das? Du brauchst doch eigentlich nur Nachrichten zu dispatchen, was muss man da noch weiterleiten?
Da ich eine C++ Klasse habe, die den WindowProc des Treeview automatisch subklassifiziert, wäre es ja denkbar, dass eine Nachricht für den TreeView "aus Versehen" abgefangen wird. Irgendetwas passiert ja, wenn ich den Tree-View in die besagte Liste einhänge - ich weiss nur nicht was. Vielleicht braucht der Tree View für das Zeichnen des HinterGrundes noch eine andere Nachricht als WM_PAINT.
Dass es an WS_CLIPSIBLINGS oder irgendeinem Verdeckungsproblem liegt, kann ich mir nicht vorstellen. Die Tree-Items werden ja gezeichnet. Sogar der Hintergrund des Parentfensters scheint einfach bestehen zu bleiben, wenn ich WM_ERASEBACKGROUND abfange.
-
hgf schrieb:
Dass es an WS_CLIPSIBLINGS oder irgendeinem Verdeckungsproblem liegt, kann ich mir nicht vorstellen.
Wie meinen? Hast Du nun diese Styles gesetzt oder nicht? Wenn ja, was passiert, wenn Du die Styles weglässt? Aber was rede ich, Du kennst die Antwort ja eh schon ...
-
Hatte jetzt Gelegenheit das zu testen. WS_CLIPSIBLINGS war gesetzt. Wenn ich es weglasse, beim Tree-View oder bei allen Child-Windows, ändert sich aber nichts (wird nur wegen der ComboBoxen benötigt). WS_CLIPCHILDREN kommt in meinem gesamten Code nirgendwo vor.
-
BTW: Wo bearbeitest du WM_ERASEBKGND überhaupt? Doch wohl hoffentlich nicht in der Subclass-Proc des TreeViews, oder?
-
BTW: Wo bearbeitest du WM_ERASEBKGND überhaupt? ... in der Subclass-Proc des TreeViews, oder?
Ja, zwar nicht spezifisch, aber letzlich schon. Das
"case WM_ERASEBKGND:"
steht im statischen CALLBACK WindowProc der Window-BasisKlasse; da wo alle Nachrichten durchlaufen (und dann gegebenenfalls an die spezifischen WindowProcs verzweigt werden).Bearbeitet wird hier aber fast nichts. Ich fange nur die Nachrichten ab, in denen ich das Window ohnehin selber zeichne (gekennzeichnet durch OPTION_PAINTMYSELF - siehe unten, also keine API-Controls ).
Wenn ich es einfach auskommentiere, ändert sich nichts (es scheint so gut wie alle Fenster zeichnen ihren Hintergrund selber und man kann sich die ERASE-Funktion eigentlich sparen).
Für den Tree-View habe ich jetzt einen eigenen If-Zweig eingebaut, um einen (fast-)weissen Hintergrund zu zeichnen. Der Code sieht jetzt so aus:
case WM_ERASEBKGND: if ( pWindow->_Options & OPTION_PAINTMYSELF ) return 1; else if ( pWindow->_RTTI == RTTI_TREEVIEW ) { HDC hdc = (HDC) wParam; VRect rect = pWindow->ClientRect(); ::FillRect(hdc, rect.PTR(), ::CreateSolidBrush(0x00FAFFFA)); return 1; } break; // NB: rect.PTR() : cast VRect zu &RECT // VRect ist von RECT abgeleitet.Das funktioniert so erstmal. Aber es ist natürlich nur ein WorkAround. Was die Probleme verursacht hat, habe ich noch nicht verstanden. Wahrscheinlich muss ich nochmal ein einfacheres Programm mit nur zwei Fenstern - Hauptfenster und Tree-View - untersuchen. Vielleicht wird es dann klarer.
-
hgf schrieb:
Bearbeitet wird hier aber fast nichts. Ich fange nur die Nachrichten ab, in denen ich das Window ohnehin selber zeichne (gekennzeichnet durch OPTION_PAINTMYSELF - siehe unten, also keine API-Controls ).
Weiter oben hast Du gesagt, daß Du WM_PAINT einfach an das TreeView durchreichst (hatte ich so verstanden). Und das ist das Problem.
Wenn Du in Dich aus WM_ERASEBKGND einfach mit 'return 1' verabschiedest, wird der Hintergrund des TreeViews nicht gezeichnet (nicht von Dir, nicht vom TreeView). In WM_PAINT zeichnet das TreeView nun brav die Items, nicht aber den Hintergrund.
Der richtige 'Workaround' ist IMO das Setzen der Hintergrundfarbe per TreeView_SetBkColor und das Durchreichen von WM_ERASEBKGND. Warum sollte das Control die Arbeit nicht auch selbst erledigen?
FYI: Du erzeugst mit CreateSolidBrush bei jedem Löschen einen neuen Brush. Die Freigabe des Brushes fehlt. Da wird Dir irgendwann die Puste ausgehen. Außerdem halte ich es für bedenklich, die Farbe so direkt anzugeben. Wenn ich ein wenig an den Systemfarben herumdrehe (viele User machen das tatsächlich, aber nicht nur ein wenig), werde ich irgendwann von Deinem TreeView nicht mehr viel erkennen.
-
Jetzt hab ich es!
Das Parent-Window erhält für das TreeView Child ein WM_CTRCOLOREDIT. Nach einem WM_CTRCOLOR"XYZ" hatte ich geguckt, aber, dass es in der "Edit-Version" ankommt - damit hatte ich nicht gerechnet.
Das erklärt auch die Sache mit der Liste. Wenn der TreeView eingelinkt war, wurde ein falscher Wert (schwarz) ausgelesen, wenn nicht, wurde kein Child gefunden und alles blieb unverändert.