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

2.1 - Fortschrittsbalken

Die Lösung (CodeSnippet) der letzten Übung gibts hier:

//Abfragen zum im Hauptfenster befindlichen Knöpfe + Buttons etc. ...
LRESULT CALLBACK WindProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        case WM_CREATE:
            //Hier den Code rein, wenns beim aufrufen sein soll
            MessageBox(hwnd, "Ich bin eine wichtige Meldung!!!", "Wichtig!", MB_ICONINFORMATION);
        break;

        case WM_DESTROY:
        {
            //Hier den Code rein, wenns beim beenden sein soll
            MessageBox(hwnd, "Ich bin eine wichtige Meldung!!!", "Wichtig!", MB_ICONINFORMATION);
            PostQuitMessage(0);
        }
        break;

        case WM_COMMAND:
        {
            switch( LOWORD( wParam ) )
            {
                case IDC_INIT:
                {
                    Init(hwnd);
                }
                break;

                case IDC_MELDEN:
                {
                    MessageBox(hwnd, "Ich bin eine wichtige Meldung!!!", "Wichtig!",
                    MB_ICONINFORMATION);
                }
                break;
            }
        }
        return 0 ;
    }

    return DefWindowProc (hwnd, message, wParam, lParam) ;
}

Wie zu erkennen ist, war das gar nicht so schwer! Das einzige was zu beachten ist, dass beim beenden der Anwendung zuerst die MessageBox aufgerufen wird und dann PostQuitMessage gesendet wird:

case WM_DESTROY:
{
    MessageBox(hwnd, "Ich bin eine wichtige Meldung!!!", "Wichtig!", MB_ICONINFORMATION);
    PostQuitMessage(0);
}
break;

Jetzt gehts aber weiter!

Macht mal zuerst alle Änderungen, welche in der Übung/Hausaufgabe gemacht wurden wieder rückgängig. Oder Ihr könnt auch gleich mein Win32-Konstrukt herunterladen.

Jetzt wollen wir noch einen Fortschrittsbalken in unser Programm einfügen. Dazu öffnen wir wieder unseren Dialog in der Ressourcenübersicht und fügen eine Fortschrittsanzeige ein. Wir editieren die Eigenschaften so, dass die ID “IDC_PROGRESS” heißt und der Balken horizontal verläuft und keine Ränder hat. Des weiteren ändern Wir unseren Dialog so ab, dass er folgendermaßen ausieht:

Wir sehen also 3 Buttons mit der jeweiligen Beschriftung und einen Fortschrittsbalken, den ich aufgrund der langen Schreibweise jetzt ProgressBar nenne.

Den Knöpfen geben wir folgende ID’s (HANDLES): - Beenden IDC_BEENDEN - Zurück IDC_ZURUECK - Weiter IDC_WEITER

Was gemerkt? In den Handlenamen dürfen keine Umlaute vorkommen (ä, ö, ü, -, usw.). Falls es doch mal vorkommen sollte, warnt euch das Teil schon!

Soweit mit dem Ressourceneditor, jetzt gehts an den Quellcode. Ich habe folgendes vor: Beim starten des Programmes befindet sich der Balken bei 50%. Beim betätigen der Knöpfe Weiter oder Zurück ändert der Balken seine Fortschrittsanzeige. Beim drücken von Beenden wird halt das Programm beendet.

Wir müssen nun also erst einmal eine Variable hinzufügen, die dem Balken sagt, wie weit er jetzt laufen soll. Am besten wir nehmen einen Int-Wert und initialisieren ihn sofort mit dem Wert 50. Hier der Code-Ausschnitt:

...
#include "resource.h"

int progress=50;

LRESULT CALLBACK WindProc (HWND, UINT, WPARAM, LPARAM) ;
...

Nun müssen wir dem Balken sagen, es soll beim Programmstart sich auf 50% bewegen. Das machen wir so:

void Init ( HWND hwnd)
{
    SendMessage(GetDlgItem(hwnd,IDC_PROGRESS), PBM_SETPOS,(WPARAM)progress,0);
}

Wie Ihr seht, habe ich den Befehl SendMessage(…) in die Funktion Init(…) reingeschrieben. Aus der letzten Übung wissen wir aber auch, dass es auch so geht:

switch (message)
{
    case WM_CREATE:
        SendMessage(GetDlgItem(hwnd,IDC_PROGRESS), PBM_SETPOS,(WPARAM)progress,0);
    break;
    ...

Nun stellt euch mal vor, unser Programm gewinnt an Funktionsvielfalt und Umfang. Nun echt jede Variable in WM_CREATE reinzuschreiben wäre zuviel des Guten und würde ausserdem der Übersicht schaden. Ausserdem kann ich mit meiner Lösung stets den Balken zurücksetzen, indem ich halt nur die Funktion Init(…) aufrufe. Zur Probe können wir nun einen Test starten. Kompiliert mal euer Programm. Es sollte so aussehen:

Nun hat das ganze ja keinen Sinn, wenn wir den Balken nicht verändern könnten. Deshalb müssen wir jetzt den Buttons Zurück und Weiter Leben einhauchen. Wir verändern wieder unseren Code und fügen zum Beispiel unter IDC_INIT die Abfragen für unsere beiden Buttons hinzu:

...
case WM_COMMAND:
{
    switch( LOWORD( wParam ) )
    {
        case IDC_INIT:
        {
            Init(hwnd);
        }
        break;

        case IDC_ZURUECK:
        {
            progress=progress-10;
            if(progress<0)
                progress=0;
            else
                Init(hwnd);
        }
        break;

        case IDC_WEITER:
        {
            progress=progress+10;
            if(progress>100)
                progress=100;
            else
                Init(hwnd);
        }
        break;

        case IDC_BEENDEN:
            PostQuitMessage(0);
        break;
    }
    ...

Wichtig: Innerhalb WM_COMMAND’s werden unsere Ressourcen, welche wir unserem Dialog hinzugefügt haben, abgefragt. Also dürfte da nur etwas wie “case IDC_xxxx:” stehen! Die Anweisungen, die ausserhalb von WM_COMMAND liegen kümmern sich das Aussehen und Verhalten des Dialoges.

Der Code-Snippet sieht erstmal ein wenig viel aus, ich habe aber schon eine Begrenzung der Werte von progress von 0 bis 100 vorgenommen. Das ist zwar nicht unbedingt zwingend, kann aber nützlich sein, wenn die ProgressBar versucht eine -20 oder 130 darzustellen ;-). Fehler gibts zwar nicht, aber es scheint so zu sein, dass der Progress-Balken über die Begrenzungen hinausschießt. Jedenfalls ist das ganze ziemlich blöd wenn’s nicht abgefangen wird! Auch noch zu erkennen ist, dass ich eine Routine für unseren Beenden-Button eingebaut habe. Wie in WM_DESTROY schließt er die Anwendung. Probierts mal aus!