Labels im TableLayoutPanel sind super langsam

  • VB.NET

Es gibt 11 Antworten in diesem Thema. Der letzte Beitrag () ist von Snake3000.

    Labels im TableLayoutPanel sind super langsam

    Hallo Gemeinde,

    es gilt 310 Daten schön ansehbar darzustellen... also 16pt Grösse und in unterschiedlichen Farben.
    Das Ganze als eine Liste die man scrollen kann.

    Ich habe dazu ein Tablelayoutpanel gewählt und Labels darin plaziert und formatiert.
    Zur Laufzeit wird jedes Label mit controls angesprochen und .text gefüllt.

    Das funktioniert, aber es ist nur sehr langsam. Suuuper langsam!!!!

    Die Fragen sind nun:

    ist das TableLayoutPanel die richtige Wahl?

    ist meine Vorgehensweise Controls.Find("Label" & sei.ToString, True).First.Text = Form1.sedat(sei).ToString so richtig?


    Was kann ich da besser machen?
    1. Probier den "Performancetest" ohne Deinen Datenbefüllungscode. Wenn es fix geht, hast Du also den Flaschenhals ausgemacht.
    2. Wie oft werden die Labels befüllt?
    3. Dein Befüllungscode ist ... ausbaufähig. Pack alle Labels per Schleife zum Programmanfang in einen Container (Array, List(Of Label), whatever) und geh dann mit ner For-Schleife durch:

    VB.NET-Quellcode

    1. For i = 0 To Form1.sedat.Count() -1
    2. DeinLabelContainer(i).Text = Form1.sedat(i).ToString
    3. Next

    Von welchem Datentyp ist sedat?
    ABER! Was ist Form1? Warum glaubst Du es in der Codezeile zu brauchen? Befindet sich der Code in der Form1-Klasse? Wenn nicht: Ist Form1 das Hauptformular? All das weist würde auf strukturelle Fehler hinweisen. Ist zwar für das Problem nebensächlich, aber auf Dauer nicht.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Hi Zed,

    1.) ohne den Befüllungscode ist es flott wie ein Augenzwinkern.
    2.) jedesmal wenn der geneigte Benutzer einen neuen Monat anwählt.
    3.) freue mich darauf die Ausbaufähigkeit zu lernen .-)

    die Daten sind beim Laden eines neuen Monats in einem Datenfeld "Public Shared sedat(32) As String", deklariert in der Form1.

    Strukturelle Fehler habe ich mit Sicherheit. Bin Prozedurale Programierung gewöhnt und taste mich nun an die oops heran.
    Ja, ich Form1 ist das Hauptformular. Es ruft Form2 auf in dem die Variablen genutzt werden.

    Snake3000 schrieb:

    ist meine Vorgehensweise

    VB.NET-Quellcode

    1. Controls.Find("Label" & sei.ToString, True).First.Text = Form1.sedat(sei).ToString
    so richtig?

    Snake3000 schrieb:

    Ja, ich Form1 ist das Hauptformular. Es ruft Form2 auf in dem die Variablen genutzt werden.
    Verstehe dies (auch wenn Du der Meinung bist, dass das nix mit Deinem Problem zu tun hat):
    Dialoge: Instanziierung von Forms und Aufruf von Dialogen
    Deklarier mal spaßeshalber das Objekt sedat als Shared.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Gut. Also der Befüllungscode.
    Dann fang an mit dem Container:
    Unter Public Class Form2 schreib mal: Private LabelContainer As New List(Of Label)
    Und dann im Load-EventHandler:

    VB.NET-Quellcode

    1. For Each Control In Me.Controls
    2. If TypeOf Control Is Label Then LabelContainer.Add(Control)
    3. Next

    Und dann später die Schleife aus Post#2.
    Geht das? Wie ist die Performance?

    RodFromGermany schrieb:

    Deklarier mal spaßeshalber das Objekt sedat als Shared.

    Snake3000 schrieb:

    Public Shared sedat(32) As String

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Hi Zed,

    danke für die Idee. Ich sehe den Charme deiner Lösung und habe es gerade probiert.

    Leider findet die Schleife in Form2.load nicht die Label die in dem Table Layout Panel liegen.
    Habe das durchgetraced, es werden alle controls meiner Form2 gefunden einschliesslich des TableLayoutPanels, aber nicht die Label die in dem Panel sind, :-/

    Beim schreiben ist mir eingefallen das ich den Container selber füllen kann:

    LabelContainer.Add(Controls.Find("Label323", True).First)
    For i = 1 To 310
    LabelContainer.Add(Controls.Find("Label" & i.ToString, True).First)
    Next i

    Das .Add vor der Schleife füllt den 0-Eintrag den ich nicht weiter nutze.

    Der Code rennt, ist aber leider keinen Deut schneller geworden. Schade.

    Ich glaube das ich mich von dem TableLayoutPanel verabschieden muss, oder?
    Was gibt es sonst für Möglichkeiten? Das Aussehen gefällt mir so recht gut...

    Ach ja, der Vollständigkeithalber hier noch meine Befüllungsschleife:

    For i = 1 To 31
    LabelContainer(1 + ((i * 10) - 10)).Text = Form1.sedat(i)
    LabelContainer(2 + ((i * 10) - 10)).Text = Form1.semosys(i).ToString
    LabelContainer(3 + ((i * 10) - 10)).Text = Form1.semodia(i).ToString
    LabelContainer(4 + ((i * 10) - 10)).Text = Form1.semopul(i).ToString
    LabelContainer(5 + ((i * 10) - 10)).Text = Form1.semisys(i).ToString
    LabelContainer(6 + ((i * 10) - 10)).Text = Form1.semidia(i).ToString
    LabelContainer(7 + ((i * 10) - 10)).Text = Form1.semipul(i).ToString
    LabelContainer(8 + ((i * 10) - 10)).Text = Form1.seabsys(i).ToString
    LabelContainer(9 + ((i * 10) - 10)).Text = Form1.seabdia(i).ToString
    LabelContainer(10 + ((i * 10) - 10)).Text = Form1.seabpul(i).ToString
    Form1.ProgressBar1.PerformStep() '--------------------------------------- fortschritt (zumindest am balken)
    Next i

    … ist doch kein Hexenwerk das den Rechner in die Knie zwingt, oder?

    @Rod, auch Dir vielen Dank.
    Ja, ich habe deinen verlinkten Beitrag auch schonmal gelesen und im Hinterkopf, leider bin ich Objektorientiert noch immer nicht angekommen.
    Glücklich bin ich damit selber auch noch nicht wie ich es im Moment mache, da will ich noch dran arbeiten.
    Verstehe ich das richtig, dass da 310 Labels herumfahren?

    Scheint mir aber dochn bischen ville.
    Und wenn die alle Autosize an haben, und das TableLayoutpanel auch die eine oder annere Spalte oder Zeile auf AutoSize - jo, dann ist das doch ein ordentliches Herum-Gelayoute vor dem Herrn.

    Wäre evtl. ein Datagridview nicht deutlich günstiger?
    Grins.... Jepp, ich gestehe genauso ist es.

    Mir ist am Anfang nix schlaueres eingefallen. Zugegeben ich war nahe an einer Sehnenscheidenentzündung beim hereinklicken. :)
    Ich hatte auch den Ansatz die zur Laufzeit zu erstellen, habe mich aber für das stupide klicken entschieden. Wichtig ist für mich halt das Aussehen.

    An DataGridView habe ich in Unkenntnis der Sachlage nicht gedacht. Wäre eine Idee. Schaue ich mir mal an...… Danke Dir.

    PS: Ich musste gerade echt laut loslachen bei Deinem Post.... ich liebe trockenen Humor....


    Edit:
    ErfinderDesRades, du bist genial!!!
    Habe gerade Autosize auf false gesetzt und es geht rubbel die Katz voran.

    Das war offenbar die Lösung!!!
    Danke

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Snake3000“ ()

    Als Ergänzung: Klar, statt For Each Control In Me.Controls muss es natürlich heißen: For Each Control In TableLayoutPanel1.Controls
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Hallo hier der momentane Bericht zur Sache:

    Nach dem Wochenende habe ich nun nochmal alle Möglichkeiten durchgespielt.

    Zu Anfang mein Ausgangscode der mich ja zu dem Post hier geführt hat.
    - 310 Label in einem TableLayoutPanel
    - Autosize auf true
    - Füllung zur Laufzeit mit Controls.Find("Label" & sei.ToString, True).First.Text = Form1.sedat(sei).ToString
    - Fortschrittsbalken, da ich vorher die Daten aus einer Datei hole und einige Berechnungen durchführe
    Ergebnis, von Hand gestoppt : 17 Sekunden

    Nächster Versuch:
    - Erstellung eines Containers, alle Label in einer Schleife vorher hereingelegt und bei der Befüllung
    mit LabelContainer(1 + ((i * 10) - 10)).Text = Form1.sedat(i) angesprochen
    Ergebnis : 10 Sekunden (es kam mir am Samstag in der Nacht nicht schneller vor, aber heute habe ich es mal gestoppt)

    Dritter Versuch:
    - in der ersten Schleife LabelContainer(i).AutoSize = False gesetzt
    Ergebnis : 6 Sekunden

    Jetzt kommt der Knaller, in voller Hoffnung den vierten Versuch gestartet:
    - Autosize aller Labels in der Entwicklungsumgebung auf False gesetzt und aus der Laufzeit herausgenommen
    Ergebnis : 17 Sekunden

    Ist das zu Erklären?
    @Snake3000 Probierma

    VB.NET-Quellcode

    1. TLP.SuspendLayout()
    2. ' Dein Befüllungscode
    3. TLP.ResumeLayout()
    4. TLP.PerformLayout()
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Huwahhhh….. Rod, mir wird schwindelig… :)

    Somit kommen wir dann jetzt zum Abschlussbericht.

    Fünfter Versuch:
    - Code belassen wie er war
    - die erste Schleife zum container füllen in .SuspendLayout() und .ResumeLayout() geklammert
    - die zweite Befüllschleife in .SuspendLayout() und .ResumeLayout() geklammert
    - .PerformLayout() dahinter ausgeführt
    Ergebnis: <1 Sekunde

    Ich sehe gerade mal das der Fortschrittsbalken da ist, da ist er schon wieder weg.

    Auf jeden Fall meinen vielen Dank an euch Drei, ich habe wieder so einiges gelernt.