![]() |
Label in Schleife zeichnen lassen
Eine kurze frage:
Ich habe eine Schleife die von 1 bis 1.000.000 zählt. Nun möchte ich möglichst schnell in der Schleife ein Label aktualisieren - deswegen habe ich KEIN Application.Processmessages drinnen (dauert zu lange) wollte es einfach mit:
Delphi-Quellcode:
Das Label ist nicht transparent.
Label1.Caption := IntToStr(i);
TCrackedLabel(Label1).Paint; Problem ist, das es flackert bzw teilweise nur der clBtnFace hintergrund zu sehen ist, also der Text gar nicht. Wie wenn im Hintergrund wer noch mal drüber zeichnet, oder wie wenn der Text erst verzögert gezeichnet werden würde. Habe selbiges auch mal getestet das ich den Text selber auf den Canvas zeichne, das hat auch nicht funktioniert. Wer könnte mir da noch dazwischenfunken? |
AW: Label in Schleife zeichnen lassen
Das Problem ist, dass es nicht anders geht, als auch den Hintergrund neu zu zeichnen. Denn der neue Text deckt ja nicht unbedingt den alten komplett ab. Normalerweise kann man Flackern vermindern, indem man das Neuzeichnen zeitweise unterbindet. Bei so schnellen Aktualisierungen hilft das aber auch nicht.
Ein TStaticText sollte weniger flackern. Sinnvoller ist aber eine bessere Lösung: So schnell kann das doch ohnehin niemand wahrnehmen. Sinnvoller ist daher, dass du die Aktualisierungen nicht bei jedem Durchlauf machst, sondern nur z.B. alle x Durchläufe oder alle x Millisekunden. Das reduziert effektiv das Flackern und verringert zudem den Aufwand für das Neuzeichnen, weshalb der Ablauf selbst beschleunigt wird. |
AW: Label in Schleife zeichnen lassen
Ja das wäre mir schon klar, deswegen habe ich das Label auf Transparent := FALSE gesetzt, dadurch zeichnet das Label ja voher den Hintergrund auf clBtnFace.
Zweitens ich habe es schon das ich nur alle 20ms mal zeichne. Aber trotzdem passiert es bei mir dann, das ich teilweise dann für ne sekunde oder so nur den hintergrund sehe also alles clBtnFace ist, und KEIN text, öfters blinkt dann der Text mal auf. Wie wenn der Text nicht gleich gezeichnet wird Werde aber auf jeden Fall auf static Text umstellen |
AW: Label in Schleife zeichnen lassen
Was mir auch komisch vorkommt.
Wenn ich es mit dem Debuger durchgehe, und nebenbei das Fenster sehe. Dann sehe ich das wenn er den FillRect macht, ist der Text im Fenster weg (logisch) Aber nach dem DrawText, sieht man im Fenster noch nix. Erst wenn er das nächste mal wieder zum FillRect kommt im Debugger, dann sehe ich im Fenster das nun der alte Text da steht. |
AW: Label in Schleife zeichnen lassen
Hallo,
1 bis 1.000.000 zählt. Willst Du jetzt 1.000.000 neu zeichnen. Macht für mich keinen Sinn. Besser z.B. in bestimmten Zeitpunkten (hier alle 1000)
Delphi-Quellcode:
if (i mod 1000)=0 then
begin Label.Caption:= 'bla'; Application.ProcessMessages; end; |
AW: Label in Schleife zeichnen lassen
nein, ich zeichne nur alle 20ms sowas
Delphi-Quellcode:
aber ich will eben keine ProcessMessages, sondenr nur das .paint
if (fLastRepaint = 0) or (fRepaintEvery = 0) or (GetTickCount > fLastRepaint+fRepaintEvery) then begin
fLastRepaint := GetTickCount; Label1.Paint; end; |
AW: Label in Schleife zeichnen lassen
Vielleicht wäre es sinnvoller mit einem Thread und einer threadbasierten Anzeige zu arbeiten. Ich habe hier vor einiger Zeit ein paar multithreadfähige Komponenten angefangen:
![]() Damit kannst du ein zweites Fenster aufmachen und direkt aus einem Thread heraus ohne Synchronisierung aktualisieren. Dann brauchst du auch kein ProcessMessages. Es gab dafür offenbar kein Interesse, deshalb habe ich da nicht viel weiter gemacht, aber grundlegende Funktionen (Textanzeige, Fortschjrittsanzeige, Positionierung, Schriftarten) sind vorhanden, siehe Demo. Mein nächstes Ziel ist z.B. die Implementierung von Anchors. |
AW: Label in Schleife zeichnen lassen
Zitat:
Ich empfehle die Verwendung einer gelockten globalen variable/record. Im einfachsten Fall verwende einfach TInterlocked.Increment(FMyProgress); TInterlocked.Increment(FMyProgressHasChanged); Du kannst in deiner UI einen Timer nehmen und dort alle X ms abfragen ob sich FMyProgressHasChanged geändert hat, und wenn ja dein Label/UI mit den Daten aus FMyProgress zu aktualisieren. Schau Dir mal die Klasse TMultiReadExclusiveWriteSynchronizer an. Damit kann man sehr effektive Locks realisieren. Das Prinzip ist immer, dass ein Thread nur auf seinen Daten arbeitet und einen gelockten 2. Datensatz dafür verwendet, bei Bedarf Daten dem Hautpformular zur Verfügung zu stellen. Ich empfehle einen riesen Bogen um TThread.Synchronize zu machen. Das Ding hätte nie erfunden werden sollen. Falls es nicht um threads geht schau mal hier: ![]() Vielleicht reicht auch schon ein Label1.Update. |
AW: Label in Schleife zeichnen lassen
Ja will das ganze ohne Thread.
und ja das TLAbel.Update sieht zumindest auf den ersten Blick mal genau nahc dem aus was ich brauche :D Danke |
AW: Label in Schleife zeichnen lassen
Das mit dem Thread klingt zwar auch sehr interessant, werde mir das bei Gelegenheit auch mal anschauen, sowas könnte ich für den Fortschritt bei sql Abfragen vorstellen.
Vorallem, wenn das .Open mal länger dauert, das man nicht glaubt alles ist gerade tot (das sql.Open MUSS teils im Hauptthread passieren - daher Progress oder "ich bin nicht tot" anzeige dann ausgelagert) Aber für den aktuellen Fall zu oversized |
AW: Label in Schleife zeichnen lassen
Zitat:
Denn der ganze visuelle Kram den dein Programm und alle Fenster machen hängt da ja auch drinne. Manche DB Komponenten bieten dafür ein Event an was von Zeit zu Zeit feurt. Da kann man dann Application.ProcessMessages aufrufen um das programm lebendig zu halten wären der Hauptthread in wirklichkeit woanders ist. |
AW: Label in Schleife zeichnen lassen
Eventuell eine andere Komponente zur Ausgabe, z.B. TPanel, da könnte man doubleBuffered aktivieren.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:00 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz