Autor Beitrag
galagher
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2556
Erhaltene Danke: 45

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Mo 12.05.14 21:36 
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:

ausblenden 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;  //Variable funktioniert nicht, Konstante oder Zahl direkt schon!
end;

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
Tastaro
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 414
Erhaltene Danke: 23



BeitragVerfasst: Di 13.05.14 07:17 
Die Frage ist, wo Du die Variable deklariert hast.
Das erkennt man in dem Codeschnipsel leider nicht.
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2556
Erhaltene Danke: 45

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Di 13.05.14 17:37 
user profile iconTastaro hat folgendes geschrieben Zum zitierten Posting springen:
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: www.developpez.net/f...tream-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:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
  {Erst Wert zuweisen, ...}
  iGraphicHeight := Image1.Picture.Bitmap.Height;
  {... dann Neuzeichnen veranlassen}
  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!

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!
Popov
ontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic starofftopic star
Beiträge: 1655
Erhaltene Danke: 13

WinXP Prof.
Bei Kleinigkeiten D3Pro, bei größeren Sachen D6Pro oder D7
BeitragVerfasst: 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
WasWeißDennIch
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 653
Erhaltene Danke: 160



BeitragVerfasst: Mi 14.05.14 08:10 
docwiki.embarcadero....istBox.OnMeasureItem
Zitat:
Tritt ein, wenn ein Eintrag in einem Owner-Draw-Listenfeld mit variabler Höhe neu gezeichnet werden muss.

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.
Popov
ontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic starofftopic star
Beiträge: 1655
Erhaltene Danke: 13

WinXP Prof.
Bei Kleinigkeiten D3Pro, bei größeren Sachen D6Pro oder D7
BeitragVerfasst: Mi 14.05.14 12:13 
user profile iconWasWeißDennIch hat folgendes geschrieben Zum zitierten Posting springen:
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.

_________________
Popov
WasWeißDennIch
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 653
Erhaltene Danke: 160



BeitragVerfasst: 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
ausblenden 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
ontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic starofftopic star
Beiträge: 1655
Erhaltene Danke: 13

WinXP Prof.
Bei Kleinigkeiten D3Pro, bei größeren Sachen D6Pro oder D7
BeitragVerfasst: 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.

_________________
Popov
galagher Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 2556
Erhaltene Danke: 45

Windows 10 Home
Delphi 10.1 Starter, Lazarus 2.0.6
BeitragVerfasst: Mi 14.05.14 18:25 
user profile iconPopov hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconWasWeißDennIch hat folgendes geschrieben Zum zitierten Posting springen:
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.

user profile iconWasWeißDennIch hat folgendes geschrieben Zum zitierten Posting springen:
im blödesten Falle dann eben mit Konstrukten wie
ausblenden 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!

_________________
gedunstig war's - und fahle wornen zerschellten karsig im gestrock. oh graus, es gloomt der jabberwock - und die graisligen gulpen nurmen!