Timer - Solange ausführen bis Beenden gedrückt wurde



  • Hallo

    Ich lade aus dem Internet ein Bild herunter das in einem Dialogfesnter angezeigt wird. Da dies ein Radarbild ist, welches alle 10 Minuten aktualisiert wird, möchte ich während dem laufenden Programm dieses Bild (m_Picture, IDC_MYPICTURE) alle 10 Minuten automatisch neu Laden und zeichnen, ohne den Rest des Programmes zu blockieren.

    Ich habe mich mal mit dem Thema Threads auseinadnergestzt aber werde nicht schlau daraus. Bisher versuchte ich es mit einem Timer, der alle 10 Minuten das Bild neu lädt und danach m_Picture mittels Invalidate aktualisiert. Dies wollte ich in eine While-Schleife packen wenn nBeenden = TRUE ist, dann sollte der Timer beendet werden. Ansonsten immer weiterlaufen.

    Ich weiss es ist keine Optimale Lösung jedoch verstehe ich noch nicht ganz wie ich das mit einem Thread mach. Meine While-Funktion hängt sich auf, es wird kein Bild geladen. 🙂

    Hier mal den Timer:

    void CHauptDlg::OnTimer(UINT_PTR nIDEvent)
    {
    	// TODO: Add your message handler code here and/or call default
    	nBeenden = 0;
    
    	while(nBeenden == 0) {
    
    	GetPicFromHTTP("http://www.meteo-radar.ch/bilder/mch_aktuell.gif", GetApplicationDirector());
    
    	if (m_Picture.Load(_T(GetApplicationDirector() + "mch_aktuell.gif")))
    	 m_Picture.Draw();
    	m_Picture.Invalidate();
    	Sleep(60000);
    	}
    	KillTimer(TRUE);
    
    	CDialogEx::OnTimer(nIDEvent);
    }
    

    Wenn ich dann auf den Button (zu Testzwecken) Timer STOP klick geb ich dem Wert nBeenden den Wert 1.

    void CHauptDlg::OnBnClickedButton1()
    {
    	// TODO: Add your control notification handler code here
    	nBeenden = 1;
    }
    

    Keine Fehler, aber nach dem Zeichnen von HauptDlg erscheint weder Bild noch Buttons oder andere Controls und das Programm lässt sich nur via Taskmanager beenden. Daher möchte ich das obige Vorgehen als Thread realisieren da es später noch mehr Dinge gibt die aktualisiert werden müssten bis das Programm beendet wird. Wie fang ich da am besten an??

    Gruss
    WolfCH


  • Mod

    Das ist doch Quatsch, die Endlosschleife im Timer Handler.

    Mach das, was Du immer wieder machen möchtest im OnTimer Handler. Der Handler wird immer wieder aufgerufen...
    Schmeiß alles raus was Sleep und Schleife ist..

    Im OnInitDialog einfach SetTimer ausführen, im Button Handler für das Beenden einfach KillTimer...



  • Daran hab ich noch nicht gedacht.
    Hast recht. Allerdings nützt mir das nicht, da das eine Radarbild nur alle 10 Minuten neu geladen werden müsste und das andere ständig.

    Werde wohl um Threads nicht herumkommen und mich nun damit befassen. Das mit dem Timer ist eigentlich ok, aber für diese Zwecke bullshit. Das Sleep blockiert nur das ganze Programm. Wo erhalte ich, ausser in der MSDN, mehr Infos zu Threads?

    Gruss
    WolfCH



  • So. Ich hab das ganze mal in einen Thread gepackt:

    CDialogEx::OnInitDialog();
    
    	// TODO:  Add extra initialization here
    	LPVOID pParam = &m_Picture;
    	::AfxBeginThread(loadRadar,pParam);
    

    Der Thread:

    UINT loadRadar(LPVOID pParam)
    {
    
    	CPictureEx *pPicture = (CPictureEx*)pParam;
            label_new:
    	GetPicFromHTTP("http://www.meteo-radar.ch/bilder/mch_aktuell.gif", GetApplicationDirector());
    
    	if (pPicture->Load(_T(GetApplicationDirector() + "mch_aktuell.gif")))
    	 pPicture->Draw();
    	 pPicture->Invalidate();
             Sleep(300000);
             goto label_new;
    
    	 return 0;
    }
    

    EDIT: Hab es nun mit Sleep(300000); und goto label gelöst. So wird das Bild nur alle 5 Minuten neu geladen. - Gibt sicher ne schönere Variante..

    Beenden wollt ich den Thread mit einem Button, hab da unter OnClickedButton folgendes geschrieben:

    ::AfxEndThread(TRUE);
    

    aber dann erhalte ich einen ASSERCION FAILED! Fehler im laufenden Programm.

    Gibts dafür eine schönere Lösung? Respektive wie lös ich das nun mit mehreren Threads, wenn mehrere Bilder aktualisiert werden sollten?
    Und wenn ich den Thread erst bei Programmende beenden möchte müsste ich Theoretisch ja nix tun, sondern nur so lassen? Allerdings frisst mir das wiederum Rechenleistung unnötig..

    Gruss
    WolfCH



  • Oh augenkrebs, ein goto ist ja nun mal ein no go, das geht ja mal gar nicht. Wenn das dann schon ein thread sein soll, dann bau eine while drum rum und setz eine Variable wenignstens zum beenden. da du größere Pausen drin hast solltest du die sache etwas geschickter anstellen, sonnst wirst du dein Problem mit dem absturz nicht in griff bekommen, weil du den Thread beim Programmende immer absägst.

    warum du nicht einfach 2 timer benutzt? den einen lässt du in kurzen intervallen auslösen und den anderen für dein sat-bild eben aller 5 minuten oder so, dazu einfach im Timer das nIDEvent abfragen und über eine switch auf den entsprechenden code verzweigen, spaart die ne menge arbeit und ärger.


  • Mod

    Aus einem anderen Thread sollte man nicht aufUI Elemente zugreifen.
    Was ist denn Dein Problem mit dem Timer.
    Setze zwei Timer, einer der alle 50msec läuft und einer der eben alle 10min läuft.
    Geht doch alles mit einem Thread.



  • Danke für Eure Ansätze. 🙂
    Hab es nun so wie Markus Richter vorgeschlagen hat, gelöst.

    Klappt wunderbar. 🙂 Leider ist die betreffende Seite, von der die Grafik geladen werden sollte zur Zeit down..

    Gruss
    WolfCH



  • Einen UI-Thread findest Du in der FAQ. Da gibt auch noch einen Workerthread.


Anmelden zum Antworten