DB Lutz Ifer

Digital
Blacksmithing
Amboss
Lutz Ifer

Inhalt

Startseite
Downloads Quellcode Entwicklung WinApi-Tutorial Linkliste
Kontakt Impressum

lutzifer.freebasic.de

Softwareschmied Lutz Ifer

Ein WinApi-Tutorial für FreeBasic von Lutz Ifer

Inhalt

  • 1 Einleitung
    • 1.1 Was ist die WinApi?
    • 1.2 Erzeugen eines Fensters
  • 2 Zeichnen mit der WinApi
    • 2.1 Pixeloperationen
    • 2.2 Filled Shapes
    • 2.3 Textausgabe
    • 2.4 Bitmaps blitten
    • 2.5 Bitmaps laden
  • 3 Eingabe
    • 3.1 Tastatur
    • 3.2 Maus
  • 4 Childwindows
    • 4.1 Zweitfenster
    • 4.2 Childwindows
    • 4.3 Speicher reservieren
    • 4.4 Messages
    • 4.5 Buttons erstellen
    • 4.6 Auf Buttons reagieren

Dieses Tutorial ist weder fertig noch vollständig, und weit davon entfernt, wirklich hilfreich zu sein. Kapitel, die kursiv geschrieben sind, sind noch nicht fertig, ihr Sourcecode kann jedoch schon heruntergeladen werden.
Bei Fragen und Anregungen einfach das Forum http://forum.freebasic.de besuchen, oder eine E-Mail schreiben.

Mit Dank an Mecki (www.freebasic.de) für den Webspace und MisterD für das Syntax-Highlighting.

Diese Chm-Datei wurde von ytwinky mit Html-Workshop von Microsoft© erstellt.

Valid XHTML 1.0 Strict


Digital
Blacksmithing
Amboss
Lutz Ifer

Inhalt

Startseite
Downloads Quellcode Entwicklung WinApi-Tutorial Linkliste
Kontakt Impressum

lutzifer.freebasic.de

Softwareschmied Lutz Ifer

Kapitel 1.1: Was ist die WinApi?

Jeder, der schon etwas länger programmiert, hat schon einmal Sourcecode wiederverwendet, und gemerkt, dass es eigentlich nicht dumm ist, oft benutzte Teile in eine sub() oder function() zu packen, und bei Bedarf einfach "zusammenzustecken".

Dies ist auch die Idee hinter der WinAPI. API steht für "Application Programming Interface", und stellt als Schnittstelle zwischen Programm und Betriebssystem eine Reihe von oft genutzten Funktionen zur Verfügung.

Ein Beispiel: Ein Programm soll eine vom Benutzer auswählbare Datei in irgendeiner Art verarbeiten. Wie wählt der Benutzer die Datei aus? Mit dem in Windows allgegenwärtigen "Datei-Öffnen"-Dialog. Dieser Dialog ist eine function() in der WinApi, die wie eine ganz normale function() aufgerufen werden kann. Gäbe es sie nicht, müsste jeder Programmierer für jedes Programm einen eigenen "Datei-Öffnen"-Dialog programmieren.

Weitere Dinge, die man mit der WinAPI machen kann, sind unter Anderem Abfragen über die Mausposition, Tastatureingaben, Fensterverwaltung (und darum wird es hauptsächlich in diesem Tutorial gehen), Netzwerkunterstützung, oder einfache Dialogboxen, wie folgendes Beispiel demonstriert:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

''' Lutz Ifers WinAPI-Tutorial
''' LutzIfer.FreeBasic.de
'''
''' Kapitel 1.1 - "Was ist die WinAPI?"

option explicit
#include "windows.bi"

if MessageBox(0, "Kann man sich eigentlich mehr" + chr(13, 10) + "als zweimal"+_
    " halb totlachen?", "Ich hätt' da mal ne Frage...", MB_ICONQUESTION or _
    MB_YESNO) = IDYES then

    MessageBox(0, "Natürlich kann man." + chr(13, 10) + "Sofern man sich zwis"+_
        "chendrin erholt", "Ja", MB_ICONINFORMATION or MB_OK)
else
    MessageBox(0, "Nicht? Finde ich aber schon.", "Nein", MB_ICONEXCLAMATION _
    OR MB_OK)
end if

Die komplette Deklaration der Messagebox-Funktion lautet:

int MessageBox(hWnd as HWND, Text as STRING, Caption as STRING, uType as UINTEGER)

"hWnd" ist ein sogenanntes Handle zu einem Fenster, und gibt an, wem die Messagebox gehört. Was Handles genau sind, besprechen wir im zweiten Kapitel. Der Text der Messagebox darf auch Zeilenumbrüche (chr(13,10) bzw. \n) oder Tabstops (chr(7) bzw. \t) enthalten. Im uType können die Eigenschaften der Messagebox durch vordefinierte, kombinierbare Flags angegeben werden. Diese Flags beinhalten das Präfix "MB_" für "MessageBox". Mit ihnen lässt sich das angezeigte Symbol (Keins, Ausrufezeichen, Fragezeichen, Stop-Zeichen, Informations-Zeichen), die Buttons (Ja, Nein, OK, Abbrechen, Wiederholen, Ignorieren), den vorausgewählten Button, und den Einfluss des Buttons auf den Programmablauf (Unterbrechen des Programms, Unterbrechen aller Programme, usw.) auswählen.

Links:

  • Dieses Kapitel downloaden
  • MessageBox() in der MSDN


Digital
Blacksmithing
Amboss
Lutz Ifer

Inhalt

Startseite
Downloads Quellcode Entwicklung WinApi-Tutorial Linkliste
Kontakt Impressum

lutzifer.freebasic.de

Softwareschmied Lutz Ifer

Kapitel 1.2: Ein erstes Fenster

In der Programmiersprache C ist es nicht erlaubt, Code "einfach so" in den Hauptteil des Programmes zu schreiben, C fordert eine "main()"-Funktion. Die komplette Deklaration dieser Funktion lautet "int main (int argc, char **argv)", in FreeBasisch gesprochen also

declare function main(argc as integer, argv() as string) as integer

Auf diese Weise werden in C die Aufrufparameter übergeben, argc beinhaltet die Anzahl der Parameter, argv die Zeichenketten. FreeBasic ist in dieser Hinsicht deutlich einfacher. Wir benötigen keine main()-Funktion, und die Parameter sind bei uns in der Variable "Command$" bzw. mit Leerzeichen als Trennzeichen in "Command$()" gespeichert.

Windowsprogramme in C haben eine andere main()-Funktion. Ihre Deklaration lautet "int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)". In FreeBasisch:

declare function WinMain(hInstance as HINSTANCE, hPrevInstance as HINSTANCE,_
    szCmdLine as PSTR, iCmdShow as integer) as integer

"Winapi" ist eine sogenannte Aufrufkonvention, die uns nicht interessiern braucht, sie bedeutet letztlich nur, dass die WinMain()-Funktion anstatt der main()-Funktion als Hauptfunktion des Programmes dienen soll. Was sind jetzt das allerdings für Datentypen, "HINSTANCE" und "PSTR"? Das sind von Windows eingeführte Datentypen, in FreeBasic kennen wir das als "UDT" bzw. "User defined type". Die Art, die Namen für diese Datentypen auszuwählen nennt man "Ungarische Notation", das heißt: Die ersten Zeichen geben die Art des Datentyps an, der Rest ist Name. "p" steht für "Pointer", "Str" für "String" - "PSTR" ist also ein String Pointer. "h" steht für "Handle", wie erwähnt, eine Windowsinterne Identifikationsnummer(defacto: ein Pointer auf die Adresse im RAM, an der alle nötigen Informationen stehen - aber vorerst halte ich die einfache Erklärung für besser), eine Art Etikett, und werden von FreeBasic in der Regel als Integer umgesetzt.

Nun zur Bedeutung dieser Parameter: hInstance ist ein Handle auf die eigene Instanz, daher die von Windows vergebene Nummer für dieses Programm. Logischerweise enthält hPrevInstance ein Handle auf das aufrufende Programm. Die Aufrufparameter stehen in dem String, auf den szCmdLine verweist. iCmdShow steht für die Art, wie das Programm seine Fenster erzeugen soll: Maximiert, Minimiert oder Normal (In den Dateieigenschaften einer Verknüpfung zu einem Programmes kann man das im zweiten Reiter unter "Ausführen" einstellen).

Wie ist das jetzt in FB? FreeBasic benötigt wie erwähnt keine solche [win]main-Funktion, ob dies ein Vorteil ist, darüber könnte man sich streiten. Ein Nachteil davon allerdings ist, dass wir uns einige der Informationen selber besorgen müssen: hInstance bekommt man durch einen AUfruf von "GetModuleHandle(NULL)", und iCmdShow ersetzen wir ungefragt durch "SW_NORMAL" ("Callback" da wir die Funktion nur angeben, sie aber von Windows aufgerufen bzw. "zurückgerufen" wird).

1
2
3
4
5
6
7
8
9
10
11

''' Lutz Ifers WinAPI-Tutorial
''' LutzIfer.FreeBasic.de
'''
''' Kapitel 1.2 - "Erzeugen eines Fensters"

option explicit
#include "windows.bi"
const ProgrammName = "Erzeugen eines Fensters"

declare function Fenster(byval hWnd as HWND, byval message as UINTEGER,_
    byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT

Als erstes benötigen wir die Deklaration der Callback-Funktion unseres Fensters. Da Windows seine Fenster ereignisgesteuert organisiert, bekommt unser Fenster ständig Nachrichten zugeschickt, die es über Aktivitäten, zum Beispiel Bewegungen der Maus oder Eingaben auf der Tastatur informiert. Dies ist die Funktion, die diese Nachrichten verarbeiten wird.

13
14
15
16
17
18
19
20
21
22
23
24
25
26

dim as WNDCLASS	windowclass
with windowclass
    .style         =  CS_HREDRAW or CS_VREDRAW
    .lpfnWndProc   =  ProcPtr(Fenster)
    .cbClsExtra    =  0
    .cbWndExtra    =  0
    .hInstance     =  GetModuleHandle(NULL)
    .hCursor       =  LoadCursor(NULL, IDC_ARROW)
    .hIcon         =  LoadIcon(NULL, IDI_APPLICATION)
    .hbrBackground =  GetStockObject(WHITE_BRUSH)
    .lpszClassName =  StrPtr(ProgrammName)
    .lpszMenuName  =  NULL
end with
RegisterClass @windowclass

Für unser Fenster legen wir als erstes die sogenannte Fensterklasse fest. Sie enthält alle wichtigen Informationen über die Beschaffenheit des Fensters. lpfnWndProc verweist auf die Callback-Funktion, die wir vorher deklariert haben. Mit den beiden "Extra"-Einträge könnte man für alle gemeinsam oder jedes einzelne Fenster der Klasse zusätzlichen Speicher reservieren. Was es damit auf sich hat, werden wir in Kapitel 4.3, "Speicher reservieren" näher beleuchten. hInstance sagt Windows, zu welchem Programm die Fensterklasse gehört. hIcon und hCursor legen das Fenstericon (das links oben in der Titelzeile) und den Cursor fest. Hier legen wir im Moment das Standardicon und den Standardcursor fest. hbrBackground enthält einen sogenannten Brush (siehe Kapitel 2.2, "Filled Shapes"), grob gesprochen: Die Hintergrundfarbe des Fensters, bei der wir uns für weiß entscheiden. Bei lpszClassName legen wir den Namen unserer neuen Fensterklasse fest, in der Regel wird dies der Programmname sein. Da wir noch keine Menüleiste im Fenster haben wollen, wählen wir für lpszMenuName NULL. Der Style der Fensterklasse (nicht zu verwechseln mit dem Fensterstyle, mit dem wir uns später beschäftigen werden) legt fest, dass das Fenster bei horizontaler oder vertikaler Größenänderung neu gezeichnet werden soll. Weitere interessante Flags wären "CS_NOCLOSE" (deaktiviert den "x"-Button) oder "CS_DROPSHADOW" (Nur WinXP/Vista: Das Fenster wirft einen Schatten). Mit RegisterClass wird Windows von der neuen Klasse unterrichtet, der Rückgabewert, der hier ignoriert wird, enthält die Information, ob die Registrierung der Klasse erfolgreich war, oder nicht.

28
29
30
31
32
33
34

dim as HWND	MeinFenster = CreateWindow(_
    ProgrammName, "Titelzeile", WS_OVERLAPPEDWINDOW,_
    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,_
    NULL, NULL, GetModuleHandle(NULL), NULL)

ShowWindow   MeinFenster, SW_NORMAL
UpdateWindow MeinFenster

CreateWindow ist eine Funktion, die uns noch sehr häufig begegnen wird. Ihr Rückgabewert ist ein Handle auf das erstelle Fenster. Die Deklaration von CreateWindow lautet:

declare function CreateWindow(lpClassName as STRING, lpWindowName as STRING,_
    dwStyle as DWORD, x as INTEGER, y as INTEGER, nWidth as INTEGER,_
    nHeight as INTEGER, hWndParent as HWND, hMenu as HMENU,_
    hInstance as HINSTANCE, lpParam as LPVOID) as HWND

Klassenname und Fenstername sind soweit selbsterklärend (Der Vollständigkeithalber soll erwähnt sein, dass statt des Klassennamens auch ein Pointer auf die Klasse selbst übergeben werden könnte). Wenn wir für die Position (x, y) und die Größe (nWidth, nHeight) keine speziellen Wünsche haben, verwenden wir CW_USEDEFAULT. Da unser Fenster kein Parentfenster hat, übergeben wir NULL für hWndParent, sowie für hMenu, da wir keine Menüleiste wünschen. Das zum Fenster gehörige Programm ist unser eigenes, und wir wollen dem Fenster keine weiteren Informationen mitgeben, daher auch lpParam Null. Der Aufruf von CreateWindow erzeugt das Fenster nur, setzt seinen Sichtbarkeitsstatus aber auf "unsichtbar", wir müssen es erst durch einen Aufruf von "ShowWindow" anzeigen lassen (SW_NORMAL). Wir könnten es natürlich auch minimiert (SW_SHOWMINIMIZED) oder maximiert(SW_SHOWMAXIMIZED) anzeigen lassen. Durch UpdateWindow wird direkt nach Erzeugen des Fenster der Inhalt zum ersten Mal gezeichnet.

Als nächstes kümmern wir uns um die Von Windows verschickten Nachrichten:

36
37
38
39
40

dim as MSG Nachricht
do while GetMessage(@Nachricht, NULL, 0, 0) <> 0
    DispatchMessage  @Nachricht
loop
end Nachricht.wParam

Die Nachrichten werden in dem UDT Nachricht gespeichert. GetMessage ist ein sogenannter "blocking Call", das heißt: Das Programm verbleibt solange in der Funktion, bis eine Nachricht vorliegt. Tritt dabei ein Fehler auf (zum Beispiel, weil das Fenster geschlossen wurde), gibt GetMessage TRUE zurück, die Schleife wird verlassen, und ein eventueller Fehlercode wird ausgegeben. Andernfalls wird die Nachricht an die zur Nachricht gehörende Callback-Funktion weitergegeben:

42
43
44
45
46
47
48
49
50
51

function Fenster(byval hWnd as HWND, byval message as UINTEGER,_
    byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT

    if message = WM_DESTROY then
        PostQuitMessage 0
        return 0
    else
        return DefWindowProc(hWnd, message, wParam, lParam)
    end if
end function

Diese Funktion überprüft, ob die Nachricht WM_DESTROY geschickt wurde, also das Fenster geschlossen wurde, und beendet den Nachrichtenverkehr des Fensters mit Windows (und verlässt dadurch die do-loop schleife im Hauptprogramm). Anderfalls soll die sogenannte DefaultWindowProcedure die Behandlung übernehmen. Diese Funktion ist eine Sammlung von Reaktionen auf Nachrichten, die meißtens gleich bleiben, die man aber nicht immer neuschreiben möchte, zum Beispiel die Größe des Fensters ändern, wenn jemand mit der Maus an den Rändern des Fensters zieht.

Fertig, unser erstes "richtiges" Fenster in FreeBasic.

Links:

  • Dieses Kapitel downloaden
  • In der MSDN: WNDCLASS, RegisterClass, CreateWindow, ShowWindow, GetMessage, DefWindowProc
  • In der FreeBasic-Referenz: end, with, while


Digital
Blacksmithing
Amboss
Lutz Ifer

Inhalt

Startseite
Downloads Quellcode Entwicklung WinApi-Tutorial Linkliste
Kontakt Impressum

lutzifer.freebasic.de

Softwareschmied Lutz Ifer

Kapitel 2.1:

Ziemlich schnell nach Erstellen des ersten Fensters mit der WinApi wird einem klar, dass es mit dem reinen Erzeugen des Fensters nicht getan ist, wir müssen uns ebenfalls nach neuen Methoden umsehen, um mit diesem Fenster zu interagieren.

Weder "pset" noch "line" noch "circle" oder irgendein anderer Grafikbefehl ("Drawing Primitives") von FreeBasic lassen sich auf diesem Fenster anwenden, noch lässt sich per GetMouse die Mausposition abfragen noch lassen sich Tastaturabfragen mit inkey, multikey oder input bewerkstelligen.

Als erstes wollen wir uns darum kümmern, ein wenig Farbe auf das Fenster zu bekommen:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

''' Lutz Ifers WinAPI-Tutorial
''' LutzIfer.FreeBasic.de
'''
''' Kapitel 2.1 - "Pixeloperationen"

option explicit
#include "windows.bi"
const ProgrammName = "Pixeloperationen"

declare function Fenster(byval hWnd as HWND, byval message as UINTEGER,_
    byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT

dim as WNDCLASS	wcMeinFenster
with wcMeinFenster
    .style         =  CS_HREDRAW or CS_VREDRAW
    .lpfnWndProc   =  ProcPtr(Fenster)
    .cbClsExtra    =  0
    .cbWndExtra    =  0
    .hInstance     =  GetModuleHandle(NULL)
    .hCursor       =  LoadCursor(NULL, IDC_ARROW)
    .hIcon         =  LoadIcon(NULL, IDI_APPLICATION)
    .hbrBackground =  GetStockObject(WHITE_BRUSH)
    .lpszClassName =  StrPtr(ProgrammName)
    .lpszMenuName  =  NULL
end with
RegisterClass @wcMeinFenster

dim as HWND	hMeinFenster = CreateWindow(_
    ProgrammName, "Titelzeile", WS_OVERLAPPEDWINDOW,_
    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,_
    NULL, NULL, GetModuleHandle(NULL), NULL)

ShowWindow   hMeinFenster, SW_NORMAL
UpdateWindow hMeinFenster

dim as MSG msg
do while getmessage(@msg, NULL, 0, 0) <> 0
    DispatchMessage  @msg
loop
end msg.wParam

Der Beginn unseres Programmes ist unverändert. Wir deklarieren die Callbackfunktion des Fensters, seine Fensterklasse, erzeugen es, zeigen es an, lassen es neuzeichnen, und leiten die Nachrichten weiter. Und die sehen wir uns jetzt genauer an:

42
43
44
45
46
47
48

function Fenster(byval hWnd as HWND, byval message as UINTEGER,_
    byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT

    select case message
        case WM_DESTROY
            PostQuitMessage 0
            return 0

Dieser Teil ist uns nicht unbekannt: Wenn das Fenster die Schließen-Nachricht bekommt, soll das Programm beendet werden. In diesem Programm kümmern wir uns noch um eine zweite Nachricht, die WM_PAINT-Nachricht. Sie wird dem Fenster jedesmal zugeschickt, wenn der Inhalt des Fensters ungültig ist, also neugezeichnet werden muss. Weil ich verdeckendes Fenster verschoben wurde, sich die Fenstergröße ändert, oder wir ein Neuzeichnen angefordert haben zum Beispiel.

50
51
52

        case WM_PAINT
            dim as PAINTSTRUCT pnt
            dim as HDC hDC = BeginPaint(hWnd, @pnt)

Wir definieren als erstes eine Paintstruktur. Dieses UDT enthält wichtige Informationen über die Clippingregion. Als nächstes erzeugen wir einen sogeanannten DeviceContext, das ist eine Oberfläche eines Fensters, vergleichbar mit dem Screen[res]-Befehl in FreeBasic, angepasst an die Vorraussetzungen, die ein Mehrfenster-System mit sich bringt.

53
54
55
56
57
58

                dim as INTEGER ix, iy
                for ix = 0 to 255
                    for iy = 0 to 255
                        SetPixel hDC, ix, iy, RGB(ix, iy, 128)
                    next
                next

Der erste Befehl, den wir näher betrachen wollen, ist der SetPixel()-Befehl, der im Grunde genommen wie pset() in einem 24Bit FreeBasic-Screen funktioniert. Bei jedem Grafikbefehl müssen wir allerdings noch mit angeben, auf welchen DC gezeichnet werden soll. Durch die beiden for-Schleifen erzeugen wir einen einfachen Farbverlauf.

GetPixel ist in seiner Funktionsweise dem FreeBasic-Befehl point() identisch, zu Demonstrationsszwecken benutzen wir ihn, um einen Teil einer Zeile aus dem Farbverlauf zu kopieren:

60
61
62
63

                for iy = 100 to 200
                    dim as INTEGER iColor = GetPixel(hDC, 100, iy)
                    SetPixel hDC, 300, iy, iColor
                next

Das Pendant zu "line" heißt LineTo, funktioniert allerdings ein wenig anders, als der FB-Befehl. Der wahrscheinlich größte Unterschied ist, dass wir mehr als nur die Farbe der Linie bestimmen können, in dem wir sogenannte pens, also Stifte definieren. Die mit diesen Stiften gezogenen Linien können unterschiedlich breit, unterschiedlich in der Farbe, und unerschiedlich im Füllmuster, durchgehend, gepunktelt, gestrichelt, gepunkt-strich-punkt-strichelt usw. sein. Wir legen zwei Stifte mit der Funktion CreatePen(Stil, Dicke, Farbe) fest:

65
66

                dim as HPEN hpenDickRot = CreatePen(ps_solid, 3, rgb(0,0,255))
                dim as HPEN hpenBlau = CreatePen(ps_dot, 1, rgb(255,0,0))

Um eine Linie zu zeichnen, müssen wir erst den virtuellen Cursor verschieben, und dann eine Linie zu einem bestimmten Punkt ziehen. Diese Vorgehensweise könnte man mit einem Line-Aufruf a la

line step(0,0)-step(x,y)

vergleichen. Als erstes Zeichnen wir eine Linie mit dem Standardstift, schwarz, durchgehend, ein Pixel breit, dann eine Linie mit dem roten durchgehenden, drei Pixel breiten Stift, und zu guter letzt eine Linie mit dem gepunkteten blauen Stift:

68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83

                MoveToEx hDC,   5, 260, NULL : LineTo hDC, 250, 260

                SelectObject hDC, hpenDickRot
                MoveToEx hDC,   5, 270, NULL : LineTo hDC, 250, 270

                SelectObject hDC, hpenBlau
                MoveToEx hDC,   5, 280, NULL : LineTo hDC, 250, 280

                DeleteObject hpenDickRot
                DeleteObject hpenBlau
            EndPaint(hWnd, @pnt)
            return 0

    end select
    return DefWindowProc(hWnd, message, wParam, lParam)
end function

Jeden Pen, den wir erstellt haben, müssen wir auch wieder löschen, sobald wir mit zeichnen fertig sind. Würden wir das nicht tun, würde unser Programm irgendwann durch einen Pufferüberlauf zusammenbrechen. Noch ein Wort zur Verwendung von BeginPaint ... EndPaint: Auch wenn es so aussehen mag, als würde das Programm auch ohne diese Befehle auskommen, und auch die Dimensierung der Paintstruct überflüssig, so sind sie dennoch nötig. Windows merkt sich, ob das Fenster noch ungültig ("invalid") ist, dieser Status wird erst durch BeginPaint zurückgesetzt. Würden wir BeginPaint nicht verwenden, würde Windows unser Programm mit WM_PAINT-Nachricht bombadieren.

Besonders auf älteren Rechnern wird einem auffallen, dass das Gezeichne nicht allzuschnell ist. Die GDI ("Graphics Device Interface") zeichnet nicht Pixel, sondern Objekte, daher ist das Zeichnen eines einzelnen Pixels (mehr oder minder) genausoschnell wie das Zeichnen einer bildschirmfüllenden Bitmap. Diesen Umstand werden wir in Kapitel 2.3 benutzen, um uns des Flackerns zu entledigen.

Links:

  • Dieses Kapitel downloaden
  • In der MSDN: WM_PAINT, PAINTSTRUCT, HDC, BeginPaint, EndPaint, SetPixel, GetPixel, CreatePen, MoveToEx, LineTo
  • In der FreeBasic-Referenz: line, pset, point


Digital
Blacksmithing
Amboss
Lutz Ifer

Inhalt

Startseite
Downloads Quellcode Entwicklung WinApi-Tutorial Linkliste
Kontakt Impressum

lutzifer.freebasic.de

Softwareschmied Lutz Ifer

Kapitel 2.2:

Die WinApi-Befehle für die Freebasic-Funktionen line(...),BF und circle unterscheiden sich von denen aus letztem Kapitel dadurch, dass sie für Windows eine "Fläche" darstellen, und daher nicht mit einem Pen (Stift) sondern Brush (Pinsel) gezeichnet werden. Ein solcher Brush kann eine einfache Farbe, ein Farbverlauf, ein Muster oder eine Bitmap sein. Aus Einfachheitsgründen beschäftigen wir uns hier nur mit einfachen Farben, Bitmaps werden Kapitel 2.4 behandelt.

Das Hauptprogramm ist wie üblich das Selbe:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

''' Lutz Ifers WinAPI-Tutorial
''' LutzIfer.FreeBasic.de
'''
''' Kapitel 2.2 - "Filled Shapes"

option explicit
#include "windows.bi"
const ProgrammName = "Filled Shapes"

declare function Fenster(byval hWnd as HWND, byval message as UINTEGER,_
    byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT

dim as WNDCLASS	wcMeinFenster
with wcMeinFenster
    .style         =  CS_HREDRAW or CS_VREDRAW
    .lpfnWndProc   =  ProcPtr(Fenster)
    .cbClsExtra    =  0
    .cbWndExtra    =  0
    .hInstance     =  GetModuleHandle(NULL)
    .hCursor       =  LoadCursor(NULL, IDC_ARROW)
    .hIcon         =  LoadIcon(NULL, IDI_APPLICATION)
    .hbrBackground =  GetStockObject(WHITE_BRUSH)
    .lpszClassName =  StrPtr(ProgrammName)
    .lpszMenuName  =  NULL
end with
RegisterClass @wcMeinFenster

dim as HWND	hMeinFenster = CreateWindow(_
    ProgrammName, "Titelzeile", WS_OVERLAPPEDWINDOW,_
    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,_
    NULL, NULL, GetModuleHandle(NULL), NULL)

ShowWindow   hMeinFenster, SW_NORMAL
UpdateWindow hMeinFenster

dim as MSG msg
do while getmessage(@msg, NULL, 0, 0) <> 0
    DispatchMessage  @msg
loop
end msg.wParam

In der Callback-Funktion definieren wir nun statt der Pens Brushes (Wie erwähnt, vorerst mal nur "solid", also einfarbige Brushes). Dies können wir entweder durch direktes Eingeben des 24Bit-Wertes der Farbe tun, oder das rgb-Makro verwenden, bei dem allerdings beachtet werden sollte, das Windows kein rgb sondern bgr-Format verwendet.

42
43
44
45
46
47
48
49
50
51
52
53
54
55

function Fenster(byval hWnd as HWND, byval message as UINTEGER,_
    byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT

    select case message
        case WM_DESTROY
            PostQuitMessage 0
            return 0

        case WM_PAINT
            dim as PAINTSTRUCT pnt
            dim as HDC hDC = BeginPaint(hWnd, @pnt)
                dim as HBRUSH hbrushRot = CreateSolidBrush(rgb(0,0,255))
                dim as HBRUSH hbrushBlau = CreateSolidBrush(rgb(255,0,0))
                dim as HBRUSH hbrushBGR  = GetSysColorBrush(COLOR_BACKGROUND)

Für den dritten Brush haben wir eine Funktion verwendet, die uns die Farbe des Desktophintergrundes zurückgibt. Weitere vordefinierte Werte sind zum Beispiel die Farbe des Fensterhintergrundes(COLOR_WINDOW) oder die Farbe des Fenstertextes(COLOR_WINDOWTEXT). Die Funktion Rectangle ist, denke ich, selbsterklärend.

57
58
59
60
61
62
63
64
65
66
67

                SelectObject hDC, hbrushRot
                Rectangle hDC, 10, 10, 300, 300

                SelectObject hDC, hbrushBlau
                Rectangle hDC, 20, 20, 200, 200

                SelectObject hDC, hbrushBGR
                Rectangle hDC, 100, 100, 280, 280

                SelectObject hDC, GetStockObject(LTGRAY_BRUSH)
                Rectangle hDC, 150, 150, 250, 250

Für das letzte Rechteck verwenden wir einen vordefinierten Brush, den wir nicht löschen brauchen. Die beiden anderen Formen, die ich hier besprechen möchten, sind Ellipse und RoundRect, die eine Ellipse samt der Sonderform Kreis und ein Rechteckt mit abgerundeten Ecken zeichnet. Die Deklarationen lauten:

declare function Ellipse(hDC, nLeft, nTop, nRight, nBottom) as BOOL
declare function RoundRect(hDC, nLeft, nTop, nRight, nBottom, nWidth, nHeight) as BOOL

Wobei nWidth und nHeight der Breite und Höhe der Ellipsen in den Ecken entsprechen. Diese Formen (neben denen es noch eine Reihe weitere, wie Tortenstücke oder Sekanten gibt) zeichnen wir ohne Füllung, daher mit dem Null-Brush. Nach dem wir fertig sind, löschen wir wie üblich alle erstellten Objekte:

69
70
71
72
73
74
75
76
77
78
79
80
81
82

                SelectObject hDC, GetStockObject(NULL_BRUSH)
                Ellipse hDC, 20, 210, 90, 280
                RoundRect hDC, 210, 20, 290, 90, 16, 16

                DeleteObject hbrushBGR
                DeleteObject hbrushRot
                DeleteObject hbrushBlau
            EndPaint(hWnd, @pnt)
            return 0

    end select
    return DefWindowProc(hWnd, message, wParam, lParam)
end function

Links:

  • Dieses Kapitel downloaden
  • In der MSDN: Filled Shapes, CreateSolidBrush, GetSysColorBrush, GetStockObject, Ellipse, RoundRect, Rectangle
  • In der FreeBasic-Referenz: end, with


Digital
Blacksmithing
Amboss
Lutz Ifer

Inhalt

Startseite
Downloads Quellcode Entwicklung WinApi-Tutorial Linkliste
Kontakt Impressum

lutzifer.freebasic.de

Softwareschmied Lutz Ifer

Kapitel 2.3: Textausgabe

In diesem Kapitel lernen wir zwei Methoden kennen, um Text auf unserem Fenster darzustellen. Dazu definieren wir als erstes mal einen längeren Text, um die verschieden Möglichkeiten, die sich uns bieten, zu demonstrieren.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

''' Lutz Ifers WinAPI-Tutorial
''' LutzIfer.FreeBasic.de
'''
''' Kapitel 2.3 - "Textausgabe"

option explicit
#include "windows.bi"
const ProgrammName = "Textausgabe"
const sText =     "Lorem ipsum dolor sit amet, consectetur adipisicing elit, "+_
    "sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut en"+_
    "im ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut al"+_
    "iquip ex ea commodo consequat."+chr(13,10)+"Duis aute irure dolor in rep"+_
    "rehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatu"+_
    "r."+chr(13,10)+"Excepteur sint occaecat cupidatat non proident, sunt in "+_
    "culpa qui officia deserunt mollit anim id est laborum."+chr(13,10,13,10)+_
    "Lorem ipsum dolor sit amet, consectetur adipisicing elit, "+_
    "sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut en"+_
    "im ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut al"+_
    "iquip ex ea commodo consequat."+chr(13,10)+"Duis aute irure dolor in rep"+_
    "rehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatu"+_
    "r."+chr(13,10)+"Excepteur sint occaecat cupidatat non proident, sunt in "+_
    "culpa qui officia deserunt mollit anim id est laborum."

declare function Fenster(byval hWnd as HWND, byval message as UINTEGER,_
    byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT

dim as WNDCLASS	wcMeinFenster
with wcMeinFenster
    .style         =  CS_HREDRAW or CS_VREDRAW
    .lpfnWndProc   =  ProcPtr(Fenster)
    .cbClsExtra    =  0
    .cbWndExtra    =  0
    .hInstance     =  GetModuleHandle(NULL)
    .hCursor       =  LoadCursor(NULL, IDC_ARROW)
    .hIcon         =  LoadIcon(NULL, IDI_APPLICATION)
    .hbrBackground =  GetStockObject(WHITE_BRUSH)
    .lpszClassName =  StrPtr(ProgrammName)
    .lpszMenuName  =  NULL
end with
RegisterClass @wcMeinFenster

dim as HWND	hMeinFenster = CreateWindow(_
    ProgrammName, "Titelzeile", WS_OVERLAPPEDWINDOW,_
    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,_
    NULL, NULL, GetModuleHandle(NULL), NULL)

ShowWindow   hMeinFenster, SW_NORMAL
UpdateWindow hMeinFenster

dim as MSG msg
do while getmessage(@msg, NULL, 0, 0) <> 0
    DispatchMessage  @msg
loop
end msg.wParam

Die WM_SIZE Nachricht ist für uns neu. Sie wird immer dann an das Fenster geschickt, sobald sich die Größe des Fensters ändert. (Das Erstellen des Fensters gilt hier auch als Größenänderung.) Was ebenfalls neu ist, ist dass wir uns um lParam kümmern. Dieser Wert enthält codiert (namentlich: zwei SHORT-Werte in einem INTEGER) die Breite und Höhe des Fensters, die wir in ein UDT namens rect speichern. Dieses UDT besteht schlicht aus den vier INTEGER-Werten top, left, right und bottom.

56
57
58
59
60
61
62
63
64
65
66
67
68
69

function Fenster(byval hWnd as HWND, byval message as UINTEGER,_
    byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT

    static as RECT rect

    select case message
        case WM_DESTROY
            PostQuitMessage 0
            return 0

        case WM_SIZE
            rect.right = LOWORD(lParam)
            rect.bottom = HIWORD(lParam)
            return 0

Die beiden Textausgabebefehle arbeiten Pixelgenau. Um das zu demonstrieren, definieren wir einen Brush, mit dem wir den Bereich der Textausgabe einrahmen. Die Deklaration des ersten Befehls, den wir hier betrachten wollen lautet:

declare function TextOut(hDC as HDC, x as INTEGER, y as INTEGER, sText as STRING, lText as INTEGER) as BOOL

Theoretisch ist bei der Verwendung von Strings ja die Längenangabe überflüssig. Da die Funktion allerdings eigentlich mit zStrings arbeitet, war die Angabe der Länge notwendig. Als zweites betrachten wir die Funktion DrawString, die statt zwei INTEGERN eine RECT-Struktur für die Positionierung verwendet, und den Text innerhalb dieses Rechtecks formatieren kann. Dies geschieht wie üblich durch eine Kombination von Flags, die wir uns noch genauer ansehen werden. Die Deklaration der Funktion lautet:

declare function DrawString(hDC as HDC, sText as STRING, lText as INTEGER, pRect as RECT PTR, flags as BOOL

Um einige Formatierungen zu demonstrieren, lassen wir die Überschrift zentriert (DT_CENTER), und den Text einmal so wie er ist, einmal ohne Zeilenumbrüche(DT_SINGLELINE) und einmal an ganzen Wörtern umgebrochen(DT_WORDBREAK) darstellen. Weitere Formatierungsmöglichkeiten finden sich in der MSDN.

71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124

        case WM_PAINT
            const sUeberschrift = "Überschrift"
            dim as PAINTSTRUCT pnt
            dim as RECT textrect
            dim as HDC hDC = BeginPaint(hWnd, @pnt)
                SelectObject hDC, GetStockObject(LTGRAY_BRUSH)
                TextOut hDC, 10, 10, sUeberschrift, len(sUeberschrift)

                with textrect
                    .top    = 30
                    .left   = 0
                    .right  = rect.right
                    .bottom = 50
                end with

                Rectangle hDC, textrect.left, textrect.top, textrect.right, textrect.bottom
                DrawText hDC, sUeberschrift, len(sUeberschrift), @textrect, DT_CENTER

                with textrect
                    .top    = 60
                    .left   = 10
                    .right  = rect.right - 10
                    .bottom = 120
                end with

                Rectangle hDC, textrect.left-1, textrect.top-1, textrect.right+1, textrect.bottom+1
                DrawText hDC, sText, len(sText), @textrect, 0

                with textrect
                    .top    = 130
                    .left   = 10
                    .right  = rect.right - 10
                    .bottom = 170
                end with

                Rectangle hDC, textrect.left-1, textrect.top-1, textrect.right+1, textrect.bottom+1
                DrawText hDC, sText, len(sText), @textrect, DT_SINGLELINE

                with textrect
                    .top    = 180
                    .left   = 10
                    .right  = rect.right - 10
                    .bottom = rect.bottom - 10
                end with

                Rectangle hDC, textrect.left-1, textrect.top-1, textrect.right+1, textrect.bottom+1
                DrawText hDC, sText, len(sText), @textrect, DT_WORDBREAK

                EndPaint(hWnd, @pnt)
            return 0
    end select
    return DefWindowProc(hWnd, message, wParam, lParam)
end function

Links:

  • Dieses Kapitel downloaden
  • In der MSDN: RECT, WM_SIZE, TextOut, DrawText
  • In der FreeBasic-Referenz: hiword, loword, const, static


Digital
Blacksmithing
Amboss
Lutz Ifer

Inhalt

Startseite
Downloads Quellcode Entwicklung WinApi-Tutorial Linkliste
Kontakt Impressum

lutzifer.freebasic.de

Softwareschmied Lutz Ifer

Kapitel 2.4:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100

''' Lutz Ifers WinAPI-Tutorial
''' LutzIfer.FreeBasic.de
'''
''' Kapitel 2.4 - "Bitmaps blitten"

option explicit
#include "windows.bi"
const ProgrammName = "Bitmaps blitten"

declare function Fenster(byval hWnd as HWND, byval message as UINTEGER,_
    byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT

dim as WNDCLASS	wcMeinFenster
with wcMeinFenster
    .style         =  CS_HREDRAW or CS_VREDRAW
    .lpfnWndProc   =  ProcPtr(Fenster)
    .cbClsExtra    =  0
    .cbWndExtra    =  0
    .hInstance     =  GetModuleHandle(NULL)
    .hCursor       =  LoadCursor(NULL, IDC_ARROW)
    .hIcon         =  LoadIcon(NULL, IDI_APPLICATION)
    .hbrBackground =  GetStockObject(WHITE_BRUSH)
    .lpszClassName =  StrPtr(ProgrammName)
    .lpszMenuName  =  NULL
end with
RegisterClass @wcMeinFenster

dim as HWND	hMeinFenster = CreateWindow(_
    ProgrammName, "Titelzeile", WS_OVERLAPPEDWINDOW,_
    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,_
    NULL, NULL, GetModuleHandle(NULL), NULL)

ShowWindow   hMeinFenster, SW_NORMAL
UpdateWindow hMeinFenster

dim as MSG msg
do while getmessage(@msg, NULL, 0, 0) <> 0
    DispatchMessage  @msg
loop
end msg.wParam

function Fenster(byval hWnd as HWND, byval message as UINTEGER,_
    byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT

    static as HBITMAP   hBitmap
    static as HDC       hDC2
    dim    as HDC       hDC

    select case message
        case WM_DESTROY
            DeleteDC(hDC2)
            DeleteObject(hBitmap)
            PostQuitMessage 0
            return 0

        case WM_CREATE
            hDC = GetDC(hWnd)
            hBitmap = CreateCompatibleBitmap(hDC, 300, 300)
            hDC2    = CreateCompatibleDC(hDC)
            ReleaseDC(hWnd, hDC)

            SelectObject(hDC2, hBitmap)
            PatBlt(hDC2, 0, 0, 800, 800, WHITENESS)

            dim as INTEGER ix, iy
            for ix = 0 to 255
                for iy = 0 to 255
                    SetPixel hDC2, ix, iy, RGB(ix, iy, 128)
                next
            next

            for iy = 100 to 200
                dim as INTEGER iColor = GetPixel(hDC2, 100, iy)
                SetPixel hDC2, 300, iy, iColor
            next

            dim as HPEN hpenDickRot = CreatePen(ps_solid, 3, rgb(0,0,255))
            dim as HPEN hpenBlau = CreatePen(ps_dot, 1, rgb(255,0,0))

            MoveToEx hDC2,   5, 260, NULL : LineTo hDC2, 250, 260

            SelectObject hDC2, hpenDickRot
            MoveToEx hDC2,   5, 270, NULL : LineTo hDC2, 250, 270

            SelectObject hDC2, hpenBlau
            MoveToEx hDC2,   5, 280, NULL : LineTo hDC2, 250, 280

            DeleteObject hpenDickRot
            DeleteObject hpenBlau
            return 0

        case WM_PAINT
            dim as PAINTSTRUCT pnt
            hDC = BeginPaint(hWnd, @pnt)
                BitBlt hDC, 0, 0, 300, 300, hDC2, 0, 0, SRCCOPY
            EndPaint(hWnd, @pnt)
            return 0
    end select
    return DefWindowProc(hWnd, message, wParam, lParam)
end function

Links:

  • Dieses Kapitel downloaden
  • In der MSDN: ,
  • In der FreeBasic-Referenz: end, with, while


Digital
Blacksmithing
Amboss
Lutz Ifer

Inhalt

Startseite
Downloads Quellcode Entwicklung WinApi-Tutorial Linkliste
Kontakt Impressum

lutzifer.freebasic.de

Softwareschmied Lutz Ifer

Kapitel 2.5: Bitmaps laden

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85

''' Lutz Ifers WinAPI-Tutorial
''' LutzIfer.FreeBasic.de
'''
''' Kapitel 2.5 - "Bitmaps laden"

option explicit
#include "windows.bi"
const ProgrammName = "Bitmaps laden"

declare function Fenster(byval hWnd as HWND, byval message as UINTEGER,_
    byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT

dim as WNDCLASS	wcMeinFenster
with wcMeinFenster
    .style         =  CS_HREDRAW or CS_VREDRAW
    .lpfnWndProc   =  ProcPtr(Fenster)
    .cbClsExtra    =  0
    .cbWndExtra    =  0
    .hInstance     =  GetModuleHandle(NULL)
    .hCursor       =  LoadCursor(NULL, IDC_ARROW)
    .hIcon         =  LoadIcon(NULL, IDI_APPLICATION)
    .hbrBackground =  GetStockObject(WHITE_BRUSH)
    .lpszClassName =  StrPtr(ProgrammName)
    .lpszMenuName  =  NULL
end with
RegisterClass @wcMeinFenster

dim as HWND	hMeinFenster = CreateWindow(_
    ProgrammName, "Titelzeile", WS_OVERLAPPEDWINDOW,_
    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,_
    NULL, NULL, GetModuleHandle(NULL), NULL)

ShowWindow   hMeinFenster, SW_NORMAL
UpdateWindow hMeinFenster

dim as MSG msg
do while getmessage(@msg, NULL, 0, 0) <> 0
    DispatchMessage  @msg
loop
end msg.wParam

function Fenster(byval hWnd as HWND, byval message as UINTEGER,_
    byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT

    static as HBITMAP           hbmpLutz
    static as BITMAPINFO POINTER hbmiLutz

    select case message
        case WM_DESTROY
            PostQuitMessage 0
            return 0

        case WM_CREATE
            open "lutz.bmp" for binary as #1
            dim as INTEGER  iFileLength = lof(1)
            dim as BYTE     bvBuffer(iFileLength)
            get #1,, bvBuffer() : close #1

            dim as BITMAPFILEHEADER PTR bmpFileHeader = _
                cptr(BITMAPFILEHEADER PTR, @bvBuffer(0))

            hbmiLutz = cptr(BITMAPINFO PTR, bmpFileHeader +1)
            hbmpLutz = CreateDIBitmap(_
                GetDC(hWnd), @hbmiLutz->bmiHeader, CBM_INIT, _
                  cptr(BYTE PTR, bmpFileHeader) + bmpFileHeader->bfOffBits,_
                hbmiLutz, DIB_RGB_COLORS)
            return 0

        case WM_PAINT
            dim as PAINTSTRUCT pnt
            dim as HDC hDC = BeginPaint(hWnd, @pnt)
                dim as HDC bmpDC = CreateCompatibleDC(hDC)
                dim hOldObject as HGDIOBJ = SelectObject(bmpDC, hbmpLutz)
                BitBlt(hDC, 0, 0,_
                    hbmiLutz->bmiHeader.biWidth, hbmiLutz->bmiHeader.biHeight,_
                    bmpDC, 0, 0, SRCCOPY)

                SelectObject bmpDC, hOldObject
                DeleteDC bmpDC
            EndPaint(hWnd, @pnt)
            return 0

    end select
    return DefWindowProc(hWnd, message, wParam, lParam)
end function

Links:

  • Dieses Kapitel downloaden
  • In der MSDN: ,
  • In der FreeBasic-Referenz: end, with, while


Digital
Blacksmithing
Amboss
Lutz Ifer

Inhalt

Startseite
Downloads Quellcode Entwicklung WinApi-Tutorial Linkliste
Kontakt Impressum

lutzifer.freebasic.de

Softwareschmied Lutz Ifer

Kapitel 3.1: Tastatur

In diesem Kapitel beschäftigen wir uns mit den Nachichten, die uns Windows schickt, wenn wir eine Taste auf der Tastatur drücken. Das Hauptprogramm ist dieses mal ein wenig anders, in der Nachrichtenschleife gibt es nun zusätzlich den Befehl "TranslateMessage @msg", dessen Bedeutung wir später genauer unter die Lupe nehmen werden. Desweiteren definieren wir ein globales Array namens "Key".

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

''' Lutz Ifers WinAPI-Tutorial
''' LutzIfer.FreeBasic.de
'''
''' Kapitel 2.5 - "Tastatur"

option explicit
#include "windows.bi"
const ProgrammName = "Tastatur"

declare function Fenster(byval hWnd as HWND, byval message as UINTEGER,_
    byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT

dim shared as byte Key(255)

dim as WNDCLASS	wcMeinFenster
with wcMeinFenster
    .style         =  CS_HREDRAW or CS_VREDRAW
    .lpfnWndProc   =  ProcPtr(Fenster)
    .cbClsExtra    =  0
    .cbWndExtra    =  0
    .hInstance     =  GetModuleHandle(NULL)
    .hCursor       =  LoadCursor(NULL, IDC_ARROW)
    .hIcon         =  LoadIcon(NULL, IDI_APPLICATION)
    .hbrBackground =  GetStockObject(WHITE_BRUSH)
    .lpszClassName =  StrPtr(ProgrammName)
    .lpszMenuName  =  NULL
end with
RegisterClass @wcMeinFenster

dim as HWND	hMeinFenster = CreateWindow(_
    ProgrammName, "Titelzeile", WS_OVERLAPPEDWINDOW,_
    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,_
    NULL, NULL, GetModuleHandle(NULL), NULL)

ShowWindow   hMeinFenster, SW_NORMAL
UpdateWindow hMeinFenster

dim as MSG msg
do while getmessage(@msg, NULL, 0, 0) <> 0
    DispatchMessage  @msg
    TranslateMessage @msg
loop
end msg.wParam

Die Nachrichten WM_KEYDOWN und WM_KEYUP schickt uns Windows immer dann, wenn eine Taste gedrückt bzw. losgelassen wurde. Wenn eine dieser Nachrichten eingetreten ist, setzen wir den Status dieser Taste im Array Key auf TRUE bzw. FALSE. Dadurch ließe sich dieses Array ähnlich der multikey-Funktion von FreeBasic verwenden. Einiziger Unterschied: Die Tastencodes beginnen nicht mit "SC" sondern mit "VK" für "Virtual Key", denn die Werte entsprechen nicht den Ascii-Werten der eingetippten Tasten, sondern den IDs der Tasten.

45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

function Fenster(byval hWnd as HWND, byval message as UINTEGER,_
    byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT

    static as STRING    sText

    select case message
        case WM_DESTROY
            PostQuitMessage 0
            return 0

        case WM_KEYDOWN
            Key(wParam) = TRUE
            InvalidateRect hWnd, NULL, TRUE
            return 0

        case WM_KEYUP
            Key(wParam) = FALSE
            InvalidateRect hWnd, NULL, TRUE
            return 0

Die WM_CHAR Nachricht gibt es eigentlich nicht. Windows schickt uns nur Nachrichten über Niederdrücken und loslassen der Tasten. Allerdings kommt hier der TranslateMessage-Aufruf der Nachrichtenschleife zum Tragen: Diese Funktion fügt nach jeder WM_KEYDOWN-Nachricht eine WM_CHAR-Nachricht ein, die dann als wParam den Tatsächlichen ASCII-Wert des Zeichens enthält. Um das zu demonstrieren, sammeln wir mal alle gedrückten Tasten in einem String. Die nicht druckbaren Zeichen TAB(9), LINEFEED(10) und ESC(27) ignorieren wir, ENTER(13) soll den Text zurücksetzen, BACKSPACE(8) soll das letzte Zeichen löschen.

"InvalidateRect" weißt Windows an, das Fenster neuzuzeichnen, auf diesen Befehl wird an anderer Stelle weiter eingegangen.

65
66
67
68
69
70
71
72
73
74
75

        case WM_CHAR
            select case wParam
                case  9, 10, 27
                case 13 :   sText = ""
                case  8 :   if len(sText) > 0 then
                                sText = left(sText, len(sText) - 1)
                            end if
                case else : sText += chr(wParam)
            end select
            InvalidateRect hWnd, NULL, TRUE
            return 0

In der WM_PAINT-Nachricht geben wir zwei Texte aus: Als erstes eine Liste der im Moment gedrückten Tasten, als zweites den eingetippten Text. Hierbei wird deutlich, dass der Keycode zum Beispiel der Taste "A" immer der Selbe ist, also unabhängig von anderen Tasten wie "CTRL", "ALT" oder "SHIFT". Erst in der WM_CHAR-Nachricht wird ein "richtiges" Zeichen daraus.

77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94

        case WM_PAINT
            dim as INTEGER      i
            dim as STRING       sTasten = "Gedrückte Tasten: "
            dim as PAINTSTRUCT  ps

            for i = 0 to 255
                if Key(i) = TRUE then sTasten += chr(i, 32)
            next

            dim as HDC hDC = BeginPaint(hWnd, @ps)
                TextOut hDC, 5,  5, sTasten, len(sTasten)
                TextOut hDC, 5, 26, sText, len(sText)
            EndPaint(hWnd, @ps)
            return 0
    end select

    return DefWindowProc(hWnd, message, wParam, lParam)
end function

Links:

  • Dieses Kapitel downloaden
  • In der MSDN: TranslateMessage, WM_CHAR, WM_KEYDOWN, WM_KEYUP
  • In der FreeBasic-Referenz: case, left, len


Digital
Blacksmithing
Amboss
Lutz Ifer

Inhalt

Startseite
Downloads Quellcode Entwicklung WinApi-Tutorial Linkliste
Kontakt Impressum

lutzifer.freebasic.de

Softwareschmied Lutz Ifer

Kapitel 3.2:

Nachdem wir nun wissen, wie wir kontrollieren können, ob der Benutzer eine Taste gedrückt hat, fehlen uns noch die Methoden, um in Erfahrung zu bringen, ob die Maus bewegt wurde, bzw. in unser Fenster geklickt wurde.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

''' Lutz Ifers WinAPI-Tutorial
''' LutzIfer.FreeBasic.de
'''
''' Kapitel 3.2 - "Maus"

option explicit
#include "windows.bi"
const ProgrammName = "Maus"

declare function Fenster(byval hWnd as HWND, byval message as UINTEGER,_
    byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT

dim as WNDCLASS	wcMeinFenster
with wcMeinFenster
    .style         =  CS_HREDRAW or CS_VREDRAW
    .lpfnWndProc   =  ProcPtr(Fenster)
    .cbClsExtra    =  0
    .cbWndExtra    =  0
    .hInstance     =  GetModuleHandle(NULL)
    .hCursor       =  LoadCursor(NULL, IDC_ARROW)
    .hIcon         =  LoadIcon(NULL, IDI_APPLICATION)
    .hbrBackground =  GetStockObject(WHITE_BRUSH)
    .lpszClassName =  StrPtr(ProgrammName)
    .lpszMenuName  =  NULL
end with
RegisterClass @wcMeinFenster

dim as HWND	hMeinFenster = CreateWindow(_
    ProgrammName, "Titelzeile", WS_OVERLAPPEDWINDOW,_
    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,_
    NULL, NULL, GetModuleHandle(NULL), NULL)

ShowWindow   hMeinFenster, SW_NORMAL
UpdateWindow hMeinFenster

dim as MSG msg
do while getmessage(@msg, NULL, 0, 0) <> 0
    DispatchMessage  @msg
loop
end msg.wParam

In der Callback-Funktion verwenden wir erstmals ein UDT namens POINT. Da dies auch ein Schlüsselwort von FreeBasic ist, gibt es häufiger Probleme, wenn die FreeBasic-Funktion point() verwendet wird, und die windows.bi-Headerdatei eingebunden ist. Dies soll uns aber nicht weiter stören, da wir point() sowieso nicht auf Windows-Fenstern benutzen können.

Die Variable für den Device Context definieren wir ausnahmsweise nicht erst im WM_PAINT-Zweig der select case-Anweisung, sondern davor, damit wir die gleiche Variable in einem anderen Zweig verwenden können. Natürlich könnte man auch einfach zwei Variablen nehmen, oder eine C-ähnliche Umgebung mit scope ... end scope erzeugen - aber warum umständlicher als unbedingt notwendig.

42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71

function Fenster(byval hWnd as HWND, byval message as UINTEGER,_
    byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT

    static as POINT ptStart, ptEnde
    dim    as HDC   hDC

    select case message
        case WM_DESTROY
            PostQuitMessage 0
            return 0

        case WM_LBUTTONDOWN
            ptStart.x = LOWORD(lParam)
            ptStart.y = HIWORD(lParam)
            hDC = GetDC(hWnd)
                Ellipse hDC, ptStart.x - 5, ptStart.y - 5,_
                    ptStart.x + 5, ptStart.y + 5

            ReleaseDC hWnd, hDC
            return 0

        case WM_LBUTTONUP
            ptEnde.x = LOWORD(lParam)
            ptEnde.y = HIWORD(lParam)
            hDC = GetDC(hWnd)
                Ellipse hDC, ptEnde.x - 5, ptEnde.y - 5,_
                    ptEnde.x + 5, ptEnde.y + 5

            ReleaseDC hWnd, hDC
            return 0

Die Nachrichten WM_LBUTTONDOWN und WM_LBUTTONUP werden uns von Windows geschickt, wenn die linke Maustatste gedrückt bzw. losgelassen wird. Für die rechte Maustaste gelten die Nachrichten WM_RMOUSEBUTTONUP/DOWN. Sowohl die Nachrichten für Tastedrücke, als auch die Nachricht für Mausbewegungen enthalten Informationen über Zustand der Tasten als auch Position der Maus. Um den Unterschied der zwischen beiden Nachrichten besteht zu verdeutlichen, wird beim Klicken und Loslassen (allerdings nicht beim Gedrückthalten) der Maustaste ein Kreis um den Cursor gezeichnet.

73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93

        case WM_MOUSEMOVE
            if (wParam and MK_LBUTTON) <> 0 then
                ptEnde.x = LOWORD(lParam)
                ptEnde.y = HIWORD(lParam)
                InvalidateRect hWnd, NULL, TRUE
            end if
            return 0

        case WM_PAINT
            dim as PAINTSTRUCT  ps
            dim as STRING sText = "Maus: "+str(ptEnde.x)+", "+str(ptEnde.y)
            hDC = BeginPaint(hWnd, @ps)
                TextOut hDC, 0, 0, sText, len(sText)
                MoveToEx hDC, ptStart.x, ptStart.y, NULL
                LineTo hDC, ptEnde.x, ptEnde.y
            EndPaint(hWnd, @ps)
            return 0
    end select

    return DefWindowProc( hWnd, message, wParam, lParam )
end function

Bei einer Bewegung der Maus wird der Zweite Punkt (also der Endpunkt der Linie) aktualisiert, und bei WM_PAINT-Nachrichten wird diese Linie neugezeichnet.

Links:

  • Dieses Kapitel downloaden
  • In der MSDN: WM_LBUTTONDOWN, WM_LBUTTONUP, WM_LBUTTONDBLCLK, WM_MOUSEMOVE, GetDC
  • In der FreeBasic-Referenz: point


Digital
Blacksmithing
Amboss
Lutz Ifer

Inhalt

Startseite
Downloads Quellcode Entwicklung WinApi-Tutorial Linkliste
Kontakt Impressum

lutzifer.freebasic.de

Softwareschmied Lutz Ifer

Kapitel 4.1: Zweitfenster

Kapitellogo

Ein Fenster ist gut, zwei Fenster sind Besser, und wenn man weiß, wie man sich beliebig viele Fenster macht, ist das am aller Besten. Da der olle Lutz ein fauler Sack ist, demonstrieren wir hier nur, wie man die Fenster erzeugt - ansonsten machen die Fenster im Moment noch garnichts, als CallBack-Funktion tragen wir in die Fensterklasse nämlich direkt die Default-Window-Procedure ein.

Nochmal zur Unterscheidung zwischen Fenster und Fensterklasse: Mehrere Fenster können die Selbe Fensterklasse haben, aber kein Fenster mehrere Fensterklassen. Die Fensterklasse bestimmt die Callback-Funktion der Fenster, soll heißen: Selbe Callbackfunktion = selbe Funktion der Fenster. Trotzdem kann der Inhalt der Fenster unterschiedlich sein. Ein Beispiel: Buttons sind auch nur Fenster, wie wir später lernen werden. Sie teilen sich alle die selbe Fensterklasse, schicken beim Klicken also alle die selben Nachrichten ab. Ihr Inhalt (die Beschriftung, bzw. defacto ist es bei Buttons der Fenstertitel) kann unterschiedlich sein.

Für unserere Zweitfenster legen wir also eine eigene Fensterklasse an, die neben der anderen Callback-Funktion einen weiteren Unterschied zu Fensterklasse unseres (Haupt-)Fensters hat: Bei Style defieren wir zusätzlich "CS_NOCLOSE" - das kleine X wird also ausgegraut, ansonsten wäre es möglich, die Nebenfenster (einzeln) zu schließen.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

''' Lutz Ifers WinAPI-Tutorial
''' LutzIfer.FreeBasic.de
'''
''' Kapitel 4.1 - "Zweitfenster"

option explicit
#include "windows.bi"
const ProgrammName = "Zweitfenster"
const NebenfensterName = "Nebenfenster"

declare function Fenster(byval hWnd as HWND, byval message as UINTEGER,_
    byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT

dim as WNDCLASS	wcMeinFenster
with wcMeinFenster
    .style         =  CS_HREDRAW or CS_VREDRAW
    .lpfnWndProc   =  ProcPtr(Fenster)
    .cbClsExtra    =  0
    .cbWndExtra    =  0
    .hInstance     =  GetModuleHandle(NULL)
    .hCursor       =  LoadCursor(NULL, IDC_ARROW)
    .hIcon         =  LoadIcon(NULL, IDI_APPLICATION)
    .hbrBackground =  GetStockObject(WHITE_BRUSH)
    .lpszClassName =  StrPtr(ProgrammName)
    .lpszMenuName  =  NULL
end with
RegisterClass @wcMeinFenster

dim as WNDCLASS	wcNebenFenster
with wcNebenFenster
    .style         =  CS_HREDRAW or CS_VREDRAW or CS_NOCLOSE
    .lpfnWndProc   =  ProcPtr(DefWindowProc)
    .cbClsExtra    =  0
    .cbWndExtra    =  0
    .hInstance     =  GetModuleHandle(NULL)
    .hCursor       =  LoadCursor(NULL, IDC_ARROW)
    .hIcon         =  LoadIcon(NULL, IDI_APPLICATION)
    .hbrBackground =  GetStockObject(WHITE_BRUSH)
    .lpszClassName =  StrPtr(NebenfensterName)
    .lpszMenuName  =  NULL
end with
RegisterClass @wcNebenFenster

dim as HWND	hMeinFenster = CreateWindow(_
    ProgrammName, "Titelzeile", WS_OVERLAPPEDWINDOW,_
    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,_
    NULL, NULL, GetModuleHandle(NULL), NULL)

ShowWindow   hMeinFenster, SW_NORMAL
UpdateWindow hMeinFenster

dim as MSG msg
do while getmessage(@msg, NULL, 0, 0) <> 0
    DispatchMessage  @msg
loop
end msg.wParam
Trotz mehrerer Fenster und Fensterklassen benötigen wir nur eine Nachrichtenschleife: GetMessage empfängt alle Nachrichten eines Programmes (mit all seinen Fenstern); DispatchMessage sortiert die Nachrichten nach Fenster, und leitet sie an die zugehörigen Callback-Funktionen weiter.
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94

function Fenster(byval hWnd as HWND, byval message as UINTEGER,_
    byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT

    static as HWND hFensterA, hFensterB, hFensterC, hFensterD
    static as POINT ptStart, ptEnde
    dim    as HDC   hDC

    select case message
        case WM_DESTROY
            PostQuitMessage 0
            return 0

        case WM_CREATE
            hFensterA = CreateWindow(NebenfensterName,_
                "Vollwertiges Zweitfenster",_
                WS_OVERLAPPEDWINDOW or WS_VISIBLE,_
                CW_USEDEFAULT, CW_USEDEFAULT, 200, 100,_
                hWnd, NULL, cast(LPCREATESTRUCT,lParam)->hInstance, NULL)
            hFensterB = CreateWindow(NebenfensterName,_
                "Ohne alles",_
                WS_VISIBLE,_
                CW_USEDEFAULT, CW_USEDEFAULT, 100, 100,_
                hWnd, NULL, cast(LPCREATESTRUCT,lParam)->hInstance, NULL)
            hFensterC = CreateWindow(NebenfensterName,_
                "Vielleicht Menübar",_
                WS_VISIBLE or WS_OVERLAPPED or WS_SYSMENU,_
                CW_USEDEFAULT, CW_USEDEFAULT, 300, 150,_
                hWnd, NULL, cast(LPCREATESTRUCT,lParam)->hInstance, NULL)
            hFensterD = CreateWindow(NebenfensterName,_
                "Selbstständig",_
                WS_OVERLAPPEDWINDOW or WS_VISIBLE,_
                CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,_
                NULL, NULL, cast(LPCREATESTRUCT,lParam)->hInstance, NULL)
            return 0
    end select
    return DefWindowProc( hWnd, message, wParam, lParam )
end function

Wir erzeugen die Fenster mit der gleichen Funktion, CreateWindow, wie unser Hauptfenster. Theoretisch hätten wir das auch im Hauptprogramm machen können, allerdings werden die Rückgabewerte der Funktion, die Handles zu den einzelnen Funktionen zunehmend interessanter (wir werden später lernen, wie man die Fenster bewegt, versteckt, wieder anzeigt, minimiert, maximiert, Nachrichten schickt usw.), weshalb wir diese Werte in der Callbackfunktion benötigen, daher werden die Variablen auch als static definiert.

Als Parentwindow geben wir bis auf FensterD das "große" Hauptfenster an - damit gehören diese Fenster zum Hauptfenster, FensterD ist eigenständig, und erscheint deshalb auch in der Taskleiste als eigenständiger Eintrag.

Aber das eigentlich interessante am ganzen Fenstererstellen sind die verschieden Styles, die wir für die Fenster verwenden können. WS_VISIBLE erzeugt die Fenster aktiv, wir müssen sie nicht wie das Hauptfenster erst mit ShowWindow aktivieren. OVERLAPPEDWINDOW, eine Kombination aus mehreren anderen Style-Flags steht für die "normalen" Fenster, mit verschiebbarer Größe, Systemmenü (dem Icon links oben), Maximieren- und Minimieren-Icon. Die Namen der Styles sind soweit selbsterklärend - eine vollständige Liste findet sich in der MSDN unter Windowstyles.

Links:

  • Dieses Kapitel downloaden
  • In der MSDN: CreateWindow, Windowstyles


Digital
Blacksmithing
Amboss
Lutz Ifer

Inhalt

Startseite
Downloads Quellcode Entwicklung WinApi-Tutorial Linkliste
Kontakt Impressum

lutzifer.freebasic.de

Softwareschmied Lutz Ifer

Kapitel 4.2: Childwindows

In Kapitel 4.1 hatte ich schon verraten, dass Buttons auch nur Fenster sind, und in diesem Kapitel, in dem es um Childwindows geht, werden wir etwas kreieren, dass schon sehr nach Button aussieht. Ich hatte ebenfalls im letzten Kapitel den Unterschied zwischen Fenster und Fensterklasse erwähnt, und werde das hier noch einmal verdeutlichen: Die Childwindows die wir erstellen werden, sehen alle unterschiedlich aus, haben unterschiedlichen Inhalt, aber haben alle die selbe Callback-Funktion, und damit auch die selbe Funktion.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

''' Lutz Ifers WinAPI-Tutorial
''' LutzIfer.FreeBasic.de
'''
''' Kapitel 4.2 - "Childwindows"

option explicit
#include "windows.bi"
const ProgrammName = "Childwindows"
const ChildfensterName = "Child"

declare function Fenster(byval hWnd as HWND, byval message as UINTEGER,_
    byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT
declare function ChildFenster(byval hWnd as HWND, byval message as UINTEGER,_
    byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT

dim as WNDCLASS	wcMeinFenster
with wcMeinFenster
    .style         =  CS_HREDRAW or CS_VREDRAW
    .lpfnWndProc   =  ProcPtr(Fenster)
    .cbClsExtra    =  0
    .cbWndExtra    =  0
    .hInstance     =  GetModuleHandle(NULL)
    .hCursor       =  LoadCursor(NULL, IDC_ARROW)
    .hIcon         =  LoadIcon(NULL, IDI_APPLICATION)
    .hbrBackground =  GetStockObject(LTGRAY_BRUSH)
    .lpszClassName =  StrPtr(ProgrammName)
    .lpszMenuName  =  NULL
end with
RegisterClass @wcMeinFenster

dim as WNDCLASS	wcChildFenster
with wcChildFenster
    .style         =  CS_HREDRAW or CS_VREDRAW
    .lpfnWndProc   =  ProcPtr(Childfenster)
    .cbClsExtra    =  0
    .cbWndExtra    =  0
    .hInstance     =  GetModuleHandle(NULL)
    .hCursor       =  LoadCursor(NULL, IDC_ARROW)
    .hIcon         =  LoadIcon(NULL, IDI_APPLICATION)
    .hbrBackground =  GetStockObject(WHITE_BRUSH)
    .lpszClassName =  StrPtr(ChildfensterName)
    .lpszMenuName  =  NULL
end with
RegisterClass @wcChildFenster

dim as HWND	hMeinFenster = CreateWindow(_
    ProgrammName, "Titelzeile", WS_OVERLAPPEDWINDOW,_
    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,_
    NULL, NULL, GetModuleHandle(NULL), NULL)

ShowWindow   hMeinFenster, SW_NORMAL
UpdateWindow hMeinFenster

dim as MSG msg
do while getmessage(@msg, NULL, 0, 0) <> 0
    DispatchMessage  @msg
loop
end msg.wParam

Nachdem wir wieder zwei Fensterklassen (eine für unser Hauptfenster, eine für die Childwindows) erstellt haben, wenden wir uns der Callback-Funktion des Hauptfensters zu. Im Zweig der WM_CREATE-Message, die unserem Fenster nach erzeugen zugeschickt wird, lassen wir die Childfenster mit unterschiedlichen Styles erzeugen. Ein Style-Flag verdient denke ich besondere Aufmerksamkeit, und das ist WS_CLIPSIBLINGS: Wenn sich zwei Childwindows überlappen, und auf dem einen ChildWindow wird gezeichnet, wird in den Bereich des anderen Fensters gezeichnet. WS_CLIPSIBLINGS verursacht in diesem Fall, dass allen Überlappenden Fenstern eine WM_PAINT nachricht zugeschickt wird, damit ihre Inhalte ebenfalls aktualisiert werden. Besonders deutlich wird das, wenn in diesem Beispiel die WM_CLIPSIBLINGS-Flags gelöscht werden, und das verschiebbare Fenster über die Childfenster gezogen wird.

60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97

function Fenster(byval hWnd as HWND, byval message as UINTEGER,_
    byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT

    static as HWND hFensterA, hFensterB, hFensterC, hFensterD

    select case message
        case WM_DESTROY
            PostQuitMessage 0
            return 0

        case WM_CREATE
            hFensterD = CreateWindow(ChildfensterName,_
                "Schieb mich",_
                WS_CHILD or WS_VISIBLE or WS_CLIPSIBLINGS or WS_OVERLAPPEDWINDOW ,_
                10, 120, 320, 100,_
                hWnd, NULL, cast(LPCREATESTRUCT,lParam)->hInstance, NULL)

            hFensterA = CreateWindow(ChildfensterName,_
                "Ohne Alles",_
                WS_CHILD or WS_VISIBLE or WS_CLIPSIBLINGS,_
                10, 10, 100, 100,_
                hWnd, NULL, cast(LPCREATESTRUCT,lParam)->hInstance, NULL)

            hFensterB = CreateWindow(ChildfensterName,_
                "Rand",_
                WS_CHILD or WS_VISIBLE or WS_CLIPSIBLINGS or WS_BORDER,_
                120, 10, 100, 100,_
                hWnd, NULL, cast(LPCREATESTRUCT,lParam)->hInstance, NULL)

            hFensterC = CreateWindow(ChildfensterName,_
                "Viel Rand",_
                WS_CHILD or WS_VISIBLE or WS_CLIPSIBLINGS or WS_DLGFRAME,_
                230, 10, 100, 100,_
                hWnd, NULL, cast(LPCREATESTRUCT,lParam)->hInstance, NULL)
            return 0
    end select
    return DefWindowProc( hWnd, message, wParam, lParam )
end function

Nun sehen wir uns die Callback-Funktion der Childwindows an. Wir kümmern uns ausschließlich um die WM_PAINT-Nachrichten, und leiten alle anderen Nachrichten an die Default-Window-Procedure weiter. Mit der Funktion GetWindowText erfahren wir den Titel des Fensters, für das die Funktion grade aufgerufen wurde. Diesen Fenstertitel schreiben wir in das Fenster.

99
100
101
102
103
104
105
106
107
108
109
110
111
112
113

function Childfenster(byval hWnd as HWND, byval message as UINTEGER,_
    byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT

    select case message
        case WM_PAINT
            dim as ZSTRING*100  text
            dim as PAINTSTRUCT  ps
            dim as HDC hDC = BeginPaint(hWnd, @ps)
                GetWindowText hWnd, text, sizeof(text)
                TextOut hDC, 5, 5, text, len(text)
            EndPaint hWnd, @ps
            return 0
    end select
    return DefWindowProc(hWnd, message, wParam, lParam)
end function

Das dritte Childwindow, FensterC, sieht schon stark nach einem Button aus, funktioniert allerdings nicht wie einer. Wie man richtige Buttons erzeugt, ist Thema von Kapitel 4.5

Links:

  • Dieses Kapitel downloaden
  • In der MSDN: CreateWindow, Windowstyles


Digital
Blacksmithing
Amboss
Lutz Ifer

Inhalt

Startseite
Downloads Quellcode Entwicklung WinApi-Tutorial Linkliste
Kontakt Impressum

lutzifer.freebasic.de

Softwareschmied Lutz Ifer

Kapitel 4.3: Speicher reservieren

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187

''' Lutz Ifers WinAPI-Tutorial
''' LutzIfer.FreeBasic.de
'''
''' Kapitel 4.3 - "Speicher reservieren"

option explicit
#include "windows.bi"
const ProgrammName = "Hauptfenster"
const FensterName = "Farbfenster"

declare function WndProc(byval hWnd as HWND, byval message as UINTEGER,_
    byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT
declare function SubProc(byval hWnd as HWND, byval message as UINTEGER,_
    byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT

dim as WNDCLASS	wndcls
with wndcls
    .style         =  CS_HREDRAW or CS_VREDRAW
    .lpfnWndProc   =  ProcPtr(WndProc)
    .cbClsExtra    =  0
    .cbWndExtra    =  0
    .hInstance     =  GetModuleHandle(NULL)
    .hCursor       =  LoadCursor(NULL, IDC_ARROW)
    .hIcon         =  LoadIcon(NULL, IDI_APPLICATION)
    .hbrBackground =  GetStockObject(WHITE_BRUSH)
    .lpszClassName =  StrPtr(ProgrammName)
    .lpszMenuName  =  NULL
end with
RegisterClass @wndcls

with wndcls
    .style         =  CS_HREDRAW or CS_VREDRAW or CS_NOCLOSE
    .lpfnWndProc   =  ProcPtr(SubProc)
    .cbClsExtra    =  0
    .cbWndExtra    =  3 * sizeof(integer)
    .lpszClassName =  StrPtr(FensterName)
end with
RegisterClass @wndcls

dim as HWND	hWnd = CreateWindow(_
    ProgrammName, "Kapitel 4.3 - Speicher reservieren", WS_OVERLAPPEDWINDOW,_
    CW_USEDEFAULT, CW_USEDEFAULT, 200, 350,_
    NULL, NULL, GetModuleHandle(NULL), NULL)

ShowWindow   hWnd, SW_NORMAL
UpdateWindow hWnd

dim as MSG msg
do while getmessage(@msg, NULL, 0, 0) <> 0
    DispatchMessage  @msg
loop
end msg.wParam

function WndProc(byval hWnd as HWND, byval message as UINTEGER,_
    byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT

    static as HWND hFensterA, hFensterB, hFensterC

    select case message
        case WM_DESTROY
            PostQuitMessage 0
            return 0

        case WM_CREATE
            hFensterA = CreateWindow(FensterName,_
                "FensterA", WS_VISIBLE or WS_CHILD or WS_BORDER,_
                0, 0, 100, 100,_
                hWnd, NULL, cast(LPCREATESTRUCT,lParam)->hInstance, NULL)
            hFensterB = CreateWindow(FensterName,_
                "FensterB", WS_VISIBLE or WS_CHILD or WS_BORDER,_
                0, 100, 100, 100,_
                hWnd, NULL, cast(LPCREATESTRUCT,lParam)->hInstance, NULL)
            hFensterC = CreateWindow(FensterName,_
                "FensterC", WS_VISIBLE or WS_CHILD or WS_BORDER,_
                0, 200, 100, 100,_
                hWnd, NULL, cast(LPCREATESTRUCT,lParam)->hInstance, NULL)
            return 0

        case WM_PAINT
            dim as PAINTSTRUCT pnt
            dim as HDC hDC = BeginPaint(hWnd, @pnt)
                dim as HBRUSH hbrushR = CreateSolidBrush(rgb(0,0,255))
                dim as HBRUSH hbrushG = CreateSolidBrush(rgb(0,255,0))
                dim as HBRUSH hbrushB = CreateSolidBrush(rgb(255,0,0))

                SelectObject hDC, hbrushR
                Rectangle hDC, 120,  10, 140,  30
                Rectangle hDC, 120, 110, 140, 130
                Rectangle hDC, 120, 210, 140, 230

                SelectObject hDC, hbrushG
                Rectangle hDC, 120,  40, 140,  60
                Rectangle hDC, 120, 140, 140, 160
                Rectangle hDC, 120, 240, 140, 260

                SelectObject hDC, hbrushB
                Rectangle hDC, 120,  70, 140,  90
                Rectangle hDC, 120, 170, 140, 190
                Rectangle hDC, 120, 270, 140, 290

                DeleteObject hbrushR
                DeleteObject hbrushG
                DeleteObject hbrushB
            EndPaint(hWnd, @pnt)
            return 0

        case WM_LBUTTONDOWN
            dim as integer x = LOWORD(lParam), y = HIWORD(lParam)
            if (x > 120) and (x < 140) then
                if (y > 10) and (y < 30) then
                    SetWindowLong hFensterA,_
                        0 * len(INTEGER),_
                        not GetWindowLong(hFensterA, 0 * len(INTEGER))
                    InvalidateRect hFensterA, NULL, TRUE
                elseif (y > 40) and (y < 60) then
                    SetWindowLong hFensterA,_
                        1 * len(INTEGER),_
                        not GetWindowLong(hFensterA, 1 * len(INTEGER))
                    InvalidateRect hFensterA, NULL, TRUE
                elseif (y > 70) and (y < 90) then
                    SetWindowLong hFensterA,_
                        2 * len(INTEGER),_
                        not GetWindowLong(hFensterA, 2 * len(INTEGER))
                    InvalidateRect hFensterA, NULL, TRUE
                end if

                if (y > 110) and (y < 130) then
                    SetWindowLong hFensterB,_
                        0 * len(INTEGER),_
                        not GetWindowLong(hFensterB, 0 * len(INTEGER))
                    InvalidateRect hFensterB, NULL, TRUE
                elseif (y > 140) and (y < 160) then
                    SetWindowLong hFensterB,_
                        1 * len(INTEGER),_
                        not GetWindowLong(hFensterB, 1 * len(INTEGER))
                    InvalidateRect hFensterB, NULL, TRUE
                elseif (y > 170) and (y < 190) then
                    SetWindowLong hFensterB,_
                        2 * len(INTEGER),_
                        not GetWindowLong(hFensterB, 2 * len(INTEGER))
                    InvalidateRect hFensterB, NULL, TRUE
                end if

                if (y > 210) and (y < 230) then
                    SetWindowLong hFensterC,_
                        0 * len(INTEGER),_
                        not GetWindowLong(hFensterC, 0 * len(INTEGER))
                    InvalidateRect hFensterC, NULL, TRUE
                elseif (y > 240) and (y < 260) then
                    SetWindowLong hFensterC,_
                        1 * len(INTEGER),_
                        not GetWindowLong(hFensterC, 1 * len(INTEGER))
                    InvalidateRect hFensterC, NULL, TRUE
                elseif (y > 270) and (y < 290) then
                    SetWindowLong hFensterC,_
                        2 * len(INTEGER),_
                        not GetWindowLong(hFensterC, 2 * len(INTEGER))
                    InvalidateRect hFensterC, NULL, TRUE
                end if
            end if
            return 0
    end select
    return DefWindowProc( hWnd, message, wParam, lParam )
end function

function SubProc(byval hWnd as HWND, byval message as UINTEGER,_
    byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT

    select case message
        case WM_PAINT
            dim as PAINTSTRUCT pnt
            dim as HDC hDC = BeginPaint(hWnd, @pnt)
                dim as INTEGER  r, g, b
                r = iif(GetWindowLong(hWnd, 0 * len(integer)), 255, 0)
                g = iif(GetWindowLong(hWnd, 1 * len(integer)), 255, 0)
                b = iif(GetWindowLong(hWnd, 2 * len(integer)), 255, 0)
                dim as HBRUSH hBrush = CreateSolidBrush(rgb(b,g,r))

                SelectObject hDC, hBrush
                    Rectangle hDC, 10, 10, 90, 90
                DeleteObject hBrush
            EndPaint(hWnd, @pnt)
            return 0
    end select

    return DefWindowProc( hWnd, message, wParam, lParam )
end function

Links:

  • Dieses Kapitel downloaden
  • In der MSDN: ,
  • In der FreeBasic-Referenz: end, with, while


Digital
Blacksmithing
Amboss
Lutz Ifer

Inhalt

Startseite
Downloads Quellcode Entwicklung WinApi-Tutorial Linkliste
Kontakt Impressum

lutzifer.freebasic.de

Softwareschmied Lutz Ifer

Kapitel 4.4: Messages

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184

''' Lutz Ifers WinAPI-Tutorial
''' LutzIfer.FreeBasic.de
'''
''' Kapitel 4.4 - "Messages"

option explicit
#include "windows.bi"
const ProgrammName = "Hauptfenster"
const FensterName = "Farbfenster"

declare function WndProc(byval hWnd as HWND, byval message as UINTEGER,_
    byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT
declare function SubProc(byval hWnd as HWND, byval message as UINTEGER,_
    byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT

enum
    PM_COLORSET = WM_APP + 1
    PM_COLORRESET
end enum

dim as WNDCLASS	wndcls
with wndcls
    .style         =  CS_HREDRAW or CS_VREDRAW
    .lpfnWndProc   =  ProcPtr(WndProc)
    .cbClsExtra    =  0
    .cbWndExtra    =  0
    .hInstance     =  GetModuleHandle(NULL)
    .hCursor       =  LoadCursor(NULL, IDC_ARROW)
    .hIcon         =  LoadIcon(NULL, IDI_APPLICATION)
    .hbrBackground =  GetStockObject(LTGRAY_BRUSH)
    .lpszClassName =  StrPtr(ProgrammName)
    .lpszMenuName  =  NULL
end with
RegisterClass @wndcls

with wndcls
    .style         =  CS_HREDRAW or CS_VREDRAW or CS_NOCLOSE
    .lpfnWndProc   =  ProcPtr(SubProc)
    .cbClsExtra    =  0
    .cbWndExtra    =  sizeof(integer)
    .lpszClassName =  StrPtr(FensterName)
end with
RegisterClass @wndcls

dim as HWND	hWnd = CreateWindow(_
    ProgrammName, "Kapitel 4.4", WS_OVERLAPPEDWINDOW,_
    CW_USEDEFAULT, CW_USEDEFAULT, 200, 350,_
    NULL, NULL, GetModuleHandle(NULL), NULL)

ShowWindow   hWnd, SW_NORMAL
UpdateWindow hWnd

dim as MSG msg
do while getmessage(@msg, NULL, 0, 0) <> 0
    DispatchMessage  @msg
loop
end msg.wParam

function WndProc(byval hWnd as HWND, byval message as UINTEGER,_
    byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT

    static as HWND hwndA, hwndB, hwndC

    select case message
        case WM_DESTROY
            PostQuitMessage 0
            return 0

        case WM_CREATE
            hwndA = CreateWindow(FensterName,_
                "FensterA", WS_VISIBLE or WS_CHILD or WS_DLGFRAME,_
                5, 5, 90, 90,_
                hWnd, NULL, cast(LPCREATESTRUCT,lParam)->hInstance, NULL)
            hwndB = CreateWindow(FensterName,_
                "FensterB", WS_VISIBLE or WS_CHILD or WS_DLGFRAME,_
                5, 105, 90, 90,_
                hWnd, NULL, cast(LPCREATESTRUCT,lParam)->hInstance, NULL)
            hwndC = CreateWindow(FensterName,_
                "FensterC", WS_VISIBLE or WS_CHILD or WS_DLGFRAME,_
                5, 205, 90, 90,_
                hWnd, NULL, cast(LPCREATESTRUCT,lParam)->hInstance, NULL)
            return 0

        case WM_PAINT
            dim as PAINTSTRUCT pnt
            dim as HDC hDC = BeginPaint(hWnd, @pnt)
                dim as HBRUSH hbrushR = CreateSolidBrush(rgb(0,0,255))
                dim as HBRUSH hbrushG = CreateSolidBrush(rgb(0,255,0))
                dim as HBRUSH hbrushB = CreateSolidBrush(rgb(255,0,0))
                dim as HBRUSH hbrushW = CreateSolidBrush(rgb(255,255,255))

                SelectObject hDC, hbrushR
                Rectangle hDC, 120,  10, 140,  30
                Rectangle hDC, 120, 110, 140, 130
                Rectangle hDC, 120, 210, 140, 230

                SelectObject hDC, hbrushG
                Rectangle hDC, 120,  40, 140,  60
                Rectangle hDC, 120, 140, 140, 160
                Rectangle hDC, 120, 240, 140, 260

                SelectObject hDC, hbrushB
                Rectangle hDC, 120,  70, 140,  90
                Rectangle hDC, 120, 170, 140, 190
                Rectangle hDC, 120, 270, 140, 290

                SelectObject hDC, hbrushW
                Rectangle hDC, 150,  10, 170,  90
                Rectangle hDC, 150, 110, 170, 190
                Rectangle hDC, 150, 210, 170, 290

                DeleteObject hbrushW
                DeleteObject hbrushR
                DeleteObject hbrushG
                DeleteObject hbrushB
            EndPaint(hWnd, @pnt)
            return 0

        case WM_LBUTTONDOWN
            dim as integer x = LOWORD(lParam), y = HIWORD(lParam)
            if (x > 120) and (x < 140) then
                if (y > 10) and (y < 30) then
                    SendMessage hwndA, PM_COLORSET, &H0000ff, 0
                elseif (y > 40) and (y < 60) then
                    SendMessage hwndA, PM_COLORSET, &H00ff00, 0
                elseif (y > 70) and (y < 90) then
                    SendMessage hwndA, PM_COLORSET, &Hff0000, 0
                end if

                if (y > 110) and (y < 130) then
                    SendMessage hwndB, PM_COLORSET, &H0000ff, 0
                elseif (y > 140) and (y < 160) then
                    SendMessage hwndB, PM_COLORSET, &H00ff00, 0
                elseif (y > 170) and (y < 190) then
                    SendMessage hwndB, PM_COLORSET, &Hff0000, 0
                end if

                if (y > 210) and (y < 230) then
                    SendMessage hwndC, PM_COLORSET, &H0000ff, 0
                elseif (y > 240) and (y < 260) then
                    SendMessage hwndC, PM_COLORSET, &H00ff00, 0
                elseif (y > 270) and (y < 290) then
                    SendMessage hwndC, PM_COLORSET, &Hff0000, 0
                end if
            end if

            if (x > 150) and (x < 170) then
                if (y> 10)and(y< 90) then SendMessage hwndA, PM_COLORRESET, 0, 0
                if (y>110)and(y<190) then SendMessage hwndB, PM_COLORRESET, 0, 0
                if (y>210)and(y<290) then SendMessage hwndC, PM_COLORRESET, 0, 0
            end if
            return 0
    end select
    return DefWindowProc( hWnd, message, wParam, lParam )
end function

function SubProc(byval hWnd as HWND, byval message as UINTEGER,_
    byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT

    select case message
        case PM_COLORRESET
            SetWindowLong hWnd, 0, 0
            InvalidateRect hWnd, NULL, TRUE
            return 0

        case PM_COLORSET
            SetWindowLong hWnd, 0, GetWindowLong(hWnd, 0) xor wParam
            InvalidateRect hWnd, NULL, TRUE
            return 0

        case WM_PAINT
            dim as PAINTSTRUCT pnt
            dim as HDC hDC = BeginPaint(hWnd, @pnt)
                dim as HBRUSH hBrush = CreateSolidBrush(GetWindowLong(hWnd, 0))
                SelectObject hDC, hBrush
                    Rectangle hDC, 0, 0, 90, 90
                DeleteObject hBrush
            EndPaint(hWnd, @pnt)
            return 0
    end select

    return DefWindowProc( hWnd, message, wParam, lParam )
end function

Links:

  • Dieses Kapitel downloaden
  • In der MSDN: ,
  • In der FreeBasic-Referenz: end, with, while


Digital
Blacksmithing
Amboss
Lutz Ifer

Inhalt

Startseite
Downloads Quellcode Entwicklung WinApi-Tutorial Linkliste
Kontakt Impressum

lutzifer.freebasic.de

Softwareschmied Lutz Ifer

Kapitel 4.5: Buttons erstellen

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105

''' Lutz Ifers WinAPI-Tutorial
''' LutzIfer.FreeBasic.de
'''
''' Kapitel 4.5 - "Buttons erstellen"

option explicit
#include "windows.bi"
const ProgrammName = "Buttons"

declare function WndProc(byval hWnd as HWND, byval message as UINTEGER,_
    byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT
declare function SubProc(byval hWnd as HWND, byval message as UINTEGER,_
    byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT

dim as WNDCLASS	wndcls
with wndcls
    .style         =  CS_HREDRAW or CS_VREDRAW
    .lpfnWndProc   =  ProcPtr(WndProc)
    .cbClsExtra    =  0
    .cbWndExtra    =  0
    .hInstance     =  GetModuleHandle(NULL)
    .hCursor       =  LoadCursor(NULL, IDC_ARROW)
    .hIcon         =  LoadIcon(NULL, IDI_APPLICATION)
    .hbrBackground =  GetSysColorBrush(COLOR_WINDOW)
    .lpszClassName =  StrPtr(ProgrammName)
    .lpszMenuName  =  NULL
end with
RegisterClass @wndcls

dim as HWND	hWnd = CreateWindow(_
    ProgrammName, ProgrammName, WS_OVERLAPPED or WS_SYSMENU,_
    CW_USEDEFAULT, CW_USEDEFAULT, 180, 210,_
    NULL, NULL, GetModuleHandle(NULL), NULL)

ShowWindow   hWnd, SW_NORMAL
UpdateWindow hWnd

dim as MSG msg
do while getmessage(@msg, NULL, 0, 0) <> 0
    DispatchMessage  @msg
loop
end msg.wParam

function WndProc(byval hWnd as HWND, byval message as UINTEGER,_
    byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT

    static  as HWND hBeenden, hLinks, hMitte, hRechts
    static  as HWND hfoo, hbar, hfrage
    static  as HWND hrot, hblau, hgruen

    select case message
        case WM_DESTROY
            PostQuitMessage 0
            return 0

        case WM_CREATE
            hBeenden = CreateWindow("button", "Beenden",_
                WS_CHILD or WS_VISIBLE,_
                5, 5, 160, 22, hWnd, NULL,_
                cast(LPCREATESTRUCT,lParam)->hInstance,NULL)
            hLinks = CreateWindow("button", "A",_
                WS_CHILD or WS_VISIBLE,_
                5, 30, 50, 22, hWnd, NULL,_
                cast(LPCREATESTRUCT,lParam)->hInstance,NULL)
            hMitte = CreateWindow("button", "B",_
                WS_CHILD or WS_VISIBLE,_
                60, 30, 50, 22, hWnd, NULL,_
                cast(LPCREATESTRUCT,lParam)->hInstance,NULL)
            hRechts = CreateWindow("button", "C",_
                WS_CHILD or WS_VISIBLE,_
                115, 30, 50, 22, hWnd, NULL,_
                cast(LPCREATESTRUCT,lParam)->hInstance,NULL)
            hfoo = CreateWindow("button", "foo",_
                BS_AUTOCHECKBOX or WS_VISIBLE or WS_CHILD or WS_CLIPSIBLINGS,_
                5, 60, 40,20, hWnd, NULL,_
                cast(LPCREATESTRUCT,lParam)->hInstance,NULL)
            hbar = CreateWindow("button", "bar",_
                BS_AUTOCHECKBOX or WS_VISIBLE or WS_CHILD or WS_CLIPSIBLINGS,_
                50, 60, 45,20, hWnd, NULL,_
                cast(LPCREATESTRUCT,lParam)->hInstance,NULL)
            hfrage = CreateWindow("button", "Sicher?",_
                BS_CHECKBOX or WS_VISIBLE or WS_CHILD or WS_CLIPSIBLINGS,_
                100, 60, 70,20, hWnd, NULL,_
                cast(LPCREATESTRUCT,lParam)->hInstance,NULL)
            CreateWindow("button", "Lieblingsfarbe?",_
                WS_CHILD or WS_VISIBLE or WS_GROUP or BS_GROUPBOX,_
                5,90,160, 90, hWnd, NULL,_
                cast(LPCREATESTRUCT,lParam)->hInstance,NULL)
            hrot = CreateWindow("button", "Rot",_
                BS_AUTORADIOBUTTON or WS_VISIBLE or WS_CHILD or WS_GROUP,_
                10, 110, 70,20, hWnd, NULL,_
                cast(LPCREATESTRUCT,lParam)->hInstance,NULL)
            hblau = CreateWindow("button", "Blau",_
                BS_AUTORADIOBUTTON or WS_VISIBLE or WS_CHILD,_
                10, 130, 70,20, hWnd, NULL,_
                cast(LPCREATESTRUCT,lParam)->hInstance,NULL)
            hgruen = CreateWindow("button", "Grün",_
                BS_AUTORADIOBUTTON or WS_VISIBLE or WS_CHILD,_
                10, 150, 70,20, hWnd, NULL,_
                cast(LPCREATESTRUCT,lParam)->hInstance,NULL)
            SendMessage hrot, BM_SETCHECK, BST_CHECKED, 0
            return 0
    end select
    return DefWindowProc( hWnd, message, wParam, lParam )
end function

Links:

  • Dieses Kapitel downloaden
  • In der MSDN: ,
  • In der FreeBasic-Referenz: end, with, while


Digital
Blacksmithing
Amboss
Lutz Ifer

Inhalt

Startseite
Downloads Quellcode Entwicklung WinApi-Tutorial Linkliste
Kontakt Impressum

lutzifer.freebasic.de

Softwareschmied Lutz Ifer

Kapitel 4.6: Buttons erstellen

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

''' Lutz Ifers WinAPI-Tutorial
''' LutzIfer.FreeBasic.de
'''
''' Kapitel 4.6 - "Auf Buttons reagieren"

' (...)

        case WM_COMMAND
            if HIWORD(wParam) <> BN_CLICKED then return 0

            select case lParam
                case hLinks  : MessageBox  hWnd, "klick","Button A", 0
                case hMitte  : MessageBox  hWnd, "klick","Button B", 0
                case hRechts : MessageBox  hWnd, "klick","Button C", 0
                case hFrage
                    if SendMessage(hFrage, BM_GETCHECK, 0, 0) = BST_CHECKED then
                        SendMessage hFrage, BM_SETCHECK, BST_UNCHECKED, 0
                    elseif MessageBox(hWnd, "Wirklich auswählen?", "Frage",_
                            MB_YESNO or MB_ICONQUESTION) = IDYES then
                        SendMessage hFrage, BM_SETCHECK, BST_CHECKED, 0
                    end if
                case hBeenden
                    dim as string sText = "angeklickte Buttons:"+chr(13,10)
                    if SendMessage(hfoo,  BM_GETCHECK,0,0) = BST_CHECKED then _
                        sText += "foo "
                    if SendMessage(hbar,  BM_GETCHECK,0,0) = BST_CHECKED then _
                        sText += "bar "
                    if SendMessage(hfrage,BM_GETCHECK,0,0) = BST_CHECKED then _
                        sText += "sicher"

                    sText += chr(13, 10, 13, 10) + "Die Lieblingsfarbe ist "

                    if SendMessage(hrot,  BM_GETCHECK,0,0) = BST_CHECKED then _
                        sText += "rot"
                    if SendMessage(hblau, BM_GETCHECK,0,0) = BST_CHECKED then _
                        sText += "blau"
                    if SendMessage(hgruen,BM_GETCHECK,0,0) = BST_CHECKED then _
                        sText += "grün"

                    sText += chr(13, 10, 13, 10) + "Wirklich Beenden?"

                    if MessageBox(hWnd, sText, "Beenden",_
                            MB_YESNO or MB_ICONQUESTION) = IDYES then
                        SendMessage(hWnd, WM_CLOSE, 0, 0)
                    end if
            end select
            return 0
    end select
    return DefWindowProc( hWnd, message, wParam, lParam )
end function

Links:

  • Dieses Kapitel downloaden
  • In der MSDN: ,
  • In der FreeBasic-Referenz: end, with, while