Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Listbox.DoubleBuffered Anzeigeproblem (https://www.delphipraxis.net/62777-listbox-doublebuffered-anzeigeproblem.html)

Schaedel 9. Feb 2006 13:54


Listbox.DoubleBuffered Anzeigeproblem
 
Hallo und guten Tag,

ich hab da ein kleineres Problem mit einer Listbox.
Da ich das Flackern vermeiden will setze ich Listbox.DoubleBuffered := true.
Hierbei entsteht kein Problem... Das Flackern ist weg... Aaaaber
Wenn ich nun in der Listbox scrolle dann macht er mir die Bereiche, welche nicht von Buchstaben genutzt werden, schwarz.
Das ist einfach "hässlich" ...
Hat jemand eine Idee wie ich das utnerbinden könnte?
Mit Listbox.refresh gehts nicht ;)

dank im vorraus!

Luckie 9. Feb 2006 14:15

Re: Listbox.DoubleBuffered Anzeigeproblem
 
Waruim kein BeginUpdate und EndUpdate beim Einfügen der Items?

Schaedel 9. Feb 2006 14:52

Re: Listbox.DoubleBuffered Anzeigeproblem
 
:wiejetzt:
????
Ich find in der Hilfe nichts dazu.
Sowas wie Listbox.beginupdate gibt es nicht... nur Listbox.update und damit macht er den selben Murks

[edit omg sorry gefunden :wall:]
[edit die 2.
Er machts trotzdem nicht...
Wird ja im Ram gezeichnet und dann nach vorne geholt...(wenn ich das richtig verstanden habe)
mh also noch eine Idee?
So etwas wie "On Scroll" hat die Listbox ja nicht ... sonst wär mein Problem längst nichtig... ]

Matze 9. Feb 2006 14:56

Re: Listbox.DoubleBuffered Anzeigeproblem
 
Zitat:

Zitat von Schaedel
Sowas wie Listbox.beginupdate gibt es nicht...

Aber es gibt

Delphi-Quellcode:
ListBox.Items.BeginUpdate

Nachtrag: dein Edit kam zu spät. *g*

berens 19. Dez 2011 11:53

AW: Listbox.DoubleBuffered Anzeigeproblem
 
Liste der Anhänge anzeigen (Anzahl: 1)
*Staub wegpust* *Hüstel*

Hallo und sorry für das Ausgraben dieses uralten Threads, aber ich habe das gleiche Problem.

Eine lbOwnerDrawFixed TListBox zeigt das beschriebene Problem, sobald gescrollt werden muss:

Alles Items haben eine Höhe von 100px, die Box selbst eine Höhe von sagen wir als Beispiel 250px. Wenn man nun nach unten scrollt (und den ItemIndex _nicht_ verändert: Mausrad, klick auf die Dreieck-Buttons), wird ja immer automatisch soweit gescrollt, dass der oberste sichbare Eintrag bündig mit der Oberkante der kompletten Listbox ist. Wurde nun komplett heruntergescrollt, ist nun auch entsprechend der 5. Eintrag ganz oben (0-100 px), der 6. Eintrag bei 101-200 px, und der Rest der Listbox (201-250 px) ist schwarz.

Dieses Problem taucht nicht auf, wenn mit der Tastatur (Pfeil-Tasten) gescrollt wird, da hier auch der ItemIndex geändert wird, was somit auch ein (korrektes) Neuzeichnen der kompletten Listbox aufruft.

Das Problem tritt nur bei DoubleBuffered auf! Sobald die Listbox das nächste Mal neu gezeichnet wird, ist alles wieder korrekt - bis zum nächsten scrollen.

Die Frage ist nun:
-Berechnet Windows die Listbox falsch und eigentlich sollte beim kompletten Nach-Unten-Scrollen der unterste Eintrag bündig mit der Unterkante der Listbox abschließen? Scheinbar nicht, wenn bei Style lbStandard ist das Scrollverhalten identisch (also sichtbarer Freiraum nach dem letzten Eintrag).
-Wie kann/muss ich diesen Bereich nach dem letzten Eintrag zeichnen? Auch das setzen von Canvas.Brush.Color etc. haben keine Auswirkung.
-BeginUpdate / Endupdate haben hiermit nichts zu tun.
-Muss/sollte ich die Scroll-Windows-Message abfangen und dann ein Repaint aufrufen, oder gibt es eine elegantere Methode?


Delphi-Quellcode:
constructor TMeineListBox.Create(_Owner: TComponent);
begin
    inherited;

    ParentCtl3D := False;
    Ctl3D := False;

    Anchors := [akLeft, akTop, akRight, akBottom];
    BorderStyle := bsNone;

    Color := $00E6E6E6;
    ParentDoubleBuffered := False;
    DoubleBuffered := True;

    ItemHeight := 100;

    Style := lbOwnerDrawFixed;

    OnDrawItem := MeineListBoxDrawItem;
    DragMode := dmAutomatic;
end;

procedure TMeineListBox.MeineListBoxDrawItem(Control: TWinControl; Index: Integer; _Rect: TRect; State: TOwnerDrawState);
var
  re: TRect;
  bmp: Graphics.TBitmap;
begin
    if (Index < 0) or (Index >= Count) then begin
      inherited;
      Exit;
    end;
    if not Self.InheritsFrom(TCustomListBox) then Exit;

    bmp := Graphics.TBitmap.Create;
    bmp.Width := Control.ClientWidth;
    bmp.Height := Control.ClientHeight;
    bmp.Canvas.Brush.Assign((Control as TCustomListBox).Canvas.Brush);
    bmp.Canvas.Pen.Assign((Control as TCustomListBox).Canvas.Pen);

    with bmp.Canvas do begin
      re := _Rect;
      if (odSelected in State) then begin
        Brush.Color := clWhite;
        Pen.Color := clWhite;
        Brush.Color := $00F4F4F4;
        Pen.Color := $00F4F4F4;
      end else begin
        Brush.Color := Self.Color;
        Pen.Color := Self.Color;
      end;

      Brush.Color := clred;
      Pen.Color := clLime;

      Rectangle(re);

      re.Left := re.Left + 5;
      re.Top := re.Top + 5;
      re.Bottom := re.Bottom - 5;
      re.Right := re.Right - 5;

      --> Hier wird meine eigentliche Zeichenprozedur aufgerufen; Problem ist aber unabhängig davon
    end;

    BitBlt((Control as TCustomListBox).Canvas.Handle, _Rect.Left, _Rect.Top, _Rect.Right - _Rect.Left, _Rect.Bottom - _Rect.Top, bmp.Canvas.Handle, _Rect.Left, _Rect.Top, SRCCOPY);
    FreeAndNil(bmp);

    if (odSelected in State) then begin
      (Control as TCustomListBox).Canvas.DrawFocusRect(_Rect);
    end;

    (Control as TCustomListBox).Canvas.Brush.Color := clLime;
    (Control as TCustomListBox).Canvas.Pen.Color := clRed;
end;
Wie immer vielen Dank im voraus!



Edit1:
Also damit funktioniert es zwar, aber beim Scrollen flackert es nun (logischerweise wegen x-fachen Repaints) so stark, dass man DoubleBuffered auch gleich weglassen kann:
Delphi-Quellcode:
  protected
    procedure WMVScroll(var Message: TWMVScroll); message WM_VSCROLL;
    procedure WMMOUSEWHEEL(var Msg: TMessage); message WM_MOUSEWHEEL;
  ...
procedure TMeineListBox.WMMOUSEWHEEL(var Msg: TMessage);
begin
  inherited;
  Repaint;
end;

procedure TMeineListBox.WMVScroll(var Message: TWMVScroll);
begin
  inherited;
  Repaint;
end;
Edit 2:
[STRIKEOUT]Mit Invalidate anstelle von Repaint scheint es halbwegs ordentlich dargestellt zu werden. Es bleibt trotzdem die Frage, ob dieser Lösungsweg der "richtige" bzw. "elegante" ist.[/STRIKEOUT] Nö, klappt im tatsächlichen Programm dann doch nicht.


Edit 3:
Wer es nachvollziehen will: Neues Projekt mit einer Listbox:
Delphi-Quellcode:
procedure TForm2.FormCreate(Sender: TObject);
var
  i: integer;
begin
  ClientWidth := 500;
  ClientHeight := 250;
  ListBox1.Align := alClient;
  ListBox1.Style := lbOwnerDrawFixed;
  ListBox1.OnDrawItem := MyDrawItem;
  ListBox1.Font.Name := 'Arial';
  ListBox1.Font.Size := 67;
  ParentDoubleBuffered := False;
  DoubleBuffered := True;
  for i := 0 to 5 do begin
    ListBox1.Items.Add(IntToStr(i))
  end;
end;

procedure TForm2.MyDrawItem(Control: TWinControl; Index: Integer; _Rect: TRect; State: TOwnerDrawState);
var
  re: TRect;
  bmp: Graphics.TBitmap;
begin
  with Control as TListBox do
  begin
    Canvas.FillRect(_Rect);
    Canvas.TextOut(_Rect.Left + 2, _Rect.Top, Items[Index]);
  end;
end;

ventiseis 18. Apr 2012 11:15

AW: Listbox.DoubleBuffered Anzeigeproblem
 
Siehe folgenden QC-Eintrag:

50762: DoubleBuffered Bug in TListBox


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:05 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz