Entwickler-Ecke
Grafische Benutzeroberflächen (VCL & FireMonkey) - Linie durch Listbox nicht sichtbar
D. Annies - Do 22.01.09 10:48
Titel: Linie durch Listbox nicht sichtbar
Hi, Delpher,
kleine Spielerei, aber warum ist die Linie nicht (dauerhaft) sichtbar?
Code:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| listbox6.clear; n := 0; with Listbox6.Items do begin while n < klmax-1 do begin inc(n); if total[n] > 0 then begin Add(Format('Personen in R%2d : %3d = %3d / %3d ', [n, total[n], female[n], male[n]])); Add(' '); end; end; Add('----------------------------------'); end; listbox6.Canvas.MoveTo(Left,Top); listbox6.Canvas.LineTo(clientrect.Right, clientrect.Bottom); |
Danke für eine Idee/Abhilfe,
Detlef
Lannes - Do 22.01.09 10:59
Hallo,
wo steht der Code?
Wenn er in einer Routine ausgeführt wird, kann es nicht funktionieren.
D. Annies - Do 22.01.09 17:33
Hi, Lannes,
ja, der Code steht in einer Prozedur.
Und jetzt?
jaenicke - Do 22.01.09 17:41
Naja, sobald die ListBox neu gezeichnet wird, ist die Linie auch wieder weg.
Da es kein OnPaint bei der ListBox gibt, wäre die sinnvollste Möglichkeit, eine eigene abgeleitete Klasse zu erstellen, die dies beinhaltet. Ich vermute wo etwas gibt es auch im Netz.
// EDIT:
Ach ja: was Lannes meinte:
Mit Left und Top usw. greifst du ja nicht auf die Werte der ListBox zu, sondern auf die des Formulars...
// EDIT2:
Was auch gehen müsste um das neu zeichnen in den Griff zu bekommen:
WndProc überschreiben und auf WM_PAINT reagieren. ;-)
D. Annies - Do 22.01.09 18:11
Ich haben verstanden - ich lassen es! :nut:
Gruß, Detlef
Lannes - Do 22.01.09 18:11
Hallo,
jaenicke hat folgendes geschrieben : |
// EDIT:
Ach ja: was Lannes meinte:
Mit Left und Top usw. greifst du ja nicht auf die Werte der ListBox zu, sondern auf die des Formulars... |
so in etwa, oder auch nicht :wink:
jetzt weis ich immer noch nicht wo
genau der Code steht
a.
Der Code steht in ListBoxDrawItem = dort sollte man keine Einträge schreiben die ein Neuzeichnen auslösen
b.
Der Code steht in einer anderen Prozedur = dort sollte man nicht auf das canvas der Listbox zeichnen, den das wird übermalt wenn die interne Zeichenprozedur durch etwas anderes aufgerufen wird. z.B. ein überdecken der Listbox durch ein anderes Fenster.
Du kannst den Vorschlag von jaenicke (WndProc etc.) nehmen, ich meine es ist einfacher die Linie in ListBoxDrawItem zu zeichnen.
Was soll denn die Linie bezwecken?
D. Annies - Do 22.01.09 18:27
Hi, Lannes,
der Code steht in "b".
Entscheidend ist ja auch deine Frage, was bewirkt werden soll. --> Nichts, VOID, es ist wirklich nur eine Spielerei, deshalb lasse ich es auch. Wenn es wichtig wäre, würde ich mehr "beißen".
Vielen Dank für deine "Nachsorge",
Detlef
jaenicke - Do 22.01.09 19:19
D. Annies hat folgendes geschrieben : |
| Nichts, VOID, es ist wirklich nur eine Spielerei |
Na dann spiele ich mal mit :D
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25:
| TForm137 = class(TForm) ListBox1: TListBox; private public procedure WndProc(var message: TMessage); override; end;
var Form137: TForm137;
implementation
{$R *.dfm}
procedure TForm137.WndProc(var message: TMessage); begin inherited; if message.Msg = WM_PAINT then begin listbox1.Canvas.MoveTo(listbox1.Left,listbox1.Top); listbox1.Canvas.LineTo(listbox1.clientrect.Right, listbox1.clientrect.Bottom); end; end; |
Das funktioniert, wie ich schon vermutet hatte, wunderbar. ;-)
Durch das inherited an erster Stelle sorge ich dafür, dass die ListBox zuerst selbst ihre Sachen zeichnet und ich danach darüber zeichne.
D. Annies - Do 22.01.09 20:41
Sebastian, du bist "unmöglich" !!
Danke, Detlef
delfiphan - Fr 23.01.09 00:32
jaenicke hat folgendes geschrieben : |
| Das funktioniert, wie ich schon vermutet hatte, wunderbar. ;-) |
Die Lösung ist leider trotzdem etwas schief geraten ;)
Du überschreibst die WndProc der MainForm, um darin ein Child-Control zu überzeichnen :O. Wieso das niemand so macht: ;)
- Um einzelne Messages abzufangen, würde man nicht die WndProc überschreiben, sondern eine message Prozedur definieren:
procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
- Um das Neuzeichnen der MainForm abzufangen, würde man aber auch das nicht machen, sondern gleich das OnPaint-Event benutzen.
- Aber: Um das Neuzeichnen eines Child-Controls abzufangen, fängt man nicht die Paint-Message der MainForm ab, sondern wenn schon die des Child-Controls selbst, sofern das Child-Control natürlich kein eigenes Paint-Ereignis besitzt (was die TListBox ja tut, zu mindest für einzelne Items). Denn es kann sein, dass die MainForm gar nicht neugezeichnet werden muss, die ListBox aber schon.
- Bietet ein Control kein OnPaint an, sollte man das entsprechende Control erweitern, in dem man von ihr eine Ableitung macht, und dort entweder die Paint Methode überschreibt (sofern vorhanden), und falls nicht, eine message-Prozedur wie oben gezeigt definiert und von dort aus das selbstdefinierte OnPaint-Ereignis aufruft. Hier sollte man darauf achten, dass man die WinApi Doku beachtet.
- Wenn man "global" Messages abfangen muss, dann über Application.OnMessage. Dort würde man das Handle der Message überprüfen, ob es mit der der ListBox übereinstimmt, etc.. Die globale Lösung ist natürlich schlecht, aber so würde man es machen.
jaenicke - Fr 23.01.09 00:37
delfiphan hat folgendes geschrieben : |
| - Bietet ein Control kein OnPaint an, sollte man das entsprechende Control erweitern, indem man entweder die Paint Methode überschreibt (sofern vorhanden), und falls nicht, eine message-Prozedur wie oben gezeigt definiert und von dort aus das selbstdefinierte OnPaint-Ereignis aufruft. |
Das habe ich ja auch geschrieben, aber dann kann man eben keine Standard-ListBox verwenden. ;-)
Dass das in einem richtigen Anwendungsfall natürlich die bessere Lösung ist, ist klar.
delfiphan - Fr 23.01.09 00:57
jaenicke hat folgendes geschrieben : |
Das habe ich ja auch geschrieben, aber dann kann man eben keine Standard-ListBox verwenden. ;-)
Dass das in einem richtigen Anwendungsfall natürlich die bessere Lösung ist, ist klar. |
Naja ;) Trotzdem hätte man ein korrektes Beispiel posten können...
Die ganze Paint-Geschichte über WM_PAINT ist genau genommen noch etwas komplizierter, da man den beim WM_PAINT übergebenen DC noch mit BeginPaint/EndPaint umgeben muss. Bei TWinControls übernimmt das PaintHandler, der dann PaintWindow aufruft. Einige dieser Methode sind virtual, können als überschrieben werden. Dort würde man dann dem Canvas das DC als Handle geben und das eigene Event aufrufen.
Und falls global, mit Original-Listbox und ohne VCL-Event, dann über Application.OnMessage. Dann muss man sich um die oben genannten Sachen jedoch selbst kümmern.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!