22
Peter Sobe 1 Exkurs: Win32-Fenster-Programmierung Fensterbasierte Anwendungen können durch Benutzung der Win32-Anwendungsschnittstelle (API) realisiert werden. Win32: durch Auswahl Projekttyp „Win32“ innerhalb Visual Studio wird beim Erstellen ein Codegerüst für eine Fensteranwendung mit minimaler Grundfunktionalität erstellt. Hauptfenster – zum Aufnehmen von Text und Grafik Menu – mit Standardeinträgen “Datei/Beenden“ und “Hilfe/Info…“

Peter Sobe 1 - HTW Dresdensobe/Info2_Jg16/Vo/5a... · 2017. 6. 21. · Peter Sobe 1 Exkurs: Win32-Fenster-Programmierung Fensterbasierte Anwendungen können durch Benutzung der Win32-Anwendungsschnittstelle

  • Upload
    others

  • View
    4

  • Download
    0

Embed Size (px)

Citation preview

  • Peter Sobe 1

    Exkurs: Win32-Fenster-Programmierung

    Fensterbasierte Anwendungen können durch Benutzung der Win32-Anwendungsschnittstelle (API) realisiert werden.

    Win32: durch Auswahl Projekttyp „Win32“ innerhalb Visual Studio wird beim Erstellen ein Codegerüst für eine Fensteranwendung mit minimaler Grundfunktionalität erstellt.

    Hauptfenster – zum Aufnehmen von Text und Grafik

    Menu – mit Standardeinträgen “Datei/Beenden“ und “Hilfe/Info…“

  • 2

    Die Windows-API (Win32)

    Die Windows-API fasst eine große Anzahl von Windows-funktionen in einer Schnittstelle zusammen

    • die erste Windows-API basierte noch auf einer reinen C-Programmierung und bot nur reine C-Funktionen an

    • später wurde eine objektorientierte Schicht darüber gesetzt - die Microsoft Foundation Classes MFC (C++)

    - Es gibt auch noch weitere objektorientierte Windows/GUI-Programmierschnittstellen (z.B. WxWin/WxWidgets, oder Qt)

    R. Grossmann / P.Sobe

  • 3

    allgemeine Architektur einer Windowsanwendung

    • Anstelle des main() gibt es eine Funktion WinMain(). Diese Funktion wird nach dem Start der Anwendung aufgerufen.

    • In WinMain() wird in der Regel das erste Fenster oder eine andere Dialogform generiert.• Die allgemeine Anwendungsfensterklasse wird zusammen mit einer

    sogenannten CALLBACK-Routine bei Windows registriert (bekannt gemacht in der windowsinternen Verwaltung)

    • Nach dem Definieren der Fensterparameter wird das Fenster sichtbar gemacht

    • abschließend wird eine Schleife zur Abfrage und Verarbeitung von Windows-Nachrichten gestartet, welche erst bei einem angeforderten Beenden der Applikation verlassen wird

    • Windows ruft von sich aus die CALLBACK-Routine auf, falls für das zugehörige Fenster Nachrichten vorliegen

    • Unter Fenster sind auch alle Bedienelemente wie Tasten, Eingabefelder und Boxen zu verstehen, welche hierarchisch verknüpft sind.

    R. Grossmann / P.Sobe

  • 4

    Das Nachrichtensystem von WINDOWS

    Hardware ( Bildschirm, Tastatur, Maus, Massenspeicher, Drucker, ...)

    Start

    Windows-Betriebssystem

    Windows-Applikation

    WinMain ( )Fenstererzeugung/Registrierungwhile (getmessage)

    { dispatchmessage }

    Nachrichten-warteschlange

    Hardwareereignis (z.B. Mausklick)

    Kodierung und Ablage als Nachricht

    Fenster mit Callbackfunc.WndProc zur Reaktion auf Ereignisse

    Fensterverwaltung(Sichtbarkeit / Ereigniszuordn.)

    2.3.

    0.

    1.

  • 5

    Die WinMain-Funktion

    Funktionskopf der WinMain-Funktion:

    int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);

    Erläuterungen: HINSTANCE- Handle auf Anwendungsinstanz - ermöglicht dem System

    die eindeutige Zuordnung einer gestarteten Anwendung

    PrevInstance- Handle der vorherigen Instanz, bedeutungslos ab WIN32 (immer NULL)

    LPSTR lpCmdLine- Komandozeile (Zeichenkette) (entspricht: char*)

    nCmdShow- legt fest wie die Anwendung gestartet wird (maximiert, minimiert etc.)

    R. Grossmann / P.Sobe

  • 6

    Die Nachrichtenschleife von WinMain

    Windows setzt jede Aktion des Benutzers in eine Nachricht um und speichert diese in einer Nachrichtenwarteschlange

    Jede Anwendung muss diese Nachrichtenwarteschlange zyklisch abfragen.

    while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); // Umsetzen von TastatureingabenDispatchMessage(&msg); // Verteilung an die Fenster

    }

    R. Grossmann / P.Sobe

  • 7

    Die Callback-Fensterprozedur

    • Windows ermittelt für jede Nachricht den zugehörigen Empfänger in Abhängigkeit von der Sichtbarkeit

    • Für das betroffene Fenster (auch eine Taste oder Eingabeelement) wird die WndProc()-Funktion aufgerufen (Callback-Funktion, die über einen Funktionszeiger angemeldet wurde)

    LRESULT CALLBACK WndProc(HWND hWnd, UINT uiMessage, WPARAM wParam, LPARAM lParam)

    Erläuterung: hWnd- Fensterhandle des entsprechenden Fensters (= FensterID)

    uiMessage- Nachrichtenkonstante in der Form WM_x (WM: Window Message)

    -> ganze Zahl / vordefinierte Konstanten in Windows

    wParam- 1. Parameter (Bedeutung abhängig vom uiMessage-Wert)

    lParam - 2. Parameter (beide Parameter sind 32bit integer)

    LRESULT – 32bit ganzzahliger Rückgabewert (normalerweise 0)R. Grossmann / P.Sobe

  • 8

    Die Bearbeitung von Windows-Nachrichten Für jedes Fenster wird eine Fensterfunktion angegeben, die die einzelnen an das Fenster gerichteten Nachrichten verarbeitet. Das erfolgt meist mit einer CASE-Selektion.

    LRESULT CALLBACK WndProc(HWND hWnd, UINT uiMessage, WPARAM wParam, LPARAM lParam)

    { switch (uiMessage) { case WM_CLOSE: DestroyWindow(hWnd); return 0;case WM_DESTROY: PostQuitMessage(0); return 0; default: break;

    } return DefWindowProc(hWnd, uiMessage, wParam, lParam);

    }

    Falls ein Nachrichtentyp nicht bearbeitet wird, erfolgt mit DefWindowProceine Übergabe zur Standardbearbeitung an Windows. Die dargestellte case-Mehrfachselektion kann als Vorlage für das Schließen und Beenden einer Windows-Anwendung übernommen werden.

  • 9

    Vordefinierte Fensterklassen • Auf der graphischen Oberfläche können beliebig konfigurierte Fenster

    platziert werden. Jedes Dialogfeld, jedes Eingabefeld, jede Schaltfläche und auch jedes Textfeld ist ein Fenster.

    • Jedes Fenster besitzt eine Fensterklasse, welche in einer Struktur die grundsätzlichen Einstellungen des Fenster speichert. Sie enthält u.a. einen eindeutigen Namen, Informationen über Hintergrundfarbe, Menü, Verhalten beim Ändern der Größe etc. Anhand des Namens können beliebig viele Fenster ein und derselben Fensterklasse erstellt werden.

    • Die Windows-API stellt einige vordefinierte Fensterklassen bereit, die wichtigsten davon sind:

    edit Eingabefeld button Schaltfläche (auch Radio-feld)static für Textfeldercombobox Auswahlbox (z.B. bei Auswahl von Schriftarten) listbox Listenfeld

    R. Grossmann / P.Sobe

  • 10

    Eintragungen in der Fensterklassen-Struktur

    Bekanntmachen der Fensterklasse im Hauptprogramm:

    WNDCLASS wndclass;wndclass.style = CS_HREDRAW | CS_VREDRAW ;wndclass.lpfnWndProc = WndProc;wndclass.cbClsExtra = 0;wndclass.cbWndExtra = 0;wndclass.hInstance = fenst;wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);wndclass.hCursor = LoadCursor(NULL, IDC_CROSS);wndclass.hbrBackground= (HBRUSH)

    GetStockObject(LTGRAY_BRUSH);wndclass.lpszMenuName = NULL;wndclass.lpszClassName= szAppName;RegisterClassEx(&wndclass);

    R. Grossmann / P.Sobe

  • 11

    Erzeugen eines Fensters f= CreateWindow(szAppName, //Name der Fensterklasse

    "Fenster mit Sinus-Kurve", //FenstertitelWS_OVERLAPPEDWINDOW | //FensterstilWS_VISIBLE,100, //x-Wert linke obere Ecke200, //y-Wert linke obere Ecke300, //Fensterbreite300, //FensterhöheNULL, //VaterfensterNULL, //Menüfenst, //ProgrammzählerNULL); //zusätzliche Parameter

    // Display the window to the userShowWindow(f, SW_SHOWNORMAL);UpdateWindow(f);

    R. Grossmann / P.Sobe

  • 12

    Mausnachrichten

    Alle Mausbewegungen werden als Nachrichten kodiert:

    • WM_MOUSEMOVE- Maus wird bewegtWM_LBUTTONDOWN- Linke Maustaste wird gedrücktWM_LBUTTONUP- Linke Maustaste wird losgelassenWM_RBUTTONDOWN- Rechte Maustaste wird gedrücktWM_RBUTTONUP- Rechte Maustaste wird losgelassenWM_MBUTTONDOWN- Mittlere Maustaste wird gedrücktWM_MBUTTONUP- Mittlere Maustaste wird losgelassen

    • Die Nachrichtenparameter enthalten die Koordinaten und weitere Infos.signed int xPos = LOWORD(lParam); //X-Koordinate signed int yPos = HIWORD(lParam); //Y-Koordinate

    • Die Koordinaten sind relativ zum Fensterursprung (linke obere Ecke).

    • Der Parameter 'wParam' besteht aus einer Kombination von Konstanten, die jeweils angeben ob eine weitere Taste gedrückt ist oder nicht.

    R. Grossmann / P. Sobe

  • 13

    MessageBox-FunktionDie Funktion MessageBox hat vier Parameter. Als Rückkehrwert wird der int Wert der Taste gesendet, die gedrückt wurde. Die Tastencodes sind definiert über IDOK , IDYES, IDNO, IDCANCEL usw.

    Beispiel:if (MessageBox(hwnd,"Fenster schliessen","Nachricht",

    MB_YESNOCANCEL|MB_DEFBUTTON2|MB_ICONQUESTION)==IDYES) { … }

    Der 1.Parameter ist ein Fensterhandle (zu welchem Fenster gehört die MB). Der 2.Parameter stellt den Text der MB dar. Der 3.Parameter stellt den MB-Titel dar. Der 4.Parameter enthält die Buttons (max. drei möglich), den Button, der den Fokus erhält und ggf. Symbole zur Darstellung.Konstanten: MB_OK, MB_YESNO,MB_YESNOCANCEL,MB_IGNORERETRY

    Fokus: MB_DEFBUTTONi i=1,2,3 (Button i erhält Fokus)

    Symbol: MB_ICONQUESTION, MB_ICONINFORMATION, MB_ICONEXCLAMATION, MB_ICONHAND

  • 14

    Das Graphic Device Interface (GDI)

    Zum Ausgeben von Text und dem Zeichnen grafischer Elemente steht eine relativ leistungsfähige Bibliothek bereit – das Graphic Device Interface (GDI).

    • Die GDI ist hardwareunabhängig. Ein Kreis wird sowohl auf dem Bildschirm als auch auf dem Drucker mit gleichen Befehlen gezeichnet. Die Unterscheidung erfolgt durch dem sogenannten Gerätekontext (Device Context – definiert in Datenstruktur HDC -Handle to Device Context) .

    • Der Device Context muss vor dem Zeichen erzeugt und nach dem Zeichnenwieder freigeben werden (häufiger Fehler mit Ressourcenverbrauch):

    HDC hDC = GetDC(hWnd); // Erzeugung des Device Context/* --- Zeichenoperationen --- ... */ReleaseDC(hDC); // Freigabe des Device ContexthDC = NULL;

    R. Grossmann / P. Sobe

  • 15

    Die Zeichenfunktionen der GDI

    Die Grundfunktionen für das Zeichnen von Grafik und Text unter Windows sind:

    • Rectangle(hDC, Left, Top, Right, Bottom) - zeichnet ein Rechteck in dem angegebenen Rechteck

    • Ellipse(hDC, Left, Top, Right, Bottom) - zeichnet eine Ellipse in dem angegebenen Rechteck

    • MoveToEx(hDC, X, Y, &pt) - setzt die Zeichenposition und speichert die alte in 'pt'

    • LineTo(hDC, X, Y) - malt eine Linie von der aktuellen Zeichenposition zu dem angegebenen Punkt

    • TextOut(hDC,X,Y,"text",count) - zeichnet einen Text auf den DC

    • Polyline(hDC, Point, Anzahl) - Polygonzug, Point ist ein Punkt-Vektor, der die x-y-Koordinaten der Punkte des Polygons enthält; Anzahl gibt die Anzahl der Punkte im Vektor an

    R. Grossmann / P. Sobe

  • 16

    Farben und Muster bei Zeichenfunktionen • Die Zeichenfunktionen enthalten keine Parameter für Farbe und Stil.

    • Aus Effizienzgründen sind diese Parameter global einzustellen.

    • Die Füllfarbe wird definiert mit einem Pinsel (Brush)

    HBRUSH hBrush = CreateSolidBrush(RGB(0,255,0));// oder einer Farbkonstanten

    • Die Linieneigenschaften werden definiert mit einem Stift (Pen)

    HPEN hPen = CreatePen(Style, Width, cl);mit Style = PS_SOLID oder PS_DASH oder PS_DOT oder Kombinationen

    • Sowohl Pinsel wie Stift müssen dem GDC bekannt gemacht werden und sollten nach Gebrauch wieder auf den alten Wert rückgesetzt werden:HBRUSH hOldBrush = (HBRUSH)SelectObject(hDC, hBrush );/* --- Zeichenoperationen --- ... */ DeleteObject(SelectObject(hDC, hOldBrush)); hBrush = NULL;

  • Peter Sobe 17

    Win32-Beispiel (1)

    Win32 – Programmskelett, von Visual Studio automatisch erzeugt:#include "resource.h"…int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

    LPTSTR lpCmdLine, int nCmdShow){

    UNREFERENCED_PARAMETER(hPrevInstance);UNREFERENCED_PARAMETER(lpCmdLine);MSG msg;HACCEL hAccelTable;LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);LoadString(hInstance, IDC_GRAFIK, szWindowClass, MAX_LOADSTRING);MyRegisterClass(hInstance); // hier wird das Hauptfenster angelegt und

    // die WndProc()-Funktion angegeben

    // Anwendungsinitialisierung ausführen:if (!InitInstance (hInstance, nCmdShow) ) // hier wird CreateWindow ausgerufenreturn FALSE;

  • Peter Sobe 18

    Win32-Beispiel (2)

    Win32 – Fortsetzung Programmskelett:

    // Hauptnachrichtenschleife: while (GetMessage(&msg, NULL, 0, 0)){if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)){ TranslateMessage(&msg);

    DispatchMessage(&msg);}

    }return (int) msg.wParam;

    }

    Durch GetMessage(), TranslateMessage() und DispatchMessage() werden Ereignisse (z.B. Auswahl eines Menüpunkts, Mausklick in einen Fensterbereich) verarbeitet und an die Fensterfunktionen WNDProcweitergereicht. Für jedes Fenster kann eine solche Funktion programmiert werden, die dann anwendungsspezifische Aktionen umsetzt.

  • Peter Sobe 19

    Win32-Beispiel (3)

    Win32 – Fortsetzung Programmskelett:

    ATOM MyRegisterClass(HINSTANCE hInstance){

    WNDCLASSEX wcex;wcex.cbSize = sizeof(WNDCLASSEX);wcex.style = CS_HREDRAW | CS_VREDRAW;wcex.lpfnWndProc = WndProc; // hier wird Fensterfunktion angegeben wcex.cbClsExtra = 0;wcex.cbWndExtra = 0;wcex.hInstance = hInstance;wcex.hIcon = LoadIcon(hInstance, ….wcex.hCursor = LoadCursor(NULL, IDC_ARROW);wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);wcex.lpszMenuName = MAKEINTRESOURCE(IDC_WIN32_WIZARD);wcex.lpszClassName = szWindowClass;wcex.hIconSm = LoadIcon(wcex.hInstance, …return RegisterClassEx(&wcex);

    }

  • Peter Sobe 20

    Win32-Beispiel (4)

    Win32 – Fortsetzung Programmskelett:

    BOOL InitInstance(HINSTANCE hInstance, int nCmdShow){

    HWND hWnd;hInst = hInstance; // Instanzenhandle in der globalen Variablen speichern

    hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

    if (!hWnd)return FALSE;

    ShowWindow(hWnd, nCmdShow);UpdateWindow(hWnd);

    return TRUE;}

  • Peter Sobe 21

    Win32-Beispiel (5)

    Win32 – Fortsetzung Programmskelett:

    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

    { int wmId, wmEvent;PAINTSTRUCT ps; HDC hdc;switch (message){case WM_COMMAND: // typisch für Menüauswahl-Ereignisse

    wmId = LOWORD(wParam);wmEvent = HIWORD(wParam);switch (wmId) // Menüauswahl bearbeiten:{ case IDM_ABOUT: DialogBox(hInst, …); break;case IDM_EXIT: DestroyWindow(hWnd); break;default:

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

    break;…

  • Peter Sobe 22

    Win32-Beispiel (6)

    Win32 – Fortsetzung Programmskelett:

    …case WM_PAINT: // ausgelöstes Ereignis, wenn Fenster erscheint

    hdc = BeginPaint(hWnd, &ps);// Hier den Zeichnungscode hinzufügen.EndPaint(hWnd, &ps);break;

    case WM_DESTROY:PostQuitMessage(0);break;

    default:return DefWindowProc(hWnd, message, wParam, lParam);

    } // end switch message

    return 0;}