Hilfe bei "Stopuhr-Projekt"



  • Ich habe den Fehler:) Man muss den Zeichensatz von Unicode auf Multibyte umstellen...;-)



  • So umwandeln der Systemzeit in Zahlen:

    int stunde, minute, sekunde;
    int nCnt = sscanf(sz, "%d:%d:%d",&stunde, &minute, &sekunde);
    if(nCnt != 3)
    {
    std::cout << "Falsches Format\n";
    } 
    
    std::cout << stunde << " " << minute << " " << sekunde << "\n";
    


  • Dann deine Sekunden in Stunden, Minuten und Sekunden umrechnen, auf die entsprechenden Variablen aufrechnen und wieder in ein Uhrzeitformat umwandeln.
    Die Millisekunden noch hinten dranhängen.
    Fertig.



  • Danke für die Hilfe...

    Eine Frage hätte ich noch...wenn ich die Zeit permanent anzeigen lassen möcht, bräuchte ich sowas wie eine Endlos-For-Schleife, die ständig die Zeit berechnet und ausgibt? Wie muss ich das lösen?



  • Wäre es vielleicht eine Lösung, die Anweisungen in die "Paint-Nachricht" der Callback zu schreiben?



  • Nimm einen Timer. Die Berechnung kann dann im WM_TIMER-Zweig erfolgen bzw. es findet der Funktionsaufruf statt. Anschließend wird der Bereich der Ausgabe im Fenster für ungültig erklärt und neu gezeichnet.
    (die Begriffe, die du brauchst sind SetTimer & KillTimer, WM_TIMER, InvalidateRect).



  • Das würde ich mit WM_TIMER machen.

    Da kannste eine Funktion hinterschalten, die in einstellbaren Intervallen ausgeführt wird.
    Dabei übernimmt Windows die komplette Steuerung.

    Zunächst einmal mußt du eine CallBack TimerFunktion definieren.

    VOID CALLBACK TimerProc (HWND hwnd, UINT message, UINT iTimerID, DWORD dwTime)
    {
    // Hier kommt deine Ausgabefunktion der Uhrzeit rein.
    
    }
    

    Im Windows-Message-Loop mußt du dies einbauen:

    case WM_TIMER:
    return 0;
    

    Und den Interwall des Timers setzt du mit: (200 ist die Zeit in Millisekunden)

    SetTimer(hwnd,ID_TIMER,200,TimerProc);
    

    Das Ganze mußt du dann nurnoch formgerecht einbauen.



  • Vielen Dank...das werde ich dann jetzt mal versuchen;-)



  • Sooo...jetzt doch noch ein paar Fragen zur Umsetzung^^:

    1. Die Zeile:

    SetTimer(hwnd,ID_TIMER,200,TimerProc);
    

    muss an welche Stelle gesetzt werden? In die Timer-Callback?

    2. String <-> Zahl

    Ich würde zunächst gerne einmal die Sekunden in einem Label ausgeben. Das Ganze wollte ich so machen:

    wsprintf(hText,TEXT("%i"),sekunde);
    SetWindowText (hText, sekunde);
    

    Sekunde ist vom Typ Integer. Der Compiler erwartet aber einen String. Wie wandle ich das um?



  • 1. SetTimer kann sehr gut bei der Initialisierung des Fensters, also bei WM_CREATE, stehen. Eine TimerProc ist optional, es kann auch NULL übergeben werden. Für deinen Fall reicht es vielleicht aus, auf die Nachricht WM_TIMER zu reagieren. SetTimer in der TimerProc würde natürlich keinen Sinn machen.

    Am Anfang von Seite 3 hast du geschrieben, dass du das Projekt auf Multiibyte umgestellt hast. Außerdem macht es keinen Sinn, Funktionen für WChars mit Funktionen und Makros für TCHARs zu mischen. Also am Besten TCHAR-Funktionen wie _tprintf verwenden. Alternativ ginge natürlich auch _itot.

    Edit : Für Integer nimm am Besten %d, also _tprintf(hText, TEXT("%d"), sekunde);

    Edit2 : Schau dir einmal die sichereren Funktionen wie StringCbPrintf aus <strsafe.h> an.



  • Muss ich für den Befehl _tprintf eine weitere header-Datei einbinden?

    Ich erhalte immer den Fehler "Bezeichner nicht gefunden"



  • Ich habe mich gerade selber vertan, sorry. Includier' am Besten <strsafe.h> und nutze StringCbPrintf. Oder eben die Funktionen, die dafür gedacht sind wie itoa bzw. _itot.

    Funktionen im Umgang mit TCHARs sind in <tchar.h> deklariert.
    Das TCHAR-Pendant zu sprintf heißt _stprintf, nicht wie von mir fälschlicherweise geschrieben _tprintf.



  • Das will bei mir nicht fuktionieren...Ich bin mir auch absolut nicht sicher, ob ich das überhaupt richtig angehe. Hier mal mein Quellcode in Auszügen:

    WinMain:

    int WINAPI WinMain(HINSTANCE hInstance,      // Handle der Programminstanz
                       HINSTANCE hPrevInstance,  // Handle der letzten Instanz
                       LPSTR lpCmdLine,          // Kommandozeile
                       int nCmdShow)             // Art wie das Fenster angezeigt werden soll
    {
        MSG msg;
    
    	hWnd = ErstelleHauptfenster(hInstance);
    
        if(0 == hWnd)
        {
            MessageBox(0, "Fenster konnte nicht erzeugt werden", "Fehler", MB_OK);
            return 0;
        }
    
    	ErstelleSteuerelemente (hWnd, hInstance);
    
        while(GetMessage(&msg, NULL, 0, 0))
    	{
            // Nachricht an die Callbackfunktion senden
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    
        return 0;
    }
    

    Die Funktion "ErstelleHauptfenster":

    HWND ErstelleHauptfenster(HINSTANCE hInstance)
    {
        WNDCLASSEX wndClass =
        {
            sizeof(WNDCLASSEX),                                 // Groesse angeben
            CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW,    // Standardstile
            MessageHandler,                                     // Callback-Funktion
            0,                                                  // Zusaetzliche Angaben
            0,                                                  // nicht benoetigt
            hInstance,                                          // Anwendungsinstanz
            LoadIcon(NULL, IDI_WINLOGO),                        // Windows-Logo
            LoadCursor(NULL, IDC_ARROW),                        // Normaler Cursor
            (HBRUSH)COLOR_BACKGROUND+1,                         // Weisser Pinsel
            NULL,                                               // kein Menue
            "WindowClass",                                      // Der Name der Klasse
            LoadIcon(NULL, IDI_WINLOGO)                         // Windows Logo
        };
    
    	SetTimer(hwnd,ID_TIMER,1,TimerProc);
    
        RegisterClassEx(&wndClass);
    
        return CreateWindowEx(NULL,                   // Keine erweiterten Stile nutzen
                              "WindowClass",          // Klassenname
                              "Stopuhr",              // Fenstertitel
                              WS_OVERLAPPEDWINDOW |	  // Fenster
                              WS_VISIBLE,             // Eigenschaften
                              800, 500, 400, 300,     // Anfangsposition und Groesse
                              NULL,                   // Handle des Elternfensters
                              NULL,                   // Handle des Menues
                              hInstance,              // Anwendungsinstanz
                              NULL);                  // wird nicht benoetigt
    }
    

    Die Funktion "ErstelleSteuerelemente":

    void ErstelleSteuerelemente (HWND hWnd, HINSTANCE hInst)
    {
      // Statischen Text als Child-Fenster erstellen
    
      hText = CreateWindow ("STATIC",
                            "Stopuhr",
                            WS_VISIBLE | WS_CHILD | ES_CENTER,
                            0, 0,
                            300, 20,
                            hWnd,
                            (HMENU)ID_STATICTEXT,
                            hInst,
                            NULL);
    }
    

    In der Standardnachrichtenbehandlung habe ich noch zusätzlich stehen:

    case WM_TIMER:
    return 0;
    break;
    

    Und zu guter letzt die TimerProc:

    VOID CALLBACK TimerProc (HWND hwnd, UINT message, UINT iTimerID, DWORD dwTime)
    {
    	SYSTEMTIME st;
    	TCHAR      sz[128]={0}; 
    
    	GetLocalTime(&st);
    	GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, sz, (sizeof(sz) / sizeof(sz[0]))); 
    
    	int stunde, minute, sekunde;
    	int nCnt = sscanf(sz, "%d:%d:%d",&stunde, &minute, &sekunde);
    	char buffer[20];
    
        wsprintf(hText,TEXT("%d"),itoa(sekunde,buffer,10));
        SetWindowText (hText, buffer);
    }
    

    Was soll geschehen? Es sollen einfach nur die Sekunden der Systemzeit, die in die Integervariable "Sekunde" geschrieben werden, in dem Label, was ich unter "ErstelleSteuerelemente" erstellt habe, angezeigt werden.



  • Entweder du setzt die TimerProc an den Anfang des Codes, oder du setzt an den Anfang des Codes noch den Prototypen.

    VOID CALLBACK TimerProc (HWND hwnd, UINT message, UINT iTimerID, DWORD dwTime);
    

    Du kannst aber auch den TimerProc weglassen, dann schreibst du:

    SetTimer(hwnd,ID_TIMER,1,NULL);
    

    und fügst dann deinen:

    SYSTEMTIME st;
        TCHAR      sz[128]={0}; 
    
        GetLocalTime(&st);
        GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, sz, (sizeof(sz) / sizeof(sz[0]))); 
    
        int stunde, minute, sekunde;
        int nCnt = sscanf(sz, "%d:%d:%d",&stunde, &minute, &sekunde);
        char buffer[20];
    
        wsprintf(hText,TEXT("%d"),itoa(sekunde,buffer,10));
        SetWindowText (hText, buffer);
    

    unter:

    case WM_TIMER:
    // Hier dein Zeitermittlungscode
    return 0;
    

    ein.



  • Und statt hwnd in SetTimer und TimerProc mußt du natürlich die hwnd deiner Hauptanwendung eintragen.



  • Danke für die Verbesserungsvorschläge, aber ich erhalte nach wie vor die Meldung:

    "error C2664: 'wsprintfA': Konvertierung des Parameters 1 von 'HWND' in 'LPSTR' nicht möglich"

    wsprintf(hText,TEXT("%d"),itoa(sekunde,buffer,10));
    SetWindowText (hText, buffer);
    

    Das sagt mir, dass irgendwas mit den Datentypen nicht simmt...aber ich weiß einfach nicht, was ich machen soll...



  • Logsich, hText ist nen Fensterhandle.

    wsprintf(hText,TEXT("%d"),itoa(sekunde,buffer,10));
    SetWindowText (hText, buffer);
    

    ist falsch.

    Mach mal das:

    wsprintf(buffer,TEXT("%d"),sekunde);
    SetWindowText (hText, buffer);
    


  • Definier Buffer auch als

    TCHAR buffer[20];
    

    Die Umwandlung kann dann entweder so

    _stprintf(buffer,TEXT("%d"),sekunde);
    

    oder mit <strsafe.h>

    StringCbPrintf(buffer,128,TEXT("%d"),sekunde);
    

    oder einfach mit

    _itot(sekunde,buffer,10);
    

    vonstatten gehen.
    hText ist ein Handle auf dein Control. Dieses wird jetzt erst beim Setzen des Textes verwendet:

    SetWindowText (hText, buffer);
    

    Dein Aufruf von SetTimer findet _vor_ dem Erstellen des Fensters statt. Es ist nicht ersichtlich, aber ich denke, dass hwnd eine globale Variable ist, die irgendwann in der WndProc gesetzt wird.
    Mach so etwas nicht!
    Erstens ist ein Name wie hwnd denkbar schlecht für eine globale Variable, zweitens sind globale Variablen normalerweise total überflüssig.

    Der Aufruf von SetTimer sollte, wie geschrieben, bei WM_CREATE in deiner Fensterprozedur geschehen.



  • Coole Sache...jetzt geht es...Vielen Dank, dass du es nach den vielen Anfängerfragen und -fehler mit mir ausgehalten hast...

    ich freue mich^^


Anmelden zum Antworten