Entwickler-Ecke
Grafische Benutzeroberflächen (VCL & FireMonkey) - Keine Integer-Variable in OnMeasureItem möglich?
galagher - Mo 12.05.14 21:36
Titel: Keine Integer-Variable in OnMeasureItem möglich?
Hallo!
Weiss jemand, ob und warum Integer-Variablen in OnMeasureItem nicht verwendet werden können? Ich möchte in einer bestimmte Zeile für
Height eine Variable verwenden, und obwohl diese einen Wert > 0 hat, wird die Zeile in ListBox1DrawItem nicht gezeichnet, so, als ob der Wert 0 wäre! Setze ich stattdessen eine Konstante ein oder dierekt eine Zahl, funktioniert es:
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| procedure TForm1.ListBox1MeasureItem(Control: TWinControl; Index: Integer; var Height: Integer); begin if Index = 10 then Height := iGraphicHeight; end; |
Tastaro - Di 13.05.14 07:17
Die Frage ist, wo Du die Variable deklariert hast.
Das erkennt man in dem Codeschnipsel leider nicht.
galagher - Di 13.05.14 17:37
Tastaro hat folgendes geschrieben : |
| Die Frage ist, wo Du die Variable deklariert hast. |
Nach dem ich die Grafik in ein TBitmap eingelesen habe. Dazu lese ich eine Datei in ListBox1 ein und wandle mit
StringToBitmap einen String daraus in ein Bitmap um.
Siehe:
http://www.developpez.net/forums/d1059522/environnements-developpement/delphi/langage/image1-picture-graphic-loadfromstream-ms-erreur-etc/
Ich habe nun aber etwas entdeckt: OnMeasureItem wird unmittelbar
nach ListBox1.LoadFromFile aufgerufen, jedenfalls
bevor ich
StringToBitmap aufrufe, was ja logischerweise erst nach
LoadFromFile erfolgen kann. Hier hat die Variable noch den Wert 0. Dann wird ihr ein Wert zugewiesen, nämlich die Höhe der Grafik. Und sie hat diesen Wert dann auch, aber OnMeasureItem wird dann nicht mehr aufgerufen!
Das erklärt das auf den ersten Blick seltsame Verhalten, warum es mit einer Konstante, nicht aber mit einer Variablen funktioniert!
Also habe ich die Datei zunächst in eine TStringList geladen, daraus dann den String, aus dem ich die Grafik "machen" will, ausgelesen und mit
StringToBitmap verarbeitet. Dann der Variablen den Wert zugewiesen und erst danach ListBox1 mit den Zeilen befüllt. Nun habe ich die korrekte Zeilenhöhe, aber es wird kein Bitmap gezeichnet! :autsch:
Wie kann ich das lösen? Wenn nicht, auch nicht schlimm, dann eben mit fixer Höhe!
//Edit:
Lösung:
Delphi-Quelltext
1: 2: 3: 4:
| iGraphicHeight := Image1.Picture.Bitmap.Height; ListBox1.Items[10] := ListBox1.Items[10]; |
Normalerweise würde ich ja sagen, den selben String nochmals zuweisen ist Unsinn, aber so funktioniert es! Habe ListBox1.Invalidate/Update/Repaint/Refresh und sogar den Aufruf von OnMeasureItem versucht, alles erfolglos. So klappt es wenigstens, aber es ist irgendwie unschön.
Offenbar geht es nur um's Neuzeichnen. Vielleicht fällt jemandem ja etwas Besseres ein!
Popov - Di 13.05.14 22:53
Du hast das Problem im Grunde schon fast erkannt. OnMeasureItem wird nur ein mal aufgerufen und zwar beim ersten Erstellen des Items. Danach nicht mehr. Es wird also nicht beim LoadFromFile ausgeführt, sondern LoadFromFile erzeugt ein Item, somit klappt es bei der Aktion.
Das Ganze hat auch eine Logik. Beim Erstellen des Items sollte man eigentlich wissen wie hoch das Item ist und es zuweisen. Wenn man danach mit der Höhe rumspielt, bringt man alles nur durcheinander.
Ich erstelle im Falle einer Änderung ein neues Item mit Insert oder InsertObject direkt über dem alten Item, kopiere den Inhalt und lösche das alten Item. Ist eine schnelle Aktion. TopIndex und ItemIndex kurz sichern und gleich wiederherstellen. Flackert nicht mal.
Popov - Mi 14.05.14 12:13
WasWeißDennIch hat folgendes geschrieben : |
| Sollte es da nicht ein einfaches Repaint der Listbox tun? Items zu löschen und wieder neu einzufügen kommt mir zumindest sehr umständlich vor. |
Hast du das getestet oder glaubst du es nur? Nach meiner Kenntnis reicht das nicht aus (ist aber schon länger her wo ich das getestet habe). Denn wenn die Liste in der Listbox länger ist und man mit der Bildlaufleiste scrollt, werden die Items sowieso neu gezeichnet. Auch ohne Paint.
Und das erstellen eines neuen Items, inkl. löschen des anderen, sind nur zwei Zeilen Code.
WasWeißDennIch - Mi 14.05.14 14:45
Und wenn da noch Objekte dranhängen? Da würde ich lieber wie vom TE gezeigt einfach dafür sorgen, dass MeasureItem ausgelöst wird, ohne an den Daten tatsächlich etwas zu ändern, im blödesten Falle dann eben mit Konstrukten wie
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| procedure TFormTrallalla.RedrawItems; var i: integer; begin for i := 0 to MyListBox.Items.Count - 1 do MyListBox.Items[i] := MyListBox.Items[i]; end; |
Popov - Mi 14.05.14 14:54
Insert gibt es auch mit Object. Sowas hängt immer damit zusammen was man macht. Für mich war es bisher immer einfacher das Item zu ersetzten. Eigentlich wußte ich auch immer vorher wie hoch das Item ist.
galagher - Mi 14.05.14 18:25
Popov hat folgendes geschrieben : |
WasWeißDennIch hat folgendes geschrieben : | | Sollte es da nicht ein einfaches Repaint der Listbox tun? Items zu löschen und wieder neu einzufügen kommt mir zumindest sehr umständlich vor. |
Hast du das getestet oder glaubst du es nur? Nach meiner Kenntnis reicht das nicht aus (ist aber schon länger her wo ich das getestet habe). |
Es reicht tatsächlich nicht aus! Man muss dafür sorgen, dass MeasureItem ausgelöst wird, das geschieht mit Repaint usw. nicht.
WasWeißDennIch hat folgendes geschrieben : |
im blödesten Falle dann eben mit Konstrukten wie
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7:
| procedure TFormTrallalla.RedrawItems; var i: integer; begin for i := 0 to MyListBox.Items.Count - 1 do MyListBox.Items[i] := MyListBox.Items[i]; end; | |
Ja, so funktioniert es, aber es gefällt mir nicht besonders. Da ich es aber nur diesmal brauche, belasse ich es wohl so. Interessant ist, dass man MeasureItem mit
ListBox1.OnMeasureItem(ListBox1, 10, iGraphicHeight); nicht auslösen kann! Warum? Steht doch da!
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!