Grafik med GDI

Tags:    c++
<< < 123 > >>
Skrevet af Bruger #8985 @ 12.05.2009
Artikel filer

Forord


Hej, og velkommen til min første artikel på Udvikleren. Måden, jeg vil lære dig GDI på, er ved at vise en masse kodeeksempler, hvis resultater jeg har taget billeder af og indsat under de fleste af koderne. Disse eksempler gør brug af grundlæggende elementer indenfor GDI, som jeg så giver en forklaring af nedenunder billedet med resultatet. Artiklen er skrevet for begyndere indenfor GDI, men et godt kendskab til Win32-API’et er krævet. Sidst men ikke mindst vil jeg bede dig om at læse artiklen grundigt, inden du afgiver din bedømmelse eller kommentar. Ikke at disse er uønskede – det modsatte er faktisk tilfældet – men jeg har før oplevet, at jeg har skrevet en artikel, hvorefter der har været en eller anden torsk, der har brokket sig over, hvorfor jeg ikke har oplyst, hvad GDI står for. Det er lidt småirriterende :)!

Hvad er GDI og hvad er formålet?


GDI står for Graphics Device Interface, og består som alle andre biblioteker af en masse typer, funktioner og konstanter. GDI er hverken et API eller et framework, hvilket tillader det at være en kerne "bygget" direkte ind i Win32-API'et, så hvis du har det (altså Win32-API'et) liggende, er du klar til anvende GDI. Hvis ikke Win32-API'et fulgte med din IDE, kan du downloade Windows Platform SDK. Der er forkellige versioner, så hvis du vil have et link, må du søge på Google.
Før jeg kan forklare alle tre bogstaver i GDI tilsammen, er jeg nødt til at forklare de to første. GD står for Graphics Device, og i GDI bruger man noget, der hedder en Device Context. Sådan en har sin egen type i Win32-API'et, og den hedder HDC (Handle to Device Context). Navnet "Device Context" er måske ikke så ligetil, men det er temmelig præcist: En DC repræsenterer det grafiske indhold af en 'device'.
I GDI kan man udføre grafiske operationer på 3 forskellige 'devices': Computerens skærm, computerens hukommelse og en tilsluttet printer. Eksempelvis benytter Windows GDI til at tegne menuerne (HMENU) i et program, en tekstboks ("EDIT") bruger GDI til at vise teksten, og det skulle ikke undre mig, om et spil som Mario er lavet i GDI.

Vores første GDI program


Forestil dig, vi har kodet et lille program, der opretter et tomt GUI vindue. Som alle, der er i stand til at drage nytte af denne artikel, ved, har et Win32-vindue en handle på nøjagtig samme måde, som en device context. Den hedder HWND. Hvis vi opretter en HDC af vores HWND tilhørende GUI vinduet, kan vi med GDI tegne streger, cirkler, firkanter, bitmaps, pixels, skrive tekt og meget mere i vinduet.
Nå, vi må hellere hoppe ud i det, inden du mister interessen, så her kommer et eksempel.

Obs.: For at kompilere koder, der benytter GDI, skal du lænke med gdi32.lib. windows.h er dog stadig den eneste headerfil, vi inkluderer.

Fold kodeboks ind/udKode 


Her ser du resultatet:



Al den kode kan i første omgang virke uoverskuelig og håbløs, så lad os skære al den regulære Win32-kode væk, så vi står tilbage med ren GDI-kode.
Fold kodeboks ind/udKode 


To variabler, to typer, fire funktionskald og fire konstanter. Nu er det ligefrem enkelt. Måske vil jeg endda være i stand til at forklare linjerne.

HBRUSH er en type ligesom int, men en lidt speciel en. Hvis du opretter en variabel af typen HBRUSH, kan du (i Visual Studio og, hvis du er heldig, også i Dev-C++) se, at den kun har ét medlem. Strukturen ser nogenlunde således ud:

typedef struct tagHBRUSH
{
int unused;
} *HBRUSH;


HWND, HDC, HMENU og alle andre "handles" har samme struktur, så du kan i princippet gøre således, uden din IDE brokker sig:

HBRUSH hbr = (HBRUSH)GetDC(hwnd);

Det gør dog ikke ligefrem din kode mere overskuelig, og GDI bruger de forskellige typer handles til at skelne mellem GDI-objekterne, så det frarådes.

GetStockObject() er en hurtig måde at få fingre i et bestemt GDI-objekt. Ulempen er, at den ikke har adgang til særlig mange af dem. Her er en liste over værdier, du kan kalde GetStockObject med: http://msdn.microsoft.com/en-us/library/dd144925(VS.85).aspx

Alt, du kan opnå med GetStockObject, kan du opnå med kald til andre GDI-funktioner. Hvis du virkelig ønsker at forstå det smarte i at bruge den, kan du sammenligne det med en butik. GetStockObject viser dig de varer, der er stillet frem, hvilket betyder hurtig betjening men et begrænset udvalg. Med kald til et par andre GDI-funktioner får du adgang til butikkens lager.

Mens en HWND repræsenterer selve vinduet, giver en HDC adgang til vinduets grafiske indhold. Der er et par måder, vi kan få fat i et vindues DC. Et kald til GetDC er det enkleste. Da et vindue og dets grafiske indhold går hånd i hånd, er det en handle til vores vindue (en HWND), vi giver GetDC.

DrawText er en funktion som alle andre. Den skriver en tekst på din DC. Du kan med andre GDI-funktioner styre font og farve på teksten. Det kommer vi ind på senere. DrawText er defineret således:

int DrawText(
HDC hDC,
LPCTSTR lpString,
int nCount,
LPRECT lpRect,
UINT uFormat
);


På MSDN står der, at sidste argument er af typen UNIT, men det er en fejl! Den er af typen UINT, som ser således ud:

typedef unsigned int UINT;

lpString
er den tekst, du vil skrive på din DC.
nCount er antal tegn, der skal udskrives. Du kan få fat i en strengs længde uden at inkludere iostream således:

lstrlen("Hello, World!");

lpRect er en pointer af typen RECT. LP står for Long Pointer, som var et begreb i de tidligere versioner af Windows. Dette argument indeholder tekstens "bounding box". Det er den, der afgør, hvor teksten skal stå i DC’en.
uFormat tillader dig at give funktionen et par ekstra instrukser om, hvordan teksten skal opstilles. Du kan se en liste over mulige værdier her: http://msdn.microsoft.com/en-us/library/ms901121.aspx .

ReleaseDC sletter en device context oprettet med et kald til GetDC. Som sagt er der flere måder at oprette en DC på. Hver måde har sin tilsvarende funktion til slettelse af en DC. Mere om det senere.
DeleteObject sletter et GDI-objekt fra hukommelsen. Du bør altid kalde DeleteObject på et GDI-objekt, når du er færdig med det. Hvis dit program opretter for mange GDI-objekter uden at slette dem, crasher det.

Der er ikke mange ben i at udskrive tekst, når først man har DC'en. Det samme gælder firkanter, cirkler, linjer og så videre. De fleste af dem er blot et kald til en funktion. Hvis vi vil tegne en firkant, kalder vi funktionen Rectangle. I den type GDI-funktioner er DC'en altid det første argument. Eksempel:

Rectangle(dc, 100, 100, 200, 200);

100, 100 er koordinaterne for øverste venstre hjørne af firkanten. 200, 200 er ikke bredde og højde; det er koordinater for nederste højre hjørne. Ønsker vi at tegne en cirkel, gør vi således:

Ellipse(dc, 10, 10, 50, 50);

Nøjagtig samme liste af argumenter. Her er en liste over funktioner, der bruges til at tegne former.

Chord
Ellipse
FillRect
FrameRect
InvertRect
Pie
Polygon
PolyPolygon
Rectangle
RoundRect

RoundRect
bruges til at tegne firkanter med runde hjørne. Der står meget mere om disse funktioner her: http://msdn.microsoft.com/en-us/library/dd162715(VS.85).aspx .


Vedhæftede filer:


<< < 123 > >>

Hvad synes du om denne artikel? Giv din mening til kende ved at stemme via pilene til venstre og/eller lægge en kommentar herunder.

Del også gerne artiklen med dine Facebook venner:  

Kommentarer (13)

User
Bruger #10113 @ 25.05.09 16:32
Virker dette kun i Windows?
User
Bruger #8985 @ 25.05.09 17:32
Så vidt jeg ved, ja. Desværre :( Men jeg er overbevist om, at der findes alternativer til andre operativsystemer.
User
Bruger #11750 @ 02.06.09 23:04
Ikke lige mit fagområde :D Men det ser rigtig godt ud!
User
Bruger #8985 @ 04.06.09 21:17
Tak!
User
Bruger #9646 @ 23.09.09 14:07
windows.h - duer kun på windows?

Jeg har prøvet at smide ind i CodeBlocks og compiled på en Mac, og får en hel del errors :)

Hvordan kan man omskrive så den virker på mac?
User
Bruger #8985 @ 09.10.09 19:25
Jeg ville gerne hjælpe dig, men jeg har ingen idé om det. :( Jeg har aldrig skrevet programmer til andet end Windows. Faktisk har jeg aldrig ejet et operativsystem andet end Windows (eksempelvis Linux på en Virtual Machine for en kort stund). Jeg er bange for, der skal nogle helt andre biblioteker til, hvis du skal kode til Mac. Altså jeg tror ikke, der findes noget der hedder GDI ved Mac.
User
Bruger #15732 @ 04.03.10 17:09
Sakl lige teste noget håber det er ok jeg er nu på siden
Fold kodeboks ind/udKode 
#include <iostream>
std::cout << "test" << std::endl;
User
Bruger #15732 @ 04.03.10 17:10
Fold kodeboks ind/udKode 
#include <iostream>
User
Bruger #15732 @ 04.03.10 17:10
[code][#include <iostream>]
User
Bruger #15732 @ 04.03.10 17:12
Fold kodeboks ind/udKode 
[#include <iostream>]
User
Bruger #15732 @ 04.03.10 17:13
Fold kodeboks ind/udKode 
User
Bruger #15938 @ 22.06.10 15:44
Download: " Qt Creator "

- for at lave din egen Gui/ Graphical user interface med c++

Nemt og lækkert ;)
User
Bruger #14633 @ 13.09.10 15:00
Med Wine kan programmet linkes og koeres i Mac og mange POSIX-systemer.

Bemaerk at GDI er foraeldet af Microsoft til fordel for Direct2D.
Du skal være logget ind for at skrive en kommentar.
t