Buchempfehlung
Visual Basic 6 Kochbuch
Visual Basic 6 Kochbuch
Viele praktische Tipps zum Programmieren mit Visual Basic 6, die sich oft auch auf FB übertragen lassen. [Mehr Infos...]
FreeBASIC-Chat
Es sind Benutzer im FreeBASIC-Chat online.
(Stand:  )
FreeBASIC bei Twitter
Twitter FreeBASIC-Nachrichten jetzt auch über Twitter erhalten. Follow us!

Tutorial

Lutz Ifers WinAPI Tutorial

von RedakteurMODSeite 4 von 16

Kapitel 2.1: Pixeloperationen
Kap2.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 BefehlsreferenzeintragPSet noch BefehlsreferenzeintragLine noch BefehlsreferenzeintragCircle oder irgendein anderer Grafikbefehl ("Drawing Primitives") von FreeBasic lassen sich auf diesem Fenster anwenden, noch lässt sich per BefehlsreferenzeintragGetMouse die Mausposition abfragen, noch lassen sich Tastaturabfragen mit BefehlsreferenzeintragInkey, BefehlsreferenzeintragMultiKey oder Input bewerkstelligen.

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

''' Lutz Ifers WinAPI-Tutorial
''' Lizenz: WTFPL
'''
''' Kapitel 2.1 - "Pixeloperationen"

#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:

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 ein verdeckendes Fenster verschoben wurde, sich die Fenstergröße ändert oder wir ein Neuzeichnen angefordert haben zum Beispiel.

        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 sogenannten 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.

                dim as INTEGER ix, iy
                for ix = 0 to 255
                    for iy = 0 to 255
                        SetPixel hDC, ix, iy, RGBA(ix, iy, 128,0)
                    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 Befehlsreferenzeintragpoint() identisch, zu Demonstrationsszwecken benutzen wir ihn, um einen Teil einer Zeile aus dem Farbverlauf zu kopieren:

                for iy = 100 to 200
                    dim as INTEGER iColor = GetPixel(hDC, 100, iy)
                    SetPixel hDC, 299, 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:

                dim as HPEN hpenDickRot = CreatePen(ps_solid, 3, RGBA(0,0,255,0))
                dim as HPEN hpenBlau = CreatePen(ps_dot, 1, RGBA(255,0,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:


                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 ohne diese Befehle auskommen und auch die Dimensierung der Paintstruct überflüssig scheint, 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:

In der MSDN: Externer Link!WM_PAINT, Externer Link!PAINTSTRUCT, Externer Link!HDC, Externer Link!BeginPaint, Externer Link!EndPaint, Externer Link!SetPixel, Externer Link!GetPixel, Externer Link!CreatePen, Externer Link!MoveToEx, Externer Link!LineTo
In der FreeBasic-Referenz: BefehlsreferenzeintragLINE, BefehlsreferenzeintragPSET, BefehlsreferenzeintragPOINT

 

Gehe zu Seite Gehe zu Seite  1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16  
Zusätzliche Informationen und Funktionen
  • Das Tutorial wurde am 17.09.2009 von RedakteurMOD angelegt.
  • Die aktuellste Version wurde am 17.07.2013 von AdministratorSebastian gespeichert.
  Bearbeiten Bearbeiten  

  Versionen Versionen