dynamische Label



  • ja so hab ichs ja, ich setze die Labels in den Funktionen.

    nur ist es für den Anwender nicht mehr wichtig was vor 20 sec
    geschehen ist. deshalb ist die Akualität ja relativ wichtig.

    das Ding soll nur kurz anzeigen, was er grad tut,
    mehr isses nicht...



  • Mach es doch einfach mit einem Timer. Stell den Intervall auf den Wert, den du brauchst, und gut ist.

    Unit1.h

    //---------------------------------------------------------------------------
    
    #ifndef Unit1H
    #define Unit1H
    //---------------------------------------------------------------------------
    #include <Classes.hpp>
    #include <Controls.hpp>
    #include <StdCtrls.hpp>
    #include <Forms.hpp>
    #include <ExtCtrls.hpp>
    //---------------------------------------------------------------------------
    class TForm1 : public TForm
    {
    __published:	// Von der IDE verwaltete Komponenten
       TTimer *Timer1;
       TButton *Button1;
       TButton *Button2;
       TButton *Button3;
       TLabel *Label1;
       void __fastcall Button1Click(TObject *Sender);
       void __fastcall Button2Click(TObject *Sender);
       void __fastcall Button3Click(TObject *Sender);
       void __fastcall Timer1Timer(TObject *Sender);
    private:	// Anwender-Deklarationen
    String message;
    public:		// Anwender-Deklarationen
       __fastcall TForm1(TComponent* Owner);
    };
    //---------------------------------------------------------------------------
    extern PACKAGE TForm1 *Form1;
    //---------------------------------------------------------------------------
    #endif
    

    Unit1.cpp

    //---------------------------------------------------------------------------
    
    #include <vcl.h>
    #pragma hdrstop
    
    #include "Unit1.h"
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    TForm1 *Form1;
    //---------------------------------------------------------------------------
    __fastcall TForm1::TForm1(TComponent* Owner)
       : TForm(Owner)
    {
    
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
       message="tue dies";
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button2Click(TObject *Sender)
    {
       message="tue das";
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button3Click(TObject *Sender)
    {
       message="tue nochirgendwas";
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Timer1Timer(TObject *Sender)
    {
       if(message!=EmptyStr)
       {
          Label1->Caption = message;
          message=EmptyStr;
       }
    }
    //---------------------------------------------------------------------------
    


  • Nee, das mit dem Timer ist Quatsch, weil so erstens Messages unterschlagen werden könnten, die wichtig sind, und zweitens sollte der Anwender doch wissen, was das Programm direkt gerade macht, und nicht erst nach 1 bis 2 Sekunden. Vor allem, wird der User betrogen, wenn da "Performing Search..." oder so steht, was aber gerade vor 2 Sekunden der Fall war.
    Wenn die Nachrichten so schnell reinkommen, dass man sie nicht lesen kann, dann ist so ein Label eh Blödsinn. Es erfüllt seinen Zweck nicht: Information des Users. Wenn du keinen Platz hast, dann mach dir dafür eben ein Extra-Fenster und darein ne ListBox o.ä. Oder zeig eben keine Infos an und erstelle ein LogFile, wie oben bereits vorgeschlagen.



  • WebFritzi schrieb:

    Nee, das mit dem Timer ist Quatsch, weil so erstens Messages unterschlagen werden könnten, die wichtig sind, und zweitens sollte der Anwender doch wissen, was das Programm direkt gerade macht, und nicht erst nach 1 bis 2 Sekunden.

    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...



  • P.S: Entsprechend also ist der Ansatz mit dem Timer hier sicher nicht der dümmste. Die Version mit dem Sleep halte ich für etwas gewagt, da sie tatsächlich den ganzen Applikationsthread und damit die Verarbeitung der Nachrichtenschleife blockiert für 200ms. Ausser natürlich man verwendet eine Schleife mit dem Inhalt Sleep(1) und Application->ProcessMessages(). Das wiederum ist aber eine massiv ungenauere und umständlichere Variante als sie eigentlich nötig wäre. Denn genau für solche Fälle stellt Windows ja TimerCallbacks zur Verfügung.



  • Ich kann Webfritzi nur zustimmen. Unter den gegebenen Umständen ist der Einsatz eines Timers absolut sinnlos. Wo soll denn da der Vorteil gegenüber einem direkten Schreiben in das Label sein? Im Gegenteil, es ist ungünstiger, weil es mehr Ressourcen verbraucht.



  • also ich lass das erstmal so,
    wie ich das gemacht habe,
    es funktioniert und ich zeige halt nur das wichtigste an.

    den Rest lass ich halt loggen.
    trotzdem Danke für eure Antworten.



  • Joe_M. schrieb:

    Ich kann Webfritzi nur zustimmen. Unter den gegebenen Umständen ist der Einsatz eines Timers absolut sinnlos. Wo soll denn da der Vorteil gegenüber einem direkten Schreiben in das Label sein? Im Gegenteil, es ist ungünstiger, weil es mehr Ressourcen verbraucht.

    Du Widersprichst dir immer wieder selber hier.
    Das mit dem Timer verbraucht absolut nicht mehr Resourcen.
    Das Blockieren der Anwendung ist allerdings wie schon gesagt als absolut sinnlos zu betrachten.
    Also mit dem Timer ist dies der beste Ansatz, da es ihm nicht darauf ankommt, ob ältere Meldungen in der Anzeige unterschlagen werden ...



  • Ich widerspreche mir nicht, sondern versuche den Lösungsweg an neue Informationen anzupassen.

    Probier Deine Timerlösung doch einfach mal selbst aus. Und zwar nicht mit Buttons sondern in einer Schleife. Du wirst sehr schnell merken, dass dieser Lösungsweg nicht gangbar ist. Was glaubst Du denn, wie oft der Timer aufgerufen wird, wenn die Anwendung ausgelastet ist? Ich kann Dir die Antwort auch direkt geben: Gar nicht! Zumindest solange nicht, wie Du aus der Schleife heraus nicht Application->ProsessMessages() aufrufst. Und dann kannst Du dir den ganzen Firlefanz mit dem Timer auch direkt sparen und das Label vor dem Application->ProcessMesssages() setzen.



  • Joe_M. schrieb:

    Was glaubst Du denn, wie oft der Timer aufgerufen wird, wenn die Anwendung ausgelastet ist?

    Innerhalb eines gewissen Zeitrahmens nach dem Ablauf des Intervalls. Alles andere sind höchstens schlechte/fehlerhafte Applikationsdesigns.

    Joe_M. schrieb:

    Wo soll denn da der Vorteil gegenüber einem direkten Schreiben in das Label sein? Im Gegenteil, es ist ungünstiger, weil es mehr Ressourcen verbraucht.

    Das ist nicht richtig. Das direkte Schreiben ins Label hat mehrere Nachteile. Folgendes hängt an jedem neuen Setzen der Caption mit dran:
    Schreiben des Labels
    Neu zeichnen des Forms oder des Form-Bereichs

    Was passiert jetzt bei einer hohen Schreibkadenz? Dein Rechner wird nur damit beschäftigt sein, das Label zu zeichnen und klaut dir damit Rechenzeit (ebenfalls eine Ressource) für sinnvollere Anwendungen. Ausserdem ist es doch verschwendung etwas zu zeichnen, das sowieso nicht gelesen werden kann? (Stichwort Updaterate, hatte ich vorher schon erwähnt).

    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...

    Joe_M. schrieb:

    Und dann kannst Du dir den ganzen Firlefanz mit dem Timer auch direkt sparen und das Label vor dem Application->ProcessMesssages() setzen.

    Nö. Viel besser wäre es den Applikations"design" zu kippen und über was brauchbares wie MVC oder Document/View nachzudenken.



  • Also: Sleep() ist Quatsch und alles reinschreiben ins Label ist Quatsch, da zu schnell, um es zu lesen. Ich denke, da sind wir uns alle einig. Ein Timer ist aber auch Quatsch. Ich habe das doch schon erläutert. Ihr lest meine Beiträge einfach nicht richtig. Das Label soll doch sowas wie eine Status-Information sein. Wenn man ein Label verwendet, werden aber öfter Stati angezeigt werden, die schon lange nicht mehr aktuell sind:

    - Wichtiges Ereignis ist da (sollte eigentlich genau jetzt angezeigt werden)
    - Timer wartet ein paar Sekunden
    - Ereignis wird angezeigt, allerdings viel zu spät

    Wie gesagt: damit wird der User belogen, weil die Aktion, welche angezeigt wird, weder momentan in Gange ist noch gerade eben beendet worden ist.



  • Wie gesagt: damit wird der User belogen, weil die Aktion, welche angezeigt wird, weder momentan in Gange ist noch gerade eben beendet worden ist.

    Was wie hier schon 1000mal erläutert wurde, hier nicht von Relevanz ist ... 🙄



  • WebFritzi schrieb:

    - Wichtiges Ereignis ist da (sollte eigentlich genau jetzt angezeigt werden)
    - Timer wartet ein paar Sekunden
    - Ereignis wird angezeigt, allerdings viel zu spät

    Ganz 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.


Anmelden zum Antworten