Announcement

Collapse
No announcement yet.

Flackern bei selbstgeschriebener TShellView Komponente

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Flackern bei selbstgeschriebener TShellView Komponente

    Hallo ihr

    Ich habe mir eine eigene Komponente entwickelt, die wie das TListview Daten in Spalten mit eigenem Icon anzeigen kann. Dafür habe ich eine TListbox verwendet und den Style auf lbOwnerDrawFixed gestellt. Im Drawitem Ereignis zeichne ich mir dann alles selber. Mein Problem ist, daß sowohl bei einem Update als auch bei Resize die Darstellung extrem zum flackern anfängt. Es wird etwas besser, wenn ich das Zeichnen der Icons weglasse, aber die braucht der Anwender leider. Wie kann ich ein Flackern in diesem Fall verhindern oder noch besser ganz vereiteln.

    Ich hoffe ihr könnt mir dabei helfen.

  • #2
    <b>Zwischenbuffern</b> ist das magische Wort.
    Anstatt also direkt auf den DC des Fensters zu zeichenen, legst Du eine TBitmap an, mit ARect Dimensionen, zeichnest all Deine ausgaben in Bitmap.Canvas und abschließend mit .CopyRect() in den Zielcanvas kopiert. Das ist mit ListBox'en ideal da nur eine Zeile nach der anderen gezeichnet wird, d.h. die Bitmap ist max. eine Zeile groß. Um die Sache zu beschleunigen würde ich diese Bitmap einmal anlegen (dem Object zugehörig) und erst mit der ListBox zerstören.

    Gruß Hage

    Comment


    • #3
      Hallo Hagen

      Vielen Dank für deine Antwort. Das zwischenpuffern in einer Bitmap macht meine Komponente aber bereits. Mein Problem ist, das das Zwischenpuffern allein zu wenig ist. Gibt es noch andere Möglichkeiten ?? Vielleicht undokumentierte oder wenig bekannte API-Befehle um das Zeichnen zu beschleunigen bzw. den DC nicht sofort zu zeichnen sondern erst dann, wenn alle Informationen geschrieben sind ?

      Comment


      • #4
        Hi

        <li>ListView.Items.BeginUpdate und .EndUpdate;
        <li>ListView.Perform(wm_SetRedraw, 0 {1}, 0);

        Beide Methoden sind identisch, nur das die erstere das wm_SetRedraw kapselt. wm_Setredraw lockt den DC des ListViews, es kann also nichts mehr auf dem Canvas gezeichnet werden, bzw. Invalidate() erkennt diesen Zustand. .BeginUpdate() sollte also vor längerdauernden Änderungen an ListView.Items unbedingt aufgerufen werden.

        Grundsätzlich ist der ListView aber eine relativ "uneffizientes" Control. Es gibt flexiblere und schnellere Delphi Ersatzkomponenten.

        Gruß hage

        Comment


        • #5
          Hi Hagen

          Bei meiner Komponente handelt es sich auch um einen Nachfahren der TCustomListBox. Listview selbst habe ich in der ersten Version verwendet und das Ding war, wie du auch sagst, wirklich sehr langsam.

          Meine Komponente holt sich über das IShellFolder-Interface die Daten über den Shell-Namespace. Diese werden an die Listbox in eimen try-finally Block mit Items.BeginUpdate und Items.Endupdate übergeben.
          Da die Auswertung der Namespace-Daten einige Zeit in Anspruch nimmt, werte ich die Daten nicht sofort aus, sondern übergebe an die Listbox lediglich ein Objekt mit den benötigten Daten. Das Objekt wertet die Daten selbstständig aus und übergibt diese an die Listbox in der Drawitem -Methode.

          Hier ist eine geringe Geschwindigkeitseinbusse natürlich möglich. Das Objekt ist jedoch so aufgebaut, daß die Auswertung nur einmal erfolgt und die Daten selbstständig gemerkt werden. Aber auch dann ist ein Flackern zu bemerken.

          Ich glaube das das Problem an der Drawitem-Methode selbst liegt. Hier werden die Daten ineffizient ausgewertet, meiner Meinung. Wie baue ich die Drawitem Methode so effizient wie möglich auf, um ein Flackern so weit wie möglich zu verhindern ??

          Comment


          • #6
            HI

            In der Zeichenroutine für OnDrawItem werden meist 3 Aktionen ausgeführt:
            <li>löschen des Hintergrunds mit FillRect()
            <li>zeichnen des Textes usw. {DrawText()}
            <li>zeichnen des Focusrahmens

            Du solltest nun in der Zeichenroutine so wenig wie möglich zusätzlichen Code zwischen diese 3 Aktionen legen. D.h. Deine IShellFolder Auswertung MUSS vor FillRect() kommen.

            Ansonsten kann ich wenig Tipps geben da ich schon den Source sehen müsste.

            Gruß Hage

            Comment

            Working...
            X