Ereignis, das zu einer bestimmten Uhrzeit auslöst



  • Hallo

    Dann benutz bitte den Debugger und versuch mal, den Quellcode zu verstehen.
    Vor allem ein Breakpoint auf die Bedingung in ClockTimerEvent() dürfte aufschlußreich sein, wenn du mal dir anschaust was für Werte in zeitpunkt und Now() verglichen werden.

    bis bald
    akari



  • habs mal versucht. Setz ich den Breakpoint in das Event und kompiliere öffnet sich das Fenster und nix passiert. Auch zu dem gesetzten Zeitpunkt nicht. Also wurde das Ereignis nicht ausgelöst. Hab dann mal den Breakpoint in die Zeile

    timer->Enabled = zeitpunkt > Now();
    

    gesetzt und gesehen, dass die Eigenschaft Enabled des Timers auf false bleibt. Hab dann einfach mal mit

    timer->Enabled = true;
    

    auf true geändert und nochmal den Breakpoint in das Event gesetzt. Dann wurde es ausgelöst und ich konnte debuggen. Da man mit Alt+F5 nicht auf Now() setzen kann hab ich mir noch eine Variable aktZeit angelegt und Now() zugewiesen. Dabei ist mir aufgefallen, dass der Wert 40695.558313 beträgt. Meine vorgegebene Zeit aber ein 0.57....-Wert ist. Soweit ich das in Erinnerung hab sind das ja doubles und die Zahl vor dem Komma sind die Anzahl der Tage. Die brauch ich ja nicht. Deshalb wird Enabled des Timers immer false. Dann kann es ja nicht gehen :)Ich hoff ich lieg damit richtig.
    Kann ich die aktuelle Zeit auch ohne Datum speichern, also mit 0 vor dem Komma?

    Edit: grad gesehen das Time() nur die Zeit nimmt.



  • ich kann es kaum glauben aber es funktioniert 🙂 Nun versuch ich mal die Zeit als property zu deklarieren. Am schönsten wär natürlich wenn ich daraus dann eine Komponente mach, da ich mehrere Zeiten hab an der ein Ereignis auslösen soll.



  • Ich würde den Timer nicht jede Sekunde ticken lassen sondern (wenn wir mal bei deinem Vorschlag bleiben) im Konstruktor die aktuelle Systemzeit holen, anhand derer die Zeit berechnen, die vergehen muss bis die gewünschte Uhrzeit eintritt und den Timer dann genau auf die Zeit einstellen.

    habe das mal so umgesetzt. Kann ich das so machen? Außerdem hab ich mal für die Zeit eine property erstellt. Da die Zeit im Konstruktor festgelegt wird kann ich ja zur Laufzeit die Zeit gar nicht ändern. Ich möchte ja, dass der Benutzer die Zeit zur Laufzeit ändern kann. Ich stell mir das so vor, dass nach einem Buttonklick die über ein Editfeld eingegebene Zeit verwendet wird. Wie mach ich das am besten?

    class ClockTimer {
       private :
          TTimer* timer;
          TDateTime zeitpunkt;
          TNotifyEvent clock_event;
          void SetZeit(TDateTime zeitpunkt) {this->zeitpunkt = zeitpunkt;}
       public:
          ClockTimer(TDateTime zeitpunkt, TNotifyEvent ce);
          ~ClockTimer();
          void __fastcall ClockTimerEvent(TObject* Sender);
          __property TDateTime zeit = {read=zeitpunkt, write=SetZeit};
    };
    //---------------------------------------------------------------------------
    
    ClockTimer::ClockTimer(TDateTime zp, TNotifyEvent ce=0) :
       timer(new TTimer(0)),
       zeitpunkt(zp),
       clock_event(ce)
    {
       unsigned short usH, usM, usS, usMS;
       TDateTime aktZeit = Time();
       timer->Enabled = zeitpunkt > aktZeit;
       TDateTime diff =  zeitpunkt - aktZeit;
       diff.DecodeTime(&usH, &usM, &usS, &usMS);
       timer->Interval = 1000 * (usS + usM * 60.0 + usH * 3600.0 + int(diff) * 86400.0 + usMS/1000.0);
       timer->OnTimer = ClockTimerEvent;
    }
    //---------------------------------------------------------------------------
    ClockTimer::~ClockTimer()
    {
      delete timer;
    }
    //---------------------------------------------------------------------------
    void __fastcall ClockTimer::ClockTimerEvent(TObject* Sender)
    {
       TDateTime aktZeit = Time();
       if (zeitpunkt <= aktZeit) {
          zeitpunkt = TDateTime();
          timer->Enabled = false;
          if (clock_event)
             clock_event(0);
       }
    }
    

    Der Button müsste ja die Eigenschaft "zeit" auf den gewünschten Zeitpunkt setzen. Da wurde aber der Konstruktor ClockTimer im Konstruktor der Form schon aufgerufen. Oder muss ich für das Event noch eine property schreiben?

    Edit: Man könnte ja auch wie beim TTimer eine Eigenschaft Enabled anlegen. Wenn Enabled wahr ist könnte der ClockTimer laufen. Wäre das eine Möglichkeit? Wie setz ich das am besten um?



  • wenn ich also im Konstruktor der Form das ClockTimer-Objekt mit dem Zeitpunkt im Konstruktor erzeuge wird das Event wie gewünscht zu dem Zeitpunkt ausgelöst. Wenn ich den Konstruktor ohne zeit-Parameter aufrufe (wie im Code unten) und die Eigenschaft zeit setze funktioniert es nicht.

    __fastcall TForm1::TForm1(TComponent* Owner)
       : TForm(Owner)
    {
       TDateTime myTime = StrToTime("12:00:00");
       clk = new ClockTimer(MeinEvent);
       clk->zeit = myTime;
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::MeinEvent(TObject* Sender)
    {
      ShowMessage("Event ausgelöst");
    }
    


  • Setzt du im Konstruktor deiner Klasse den Timer auf Enabled = true? Oder steht da immernoch die Variante mit "zeitpunkt > aktZeit" drin? Denn das wäre immer false und führt dazu das nix geht.

    Du könntest alles was im Konstruktor steht in eine Funktion machen und die dann nach dem Setzen der Zeit aufrufen.



  • Oder steht da immernoch die Variante mit "zeitpunkt > aktZeit" drin?

    Stimmt, da stand das immer noch drin. Da brauch im mich nicht wundern. Hab nun eine Methode StartClockTimer geschrieben und nu funktionierts:

    __fastcall TForm1::TForm1(TComponent* Owner)
       : TForm(Owner)
    {
       clk = new ClockTimer(&MeinEvent);
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::MeinEvent(TObject* Sender)
    {
      ShowMessage("Event ausgelöst: " + TimeToStr(Time()));
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::LMDButton1Click(TObject *Sender)
    {
       TDateTime myTime = StrToTime(txtEingabeZeit->Text);
       clk->Zeit = myTime; // hier über property
       clk->StartClockTimer();
    }
    

    Kann man das so machen oder gibts Verbesserungsbedarf?



  • Jau, StrToTime gehört in einen try-catch Block, da eine EConvertError Exception geworfen werden könnte. Und eine Überprüfung, ob der Zeitpunkt in der Zukunft liegt wäre auch gut.



  • DocShoe schrieb:

    Jau, StrToTime gehört in einen try-catch Block, da eine EConvertError Exception geworfen werden könnte.

    Nein. Wenn man mit dem Fehler rechnet, nehme man TryStrToTime().



  • Wie prüf ich ob der Zeitpunkt in der Zukunft liegt?

    ich hab das Problem, dass das Event zu der eingegebenen Uhrzeit auslöst aber am nächsten Tag nicht wieder eintritt.


Anmelden zum Antworten