Win32-Programmierung mit VC++ und der Win-Api

2.2 - Timer und Eingabefelder

Jetzt kommt ein tolles Thema: Timer und Eingabefelder. Unter Eingabefeldern kann sich sicherlich jeder etwas vorstellen:

Bei Timern siehts da schon etwas schlechter aus. Ich machs mal so: erstmal programmieren, dann sehen und staunen, dann hoffentlich verstehen!

Nun erweitern wir unseren Dialog um ein paar Buttons:

Wie zu erkennen wurden die Buttons Start und Stop hinzugefügt. Das ganze in einem grafisch ansprechenden Steuerelement namens Gruppierfunktion. Die ist aber nur da, damit es hübsch aussieht.

Wir geben unseren beiden Buttons folgende ID’s: - Start - IDC_AUTO - Stop - IDC_STOP

Das wars wieder mit unserem Ressourceneditor, jetzt gehts wieder zum Quellcode.

Wir erweitern unser Programm um folgende Variablendefinition:

#include "resource.h"
#define INCTIMERID1 1
int progress=50;

Des Weiteren fügen wir unserem Quellcode noch folgende Funktion hinzu:

void Init ...

void CALLBACK IncTimer1 (HWND hwnd, UINT iMsg, UINT iTimer, DWORD dwTime)
{
    progress++;

    if(progress < 100)
    {
        Init(hwnd);
    }

    if(progress > =100)
    {
        progress=0;
        Init(hwnd);
    }
}

LRESULT CALLBACK WindProc ...

Jetzt fehlen nur noch die üblichen case-Abfragen:

...
case IDC_AUTO:
{
    SetTimer(hwnd, INCTIMERID1, 50, (TIMERPROC) IncTimer1);
}
break;

case IDC_STOP:
    KillTimer(hwnd, INCTIMERID1);
    break;
...

Und schon kanns losgehen! Komilieren und antesten!

Erklärung:

Die neue Variable “INCTIMERID1 1” beschreibt dem Compiler und uns ein HANDLE zu unserem Timer. Die Zahl dahinter freut sich nur, dass sie dasteht. Die neue Funktion

void CALLBACK IncTimer1 (...)

wird aufgerufen, sobald der Button mit dem Handle IDC_AUTO, also Start, gedrückt wurde. Denn in diesem Anweisungsblock steht geschrieben, dass wenn eben der Knopf gedrückt wurde, der Timer1 gestartet werden soll:

SetTimer(hwnd, INCTIMERID1, 50, (TIMERPROC) IncTimer1);

SetTimer ruft also die Funktion IncTimer1 mit dem Handle INCTIMERID1 alle 50 Millisekunden auf! Und staun', schon glauben wir zu wissen, was ein Timer macht: Er ruft Funktionen in einem (vorerst) festgelegten Intervall auf. Vorerst deshalb, weil wir die Geschwindigkeit oder Häufigkeit der Aufrufe während des laufenden Programmes ändern werden!

Was passiert denn nun, wenn der Button Stop gedrückt wurde? Na dann wird der Timer gekillt, egal ob zuvor angestellt oder nicht. Das wäre so, als wenn man über ‘nen Plattgefahrenen Igel nochmals drüberfahren würde - toter gehts nicht!

Wer will kann jetzt schon einmal kompilieren und unser Proggi antesten. Wenn’s aus irgendwelchen Gründen nicht funzt, hier gibts das Teil wieder als kompletten VC++ Workspace: timer.zip 46,7 KB

Nun gings aber in diesem Kapitel auch um Eingabefelder. Also werden wir uns ein Eingabefeld mal in unseren Dialog einfügen. Also wieder ab in den Ressourceneditor:

Nun wurden 2 Textelemente und 1 Eingabefeld unserem Dialog hinzugefügt. Bitte beachtet auch wieder die ID unseres Eingabefeldes!

Nun gehts wieder zum Quellcode. Jetzt habe ich mir folgendes vorgestellt: Beim Starten des Timers (drücken von Start) wird der Wert der sich im Eingabefeld befindet in eine Variable ausgelesen. Diese Variable bestimmt dann die Geschwindigkeit, wie schnell der Balken von 0 auf 100 inkrementiert.

Hört sich leicht an, ist es auch - wenn man weiß wie! Also ran an den Code und folgendes verändern: Eine Variable Zeit definieren:

...
int progress=50;
int zeit;
...

Diese Variable enthält den eingelesenen Speed-Wert.

Nun SetTimer-Funktion verändern - nicht neuschreiben!

...
SetTimer(hwnd, INCTIMERID1, zeit, (TIMERPROC) IncTimer1);
...

Und nun noch das ganze in die Abfrage einbauen:

...
case IDC_AUTO:
{
    BOOL bSuccess;
    zeit = GetDlgItemInt(hwnd, IDC_ZEIT, &bSuccess, FALSE);
    SetTimer(hwnd, INCTIMERID1, zeit, (TIMERPROC) IncTimer1);
}
break;
...

Erklärung: Zuerst eine Bool-Variable erzeugt.

zeit = GetDlgItemInt(hwnd, "Eingabefeld-ID", "Erfolg=TRUE oder FEHLER=FALSE", "Vorzeichenbehaftetes Integer?");

Die Bool Variable ist halt nur zur Kontrolle und späteren Verewndung, falls es Fehler beim auslesen gab oder nicht. Das ist ein Rückgabewert der Funktion.

Erklärungen zu GetDlgItemInt gibts wie immer auf der Homepage von MSDN GetDlgItemInt

Das wars wieder! Kompilieren und antesten! Falls es doch nicht funzen sollte - hier ist die Lösung: eingabefeld.zip 47 KB