dynamische Label
-
WebFritzi schrieb:
- Wichtiges Ereignis ist da (sollte eigentlich genau jetzt angezeigt werden)
- Timer wartet ein paar Sekunden
- Ereignis wird angezeigt, allerdings viel zu spätGanz offensichtlich ist der, der sich beschwert, dass seine Beiträge nicht gelesen werden, selber einer, der Beiträge nicht (richtig) liest. Erlaube mir, deine Einwände zu kommentieren:
WebFritzi schrieb:
- Timer wartet ein paar Sekunden
UnEinloggbar schrieb:
Wer sagt denn bitte, dass der Timer 1-2 Sekunden Intervalle fahren soll? Ausserdem ist erfahrungsgemäss alles was eine schnellere Änderungsrate hat als 2Hz (0.5s Pause) unleserlich für den Benutzer und damit ohnehin uninteressant...
WebFritzi schrieb:
- Ereignis wird angezeigt, allerdings viel zu spät
Falsch. Du überschreibst ja den Status immer mit dem jüngsten status. Ereignisse die also "kurz" auftreten, werden gar nicht angezeigt. Nutzt auch nichts, etwas anzuzeigen, ohne dass der User die Zeit hat, es zu lesen. Und wenn der Status mit mehr als 2Hz wechselt, würde ich mich sowieso fragen ob da nicht was anderes falsch ist.
-
Entschuldige, aber du drückst dich so unklar aus, dass das, was du willst, unverständlich ist. Ich habe immer noch keinen blassen Schimmer, was hier ein Timer soll. Erkläre doch bitte nochmal ganz genau, wie das laufen sollte. Danke.
-
WebFritzi schrieb:
Entschuldige, aber du drückst dich so unklar aus, dass das, was du willst, unverständlich ist. Ich habe immer noch keinen blassen Schimmer, was hier ein Timer soll. Erkläre doch bitte nochmal ganz genau, wie das laufen sollte. Danke.
*ROFL*

-
Also nochmals zum mitzeichnen für Analphabeten:
Ich habe ein Element welches mir den momentanen Status speichert. Der Einfachheithalber sei das eine Variable FStatus des Typs AnsiString der Formularklasse. In diese Variable wird über ZUgriffsfunktionen von diversen Quellen der Status der Applikation geschrieben. Kommt die Applikation in einen neuen Status, wird der alte überschrieben.
Nun schreit der Schlaue webfritzi aber: Speicherverschwendung! Da kann ich ja grad so gut direkt in die Caption des anzeigenden Labels schreiben. Grundsätzlich hat er auch recht. Die Frage ist allerdings, was die Konsequenz eines Statuslabel->Caption = "neuer Status" ist: In diesem Fall wäre es zum Einen das Überschreiben der Variabel, sowie das anschliessende, rechenaufwendige neuzeichnen des Labels, wenn nicht sogar des ganzen Formulars.
Dazu kommt, dass bei zu häufigem Statuswechsel (ich sagte ja >2 Hz oder anders ausgedrückt häufiger als alle 500ms) der Benutzer das angezeigte sowieso nicht lesen kann, daher also auch die Anzeige nonsens ist. Aus diesem Grund kann man also auch das Zeichnen des Formulars auf 2Hz (oder eben den Intervall von 500ms) beschränken.
Wozu nun also der Timer? Ganz einfach: In der Timer-Intervall-Routine steht nichts weiter als Statuslabel->Caption = FStatus. Dies führt dazu, dass das Formular nur alle 500ms damit b elästigt wird, sich neu zu zeichnen und ich mir die sonstigen unnötigen Rechenzyklen erspare.
War das jetzt verständlicher?
-
Du übersiehst nur eine Kleinigkeit: Ohne von Zeit zu Zeit ein Application->ProcessMessages() einzufügen, wird nur eine einzige 'Nachricht' angezeigt. Nämlich die allerletzte und das auch erst, sobald die App. in den Idle Modus geht. Warum sollte ich also einen Timer einsetzen, wenn ich doch sowieso manuell das Neuzeichen anfordern muß (mit ProcessMessages(), falls Du es schon wieder vergessen hast). Wie oft ich in ein Label schreibe ist dabei absolut irrelevant. Erst beim Aufruf von Application->ProcessMessages, oder wenn die Anwendung nicht mehr ausgelastet ist, wird neu gezechnet.
Und genau deshalb ist der Einsatz eines Timers Ressourcenverschwendung (!= Speicherverschwendung) und in diesem Fall absolut sinnlos. Timer stehen unter Windows nur in begrenzter Anzahl zur Verfügung, also sollte man sie nur einsetzen, wenn man sie wirklich braucht.
Joe_M.
-
Wie wäre es mit sehr wohl einem Timer, der mit Interval auf 1 Sek. gestellt wird oder wie lange es halt gewünscht ist, und du in der Timerfunktion den Timer wieder auf Enabled=false setzt, die Nachricht leerst usw.?
Also kurzer Code, zusammengefasst:
if(Timer1->Enabled) { Timer1->Enabled=false; // Sollte der Timer noch eingeschaltet sein, also Nachrichten "zu schnell" erscheinen } Timer1->Enabled=true; Label1->Caption=message;Und im OnTimer:
Timer1->Enabled=false; Label1->Caption="";Also dass der Timer hier als "Verzögerer" eingesetzt wird, und sich nur einmal aufruft. Ist vielleicht mit Kanonen auf Fliegen geschossen, jedoch wohl hierbei und mit dem BCB die einfachste Variante, wenn man kein sleep() verwenden möchte... so finde ich jedenfalls.

-
Manchmal fühle ich mich sooo müde...
Ich gebs auf.
Joe_M.
-
Nimm doch Sleep, wie bereits erwähnt, aber verarbeite die Labels in einem Thread, so kann das Programm weiterlaufen, während der Thread die Zwangspause einlegt. Also ich find da ist akualität vorhanden.
-

Manchmal fühle ich mich sooo müde...

-
Christian2111 schrieb:

Manchmal fühle ich mich sooo müde...

Ja, das ist nunmal so, wenn man denn Sinn für die einfachsten und sinnvollsten Lösungsansätze verloren hat ....
-
zufaulzumeinloggen schrieb:
Du übersiehst nur eine Kleinigkeit: Ohne von Zeit zu Zeit ein Application->ProcessMessages() einzufügen, wird nur eine einzige 'Nachricht' angezeigt.
Wieso sollte dem so sein? Wenns ist, weil irgendwo in nem Button-Click ne Schleife abläuft, dann habe ich dazu bereits Stellung bezogen:
UnEinloggbar schrieb:
Joe_M. schrieb:
Ich kann Dir die Antwort auch direkt geben: Gar nicht! Zumindest solange nicht, wie Du aus der Schleife heraus nicht Application->ProsessMessages() aufrufst.
Weshalb man ja auf intensive Schleiferei innerhalb eines Eventhandlers wie z.B. ButtonClick verzichten, und derlei Operationen in weitere Threads auslagern sollte...
Application->ProcessMessages ist ja das was immer, ganz ohne dein Zutun, läuft wenn nicht grade ne Nachricht bearbeitet wird. Das ist ja der Witz daran. Alles und jedes (auch jeder ButtonClick) ist nichts weiter als eine von ProcessMessages() verarbeitete Nachricht. Kannst du auch ganz einfach testen: Mach nen Button der nur
while(true) { Application->ProcessMessages(); Sleep(1); }ausführt. Dazu ein anderer in dessen Eventhandler du nen Breakpoint setzt. Nun klickst du erst auf den ersten Button, dann auf den zweiten. Wenn die Applikation dann anhält, wirst du feststellen, dass im Callingstack zwei mal Application->ProcessMessages() aufgeführt wurde. Der tiefer liegende Aufruf hat die erste Eventhandler-Routine aufgerufen, die höher liegende die zweite mit dem Breakpoint. Das Spiel lässt sich so beliebig fortsetzen.
@Sphy: DAS wiederum ist nun wirklich unsinnig!
-

-
remarker schrieb:
Christian2111 schrieb:

Manchmal fühle ich mich sooo müde...

Ja, das ist nunmal so, wenn man denn Sinn für die einfachsten und sinnvollsten Lösungsansätze verloren hat ....
das Joe hier der einzigste ist, der die sache nicht nur von der funktionalität betrachtet, ist schade, und das der einzig sinnvolle und richtige weg der vorgeschlagen wird, irgendwie ignoriert wird, ist auch schade!
darum @ threadsteller: ließ einfach nur die posts von joe, die anderen wollen oder können es nicht richtig verstehen!
-
Da Joe und Fritz allerdings die Funktionalität nicht ganz verstanden haben können sie auch keine vernünftigen Lösungen hier anbieten.
Hat ja niemand bestritten das es ab und zu sinnvoll ist, ein ProcessMessages aufzurufen.
Das mit den Nachrichten im Label ist aber nunmal eleganter über einen Timer zu lösen. Nur um eine Nachricht in einem Label anzuzeigen, gleich seine komplette Anwendung über einen Sleep zu blockieren ist einfach nur schwachsinnig. Sleep ist in diesem Fall einfach nur dirty ...
Aber naja. Da muss man dann halt mit verschiedenen Meinungen leben ...
-
darum @ threadsteller: Ignorier einfach die sturen Möchtenichtsbegreifer.
Dont feed the Troll ...
-
teatimer schrieb:
Da Joe und Fritz allerdings die Funktionalität nicht ganz verstanden haben können sie auch keine vernünftigen Lösungen hier anbieten.
Hat ja niemand bestritten das es ab und zu sinnvoll ist, ein ProcessMessages aufzurufen.
Das mit den Nachrichten im Label ist aber nunmal eleganter über einen Timer zu lösen. Nur um eine Nachricht in einem Label anzuzeigen, gleich seine komplette Anwendung über einen Sleep zu blockieren ist einfach nur schwachsinnig. Sleep ist in diesem Fall einfach nur dirty ...
Aber naja. Da muss man dann halt mit verschiedenen Meinungen leben ...wer einen timer als elegant bezeichnet, um einfache "satusanzeigen" wiederzugeben, sollte das hobby wechseln!
das sleep in anbetracht des problems sicher nciht gut ist, ist klar, aber ein timer....wie gesagt...
-
HINWEIS:
Zwei mit Beleidigungen gespickte Beiträge von 'teatimer' gelöscht, dasselbe Schicksal wird alle weiteren unsachlichen bzw. OffTopic-Beiträge ereilen.
-
ser1al schrieb:
remarker schrieb:
Christian2111 schrieb:

Manchmal fühle ich mich sooo müde...

Ja, das ist nunmal so, wenn man denn Sinn für die einfachsten und sinnvollsten Lösungsansätze verloren hat ....
das Joe hier der einzigste ist, der die sache nicht nur von der funktionalität betrachtet, ist schade,
Funktionalität zu einem brauchbaren Ressourcen Aufwand ist die Devise.
ser1al schrieb:
und das der einzig sinnvolle und richtige weg der vorgeschlagen wird, irgendwie ignoriert wird, ist auch schade!
Welcher? Direkt in das Label zu schreiben? und auf gut Glück etwas "ProcessMessages" aufzurufen? Ich bitte dich! Dann frage ich mich, wieso die Argumente ignoriert werden....
ser1al schrieb:
wer einen timer als elegant bezeichnet, um einfache "satusanzeigen" wiederzugeben, sollte das hobby wechseln!
Ich glaube, in dem Fall sollte ich meinen Beruf wechseln, denn ich arbeite eigentlich nur so, dass die Ausgaben Zeitgetriggert und nicht Eventgetriggert "gerendert" (MAn kann eigentlich nicht immer von rendern sprechen, da irgendwelche LED auf Embeddedsystemen nicht unbedingt "gerendert" werden...) werden. Ihr seid einfach alle zuverwöhnt mit Rechenleistung und seid euch gar nicht bewusst, was es heisst, permanent ein Label neu zeichnen zu lassen.
An meinem Letzten Arbeitsort wurden übrigens alle Panel Timergetrieben mit etwas zwischen 2 bis 5 Hz gerendert. Probiert doch einfach mal Aktualisierungen > 5Hz selbst mal aus und versucht dann zu urteilen ob ihr derart schnelle Wechsel an Statusanzeigen bevorzugt, geschweige denn erfassen könnt.Drehen wirs mal um: Nur weil ihr Hobbiisten keine Relation zur Geschwindigkeit mehr habt, ist das noch lange kein Grund, die wertvollste Ressource in einem PC: Die Rechenzeit sinnlos zu vergeuden.
-
Man erstelle ein neues Projekt.
2 Button, 2 Label, 1 Memo, 1 Timer
Man stelle den Timer auf disabled (Wir wollen ja nicht, dass während der gesamten Laufzeit des Programms einmal pro Sekunde, oder sogar noch öfter, das OnTimer-Ereignis durchlaufen wird).
Die Ereignisfunktionen:void __fastcall TForm1::Button1Click(TObject *Sender) { Button1->Enabled = false; Label1->Caption = "----"; unsigned int uiStart, uiEnde; int iMax = 100000000; uiStart = GetTickCount(); for (int j = 0; j < 4; ++j) { for (int i = 0; i < iMax; ++i) { int dummy = 1 * 2; } Label1->Caption = "Durchlauf " + AnsiString(j); Application->ProcessMessages(); } uiEnde = GetTickCount(); Memo1->Lines->Add("Eventgestuert: " + AnsiString(uiEnde - uiStart) + " ms"); Button1->Enabled = true; } //--------------------------------------------------------------------------- void __fastcall TForm1::Button2Click(TObject *Sender) { Button2->Enabled = false; if (!Timer1->Enabled) Timer1->Enabled = true; Label2->Caption = "----"; unsigned int uiStart, uiEnde; int iMax = 100000000; uiStart = GetTickCount(); for (int j = 0; j < 4; ++j) { for (int i = 0; i < iMax; ++i) { int dummy = 1 * 2; } asMessage = "Durchlauf " + AnsiString(j); // Application->ProcessMessages(); } uiEnde = GetTickCount(); Memo1->Lines->Add("Timergesteuert: " + AnsiString(uiEnde - uiStart) + " ms"); if (Timer1->Enabled) Timer1->Enabled = false; Button2->Enabled = true; } //--------------------------------------------------------------------------- void __fastcall TForm1::Timer1Timer(TObject *Sender) { if (!asMessage.IsEmpty()) { Label2->Caption = asMessage; asMessage = EmptyStr; } } //---------------------------------------------------------------------------Einfach mal ausprobieren so. Man wird schnell feststellen, dass bei Button2 keine einzige von den Nachrichten ausgeben wird. Erst wenn das auskommentierte Application->Messages(); (welches nach UnEinlogbars Aussage Glücksspiel ist) in der Button2Click aktiviert wird, wird überhaupt eine Nachricht im Label2 ausgegeben. Allerdings nur die letzte. Jetzt muß man anfangen, mit dem Timerintervall herumzuexperimentieren. Bei einem Intervall von 500 werden immer noch einzelne Nachrichten unterschlagen. Erst bei einem Intervall <= 200 (auf meinem Rechner) werden alle Nachrichten ausgeben. Manchmal wird jedoch auch hierbei noch die letzte Nachricht unterschlagen. Natürlich könnte man den Timer immer aktiviert lassen und dieses Problem damit umgehen, aber dann würde die Timerroutine während der gesamten Laufzeit des Programms 5 Mal in der Sekunde ausgeführt. Das betrachte ich dann allerdings nicht als Ressourcenschonend. Und über die gesamte Laufzeit einer Applikation gesehen, verbrät das garantiert mehr CPU-Zyklen.
Auf Threads gehe ich hier nicht ein, weil der Fragesteller offensichtlich keine Threads verwendet. Es ist sicherlich sinnvoll, langwierige Berechnungen in Threads auszulagern, allerdings sollten hierbei so wenig grafische Ausgaben, wie irgend möglich getätigt werden, da das Synchronisieren zwischen Thread und Anwendung eine Menge Zeit kostet.Und noch einmal: Windows-Timer stehen nur in begrenzter Anzahl zur Verfügung. Wenn also jede Anwendung für jedes Fenster einen Timer zur Anzeige verwenden würde, wären wir bald wieder bei Windows 3.xx Fehlermeldungen a la: Für diese Anwendung stehen nicht genügend Ressourcen zur Verfügung. Schließen Sie eine oder mehrere Anwendungen.
-
Da du offensichtlich nicht gemerkt hast, dass hier ein Applikationsdesign-Problem angeschnitten wurde, gehe ich mal nicht näher auf dein Beispiel ein. Nur soviel: Du hast genau das was ich explizit ausgeschlossen habe gemacht, nämlich eine lange Operation dort hingepflanzt wo sie nicht hingehört: In die Bearbeitung einer Nachrichtenschleife.
Ich muss dir recht geben: Grafische Ausgaben sollte man bei der Verwendung von Threads auf ein Minimum reduzieren. Ein weiterer Grund, wieso der Thread nicht die Ausgaben via Synchronize und direktem Labelschreiben triggern soll (da wären wir ja wieder soweit wie bei deinen Beispielen. Und da wollen wir ja wirklich nicht hin), sondern die Anzeige sich die nötigen Daten (Durchlauf x von y zum Beispiel) vom Thread über ein Attribut besorgen soll.
Und noch was: Anzeigen welche mit > 5 Hz ihren Text ändern sind nunmal nichtmehr sinnvoll erfassbar. Klar, rauscht deine Zahl nun schön nach oben. Nur was bringts dir? Denn die einzelnen Zahlen kannst du gar nicht erst lesen.
Auf Threads gehe ich hier nicht ein, weil der Fragesteller offensichtlich keine Threads verwendet.
Das ist im Übrigen ein schlechtes Argument. Know why? Wenn man schon sieht dass jemand etwas sagen wir mal nicht allzu elegant löst, dann sollte man ihm die Möglichkeit geben, gleich was dazu zu lernen und ihm die besseren Möglichkeiten aufzeigen.
Im Übrigen hab ich ProcessMessages() nicht als Glücksspiel bezeichnet. Nur bin ich ein Gegner von schlecht designten Applikationen in welche wahllos (denn sie wissen nicht, wie sies besser tun könnten) ProcessMessages() verteilt wird und man sich schlussendlich drüber wundert, wieso einem irgendwann plötzlich der Stack über geht.
So Praktisch der BCB hald ist, so sehr verleitet er leider auch (wie VB und andere RAD-Umgebungen) zu vermurksten, ineffizienten Applikationsdesigns.