OMNIA AMMATTIOPISTO PÄÄTTÖTYÖ YKSINKERTAISEN C-KIELISEN GRAAFISEN KÄYTTÖLIITTYMÄN LUONTI Nro 2010-SLE06L OMNIAN AMMATTIOPISTO KOULUTUSALA Sähkö, elektroniikka- ja tietoliikennetekniikka OPISKELIJA Riki Uusoksa OHJAAJA Erkki Viiala VUOSI 2010
3 OMNIAN AMMATTIOPISTO TIIVISTELMÄ Ala Sähköala Tekijä Riki Uusoksa Koulutusohjelma Elektroniikka ja tietoliikennetekniikka Työn nimi Yksinkertaisen C-kielisen graafisen käyttöliittymän luonti Sivumäärä 21 Työn nro 2010-SLE06L Vuosi 2010 Ohjaaja Erkki Viiala Työ sisältää johdannot C-kieleen ja graafisiin ympäristöihin, joiden jälkeen selvitän tavan luoda yksinkertaisen graafisen käyttöliittymän C-kielellä. Hakusana Ohjelmointi, C, grafiikka
4 SISÄLLYSLUETTELO Johdanto...4 1 Johdanto C-kieleen...5 1.1 C-kielen vaikuttajat ja mihin C-kieli on vaikuttanut...5 1.2 C-kielen toiminta...5-6 1.3 C-kielen standardikirjastot...6-7 2 Johdanto graafiseen ulkoasuun...7-8 2.1 Graafisen käyttöliittymän historia...8 3 Yksinkertaisen graafisen käyttöliittymän ohjelmointi C-kielellä WIN32 API-pohjalta...8 3.1 Ikkunan luominen...8-10 3.1.1 Window Classin rekisteröinti...10-11 3.1.2 Ikkunan luominen...11-12 3.1.3 Viesti-loop...12 3.1.4 Ikkunan ohjausprosessit...13 3.2 Ajonaikaisen menun luominen...13-15 3.3 Dialogi-ikkunat...15-18 3.3.1 Mooditon dialogi-ikkuna...18-19 3.4 Muokattava tekstikenttä...20 4 Lähteet...21
5 JOHDANTO Työn tarkoitus on johdattaa lukija C-kieleen ja graafisiin käyttöympäristöihin, jonka jälkeen esitän tavan jolla voit C-kielellä luoda yksinkertaisen graafisen käyttöliittymän.
6 1 JOHDANTO C-KIELEEN C on perustavanlaatuinen ohjelmointikieli joka kehitettiin vuonna 1972 Dennis Ritchien toimesta käytettäväksi Unix-käyttöjärjestelmässä. Vaikka C kehitettiin järjestelmäohjelmointiin, sitä käytetään usein myös sovellusohjelmointiin. C on yksi yleisimmin käytetyistä ohjelmointikielistä ja on hyvin vähän järjestelmiä, joista C-kääntäjää ei löydy. 1.1 C-KIELEN VAIKUTTAJAT JA MIHIN C-KIELI ON VAIKUTTANUT C-kieli on ottanut vaikutteita esimerkiksi semmoisista ohjelmointikielistä kuin B (BCPL, CPL), ALGOL 68, Assembly, PL/I, FORTRAN ja itse vaikuttanut senkaltaisten ohjelmointikielien syntyyn kuin AWK, csh, C++, C--, C#, Objective-C, BitC, D, Go, Java, JavaScript, Limbo, Perl, PHP, Pike, Processing ja Python. 1.2 C-KIELEN TOIMINTA C on proseduraalinen järjestelmätoteutuksiin tarkoitettu kieli. Se luotiin käännettäväksi suhteellisen yksinkertaisella kääntäjällä, jolla mahdollistetaan matalan tason muistinkäyttö, kielirakenteet jotka kartoittavat tehokkaasti laitteen antamat ohjeet ja joka vaatii minimaalisen määrän suoritustukea. (kts. ohjelman kirjoittamisen jälkeistä tukea c-kääntäjältä) Huolimatta sen matalan tason mahdollisuuksista, kieli tarkoitettiin rohkaisemaan järjestelmäriippumatonta ohjelmointia. C-kielen standardisoidut kirjastot mahdollistavat käytön laajassa valikoimassa laitteistoja ja käyttöjärjestelmiä vaatien vähän tai olemattoman määrän muutoksia sen lähdekoodiin. Kieltä käytetään nykyään melkein kaikkialla, sulautetuista mikrokontrollereista supertietokoneisiin. C-kieli mahdollistaa osoitettujen objektien (kts. esim. muistiin tallennettujen laitehallintarekisterien) helpon ja suoran käytön. C-kieli myös mahdollistaa argumenttien osoittamisen (esim. int p; joka tekee argumentista p int-tyyppisen muuttujan.) C-kieli tukee suurta määrää operaattoreita, jotka ovat symboleja joita käytetään lausekkeessa määrittelemään suoritteet arvioidessa kyseistä lauseketta. C käsittää operaattorit: * aritmaattiset (+, -, *, /, %)
7 * samanarvoisuuden testaus (==,!=) * arvosuhteet (<, <=, >, >=) * Boolean loogiset (!, &&, ) * bittiloogiset (~, &,, ^) * bittien siirrot (<<, >>) * tehtävät (=, +=, -=, *=, /=, %=, &=, =, ^=, <<=, >>=) * lisäys ja vähennys (++, --) * suhteellisuus ja vertaus (&, *, [ ]) * määrittelyn arviointi (? :) * jäsenvalinta (., ->) * tyyppimuunnos (( )) * objektin koko (sizeof) * function argumenttien kokoelma (( )) * listaaminen (,) * lausekkeen jäsentely (( )) C:llä on muodolline C-standardin mukainen kielirakenne. 1.3 C-KIELEN STANDARDIKIRJASTOT, SEKÄ YLEISIMMIN KÄYTETYT EI-STANDARDIT KIRJASTOT JA NIIDEN SISÄLTÄMÄT FUNKTIOT assert.h assert-makro complex.h cabs, cacos, cacosh, carg, casin, casinh, catan, catanh, ccos, ccosh, cexp, cimag, cis, clog, conj, cpow, cproj, creal, csin, csinh, csqrt, ctan, ctanh ctype.h digittoint, isalnum, isalpha, isascii, isblank, iscntrl, isdigit, isgraph, islower, isprint, ispunct, isspace, isupper, isxdigit, toascii, tolower, toupper errno.h, float.h, iso646.h, limits.h ei funktioita inttypes.h imaxabs, imaxdiv, strtoimax, strtoumax, wcstoimax, wcstoumax locale.h localeconv, setlocale math.h acos, asin, atan, atan2, atof, ceil, cos, cosh, exp, fabs, floor, frexp, ldexp, log, log10, modf, pow, sin, sinh, sqrt, tan, tanh netdb.h getaddrinfo, getnameinfo
8 setjmp.h longjmp, setjmp signal.h raise stdarg.h va_arg, va_copy, va_end, va_start-makrot stddef.h offsetof-makro stdio.h clearer, fclose, feof, ferror, fflush, fgetc, fgetpos, fgets, fopen (myös freopen, fdopen), printf (myös fprintf, sprintf, snprintf), fputc, fputs, fread, fscanf, fseek, fsetpos, ftell, fwrite, getc-makro, getchar-makro, gets, perror, putc-makro, putchar ja fputchar-makrot, puts, remove, rename, rewind, scanf (myös fscanf, sscanf, vfscanf, vscanf, vsscanf), setbuf, setvbuf, tmpfile, tmpnam, ungetc, vprintf (myös vfprintf, vsprintf) stdlib.h abort, abs (myös labs), atexit, atof, atoi, atol, bsearch, div (myös ldiv), exit, free, itoa, getenv, ltoa, malloc (myös calloc, realloc), qsort, rand, srand, strtod, strtol, strtoul, system string.h memchr, memcmp, memcpy, memmove, memset, strcat (myös strncat), strchr, strcmp (myös strncmp), strcoll, strcpy (myös strncopy), strcspn, sterror, strlen, strpbrk, strrchar, strspn, strstr, strtok, strxfrm time.h asctime, clock, ctime, difftime, gmtime, localtime, mktime, strftime, time alloc.h farmalloc conio.h getch, getche, gotoxy 2 JOHDANTO GRAAFISEEN ULKOASUUN Graafisella ulkoasulla viitataan käyttöliittymään, joka antaa käyttäjälleen mahdollisuuden ohjata sovelluksia muillakin tavoin kuin tekstikomennoilla kuten tietokoneissa, mp3-soittimissa, pelikonsoleissa ja kodinkoneissa. Informaation ja käyttömahdollisuuksien ilmoittamiseen graafinen käyttöliittymä tarjoaa graafisia ikoneita ja visuaalisia ohjastuksia (painikkeita yms.) tekstipohjaisen
9 liittymän komento-ohjauksien ja tekstipohjaisen navigoinnin sijaan. Tapahtumat suoritetaan yleensä graafisten elementtien suoralla manipuloinnilla. 2.1 GRAAFISEN KÄYTTÖLIITTYMÄN HISTORIA Graafisten käyttöliittymien edeltäjä kehitettiin Stanford Research Instituutin tutkijoiden toimesta, joita johti Douglas Engelbart. He kehittivät tekstipohjaisten hyperlinkkien käytön hiirellä ohjattavaksi NLS:ää varten. Hyperlinkkien käsite jalostettiin ja laajennettiin käsittämään grafiikoita Xerox PARCin tutkijoiden toimesta, jotka tekstipohjaisten hyperlinkkien sijaan käyttivät graafista pohjaa pääasiallisena käyttöliittymänä Xerox Alto tietokoneessa. Useimmat nykyiset peruskäyttöön tarkoitetut graafiset käyttöliittymät perustuvat tähän systeemiin. Tästä johtuen jotkut kutsuvat tämäntyylistä käyttöliittymää PARC User Interfaceksi (PUI) yleisemmin käytetyn Graphical User Interface (GUI) sijaan. Ivan Sutherland kehitti Sketchpadiksi kutsutun osoitinpohjaisen systeemin 1963. Se käytti valokynää ohjaamaan rakennuspiirrosten objektien luomista ja manipulaatiota. Xerox Star Workstation esitteli ensimmäisen GUI-käyttöliittymän vuonna 1981. 3 YKSINKERTAISEN GRAAFISEN KÄYTTÖLIITTYMÄN OHJELMOINTI C- KIELELLÄ WIN32 API-POHJALTA 3.1 IKKUNAN LUOMINEN #include <windows.h>
const char g_szclassname[] = "mywindowclass"; (tallettaa Window Class nimen) //3.1.4: Ikkunan ohjausprosessit LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) switch(msg) case WM_CLOSE: DestroyWindow(hwnd); case WM_DESTROY: PostQuitMessage(0); default: return DefWindowProc(hwnd, msg, wparam, lparam); return 0; int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int ncmdshow) WNDCLASSEX wc; HWND hwnd; MSG Msg; //3.1.1: Window Classin rekisteröinti wc.cbsize = sizeof(wndclassex); wc.style = 0; wc.lpfnwndproc = WndProc; wc.cbclsextra = 0; wc.cbwndextra = 0; wc.hinstance = hinstance; wc.hicon = LoadIcon(NULL, IDI_APPLICATION); wc.hcursor = LoadCursor(NULL, IDC_ARROW); wc.hbrbackground = (HBRUSH)(COLOR_WINDOW+1); wc.lpszmenuname = NULL; wc.lpszclassname = g_szclassname; wc.hiconsm = LoadIcon(NULL, IDI_APPLICATION); if(!registerclassex(&wc)) MessageBox(NULL, "Window Registration Failed!", "Error!", MB_ICONEXCLAMATION MB_OK); return 0; //3.1.2: Ikkunan luominen 10
11 hwnd = CreateWindowEx( WS_EX_CLIENTEDGE, g_szclassname, "The title of my window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 240, 120, NULL, NULL, hinstance, NULL); if(hwnd == NULL) MessageBox(NULL, "Window Creation Failed!", "Error!", MB_ICONEXCLAMATION MB_OK); return 0; ShowWindow(hwnd, ncmdshow); UpdateWindow(hwnd); //3.1.3: Viesti-loop while(getmessage(&msg, NULL, 0, 0) > 0) TranslateMessage(&Msg); DispatchMessage(&Msg); return Msg.wParam; 3.1.1 WINDOW CLASSIN REKISTERÖINTI Window Class säilyttää tiedot ikkunan tyypistä, sisältäen sen ohjausprosessit jotka kontrolloivat ikkunaa, pienet ja suuret ikonit ikkunalle ja taustavärin. Tällä tavoin voit rekisteröidä classin kerran, ja luoda niin monta samanlaista ikkunaa kuin vain haluat, ilman että sinun tarvitsee eritellä nämä attribuutit uudelleen ja uudelleen. Ne voi myös vaihtaa ikkunakohtaisesti jos näin haluat. Rakenteen jäsenet jotka vaikuttavat Window Classiin ovat seuraavat: cbsize Rakenteen koko. style
12 Class Styles (CS_*), ei tule sekoittaa Window Styles (WS_*) kanssa. Voi yleensä asettaa arvon 0. lpfnwndproc Ikkunan ohjausprosessin osoitin tälle Window Classille. cbclsextra Määrä ekstradataa, joka muistista asetetaan sivuun tätä Classia varten. Yleensä 0 cbwndextra Määrä ekstradataa, joka muistista asetetaan sivuun tämän tyyppistä ikkunaa varten. Yleensä 0. hinstance Handle (älykäs osoitin, abstrakti referenssi jota toinen systeemi ohjaa) toiseen ohjelmaan, jonka saimme WinMain()ensimmäisessä parametrissa. hicon Suuri, yleensä 32x32 ikoni, joka näytetään käyttäjän painaessa Alt+Tab. hcursor Kursori, joka näytetään ikkunamme yllä. hbrbackground Asettaa ikkunamme taustavärin. lpszmenuname Menu-resurssin nimi jota käytetään tämän Classin ikkunoille. lpszclassname Nimi, jolla Classimme tunnistetaan hiconsm Pieni, yleensä 16x16 ikoni, joka näytetään tehtäväpalkissa ja ikkunamme vasemmassa ylänurkassa. 3.1.2 IKKUNAN LUOMINEN Kun Class on rekisteröity, voimme luoda sillä ikkunan. Ensimmäinen parametric (WS_EX_CLIENTEDGE) on jatkettu ikkunan tyyli. Tässä esimerkissä se on asetettu antamaan upotettu sisempi reunus ikkunalle. Seuraavaksi meillä on Classin nimi (g_szclassname). Tämä kertoo systeemille minkäkaltaisen ikkunan haluamme luoda. Koska halusimme luoda ikkunan
13 rekisteröimästämme tyylistä, käytimme sen Classin nimeä. Tämän jälkeen meillä tulee ikkunan nimi ( the title of my window ) WS_OVERLAPPEDWINDOW on Window Style parametri. Näitä on monia erilaisia. Seuraavat neljä parametria (CW_USEDEFAULT, CW_USEDEFAULT, 320,240) ovat X ja Y koordinaatit ikkunamme vasemmalle ylänurkalle sekä ikkunamme leveys ja korkeus. CW_USEDEFAULT sallii Windowsin määrätä mihin se asettaa ikkunan. Ikkunan leveys kasvaa vasemmalta oikealle ja korkeus ylhäältä alas. Yksiköt ovat pikseleitä. Seuraavaksi (NULL, NULL, g_hinst, NULL) meillä on isäntäikkunan Handle, menun Handle, toisen ohjelman Handle ja osoitin ikkunan luomisen dataan. Windowsissa ikkunat ovat järjestetty Isäntä- ja lapsi-ikkuna hierarkiaan. Kun näet ikkunassa nappulan, se on Lapsi ja se on asetettu sen Isäntäikkunan sisään. Esimerkissämme Isäntä-handle on NULL, sillä ikkunalla ei ole isäntää, vaan tämä on pääikkunamme. Menu on asetettu NULL, sillä meillä ei vielä ole sitä. Toisen ohjelman handle on asetettu siihen, jonka saamme WinMain() ensimmäisestä parametrista. Kun olemme luoneet ikkunan ja tarkistaneet että meillä on oikea Handle, näytämme ikkunan käyttämällä WinMain() viimeistä parametria ja sitten päivitämme sen varmistaaksemme että ikkuna on kunnolla piirtänyt itsensä näytölle. (ShowWindow(hwnd, ncmdshow); UpdateWindow(hwnd);) 3.1.3 VIESTI-LOOP Tämä on ohjelmasi sydän. Periaatteessa kaikki mitä ohjelmasi tekee käy tämän tarkistuspisteen kautta. GetMessage() ottaa viestin ohjelmasi viestijonosta. Joka kerran kun käyttäjä siirtää hiirtä, näppäilee näppäimistöä, klikkaa ikkunasi menua tai tekee mitä tahansa, systeemi luo viestejä ohjelmasi viestijonoon. Kutsumalla GetMessage(), pyydät seuraavan mahdollisen viestin poistettavaksi viestijonosta ja siirrettäväksi ohjelmallesi käsiteltäväksi. Jos viestejä ei ole jonossa, ohjelma odottaa GetMessage() funktiossa. TranslateMessage() suorittaa ylimääräistä prosessointia näppäimistön tapahtumista kuten mahdollistamalla WM_CHAR viestien toimimista WM_KEYDOWN viestien kanssa. Viimeiseksi, DispatchMessage() lähettää viestin ikkunalle jolle se lähettiin. Se voi olla pääikkunamme, joku toinen ikkuna, ohjain tai jossain tapauksissa ikkuna jonka systeemi tai toinen ohjelma loi kulissien taakse. Systeemi huolehtii viestien menemisestä perille oikeaan osoitteeseen.
14 3.1.4 IKKUNAN OHJAUSPROSESSIT Ohjausprosessit ovat ohjelmamme aivot. Täällä kaikki lähetetyt viestit prosessoituvat. Ohjausprosessit kutsutaan jokaiselle viestille erikseen. HWND parametri on kyseisen viestin kohdeikkunan handle. Tämä on tärkeä, sillä sinulla saattaa olla useita saman Classin ikkunoita jotka käyttävät samaa ohjausprosessia (WndProc()). Ero on siinä että parametri HWND on eri joka ikkunalle. Esimerkiksi lähettäessämme WM_CLOSE viestin, suljemme ikkunan. Koska käytämme ikkunan handlea, jonka saimme ensimmäisenä parametrina, muut ikkunat eivät sulkeudu, vaan vain se johon tarkoitimme WM_CLOSEn. WM_CLOSE lähetetään kun käyttäjä painaa Sulje-nappulaa tai näppäilee Alt-F4 Kutsuessamme DestroyWindow() systeemi lähettää viestin WM_DESTROY kyseiselle ikkunalle sulkien samalla kaikki jäljelle jääneet lapsi-ikkunat. Koska tämä on ohjelmamme ainoa ikkuna, olemme tämän jälkeen valmiit ja kutsumme PostQuitMessage(). Tämä lähettää WM_QUIT viestin viesti-looppiin ja lopettaa ohjelman. 3.2 AJONAIKAISEN MENUN LUOMINEN Voit koodiisi sisällyttää menun resursseista vaihtamalla Window Class määrittelyyn wc.lpszmenuname = MAKEINTRESOURCE(IDR_MYMENU); jossa IDR_MYMENU on kyseisen menuresurssin nimi. (.rc pääte) Tässä sen sijaan käsittelen ajonaikasta menua. Näin annamme WM_CREATE viestille Handlen ja lisäämme menun ikkunaamme #define ID_FILE_EXIT 9001 #define ID_STUFF_GO 9002 Aseta nämä kaksi IDtä.c-filesi huipulle, #include rivien alle. Seuraavaksi lisäämme WM_CREATE Handleemme seuraavan koodin: case WM_CREATE: HMENU hmenu, hsubmenu; HICON hicon, hiconsm; hmenu = CreateMenu(); hsubmenu = CreatePopupMenu(); AppendMenu(hSubMenu, MF_STRING, ID_FILE_EXIT, "E&xit"); AppendMenu(hMenu, MF_STRING MF_POPUP, (UINT)hSubMenu, "&File"); hsubmenu = CreatePopupMenu(); AppendMenu(hSubMenu, MF_STRING, ID_STUFF_GO, "&Go");
15 AppendMenu(hMenu, MF_STRING MF_POPUP, (UINT)hSubMenu, "&Stuff"); SetMenu(hwnd, hmenu); Tämä lisää yllä näkyvän kaltaisen menun ikkunaamme, ilman ikonia. Kyseinen menu on ajonaikainen, joten se lopetetaan automaattisesti kun ohjelma sulkeutuu. Nyt, kun meillä on menu, meidän tulee laittaa se tekemään jotain. Tämä on suhteellisen yksinkertaista, sillä meidän tulee vain asettaa WM_COMMAND viestille Handle ja tarkistaa mitä komentoja saamme menusta ja toimia sen mukaan. Tällä hetkellä WndProc() tulisi näyttää seuraavalta: LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wparam, LPARAM lparam) switch(message) case WM_CREATE: HMENU hmenu, hsubmenu; hmenu = CreateMenu(); hsubmenu = CreatePopupMenu(); AppendMenu(hSubMenu, MF_STRING, ID_FILE_EXIT, "E&xit"); AppendMenu(hMenu, MF_STRING MF_POPUP, (UINT)hSubMenu, "&File"); hsubmenu = CreatePopupMenu(); AppendMenu(hSubMenu, MF_STRING, ID_STUFF_GO, "&Go"); AppendMenu(hMenu, MF_STRING MF_POPUP, (UINT)hSubMenu, "&Stuff"); SetMenu(hwnd, hmenu); case WM_COMMAND: switch(loword(wparam)) case ID_FILE_EXIT: case ID_STUFF_GO:
16 case WM_CLOSE: DestroyWindow(hwnd); case WM_DESTROY: PostQuitMessage(0); default: return DefWindowProc(hwnd, Message, wparam, lparam); return 0; Oletettavasti haluamme Exit valikon sulkevan ohjelman, joten WM_COMMAND,ID_FILE_EXIT Handlerissa voit seuraavalla koodilla saada sen aikaiseksi: PostMessage(hwnd, WM_CLOSE, 0, 0); WM_COMMAND Handlerisi tulisi nyt näyttää tältä: case WM_COMMAND: switch(loword(wparam)) case ID_FILE_EXIT: PostMessage(hwnd, WM_CLOSE, 0, 0); case ID_STUFF_GO: Tällä hetkellä ID_STUFF_GO ei tee mitään. 3.3 DIALOGI-IKKUNAT Ensimmäinen askel dialogi-ikkunoiden luomiseen on luoda dialogille resurssitiedosto. (.rc pääte) Tässä esimerkki sen sisällöstä: IDD_ABOUT DIALOG DISCARDABLE 0, 0, 239, 66 STYLE DS_MODALFRAME WS_POPUP WS_CAPTION WS_SYSMENU CAPTION "My About Box" FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "&OK",IDOK,174,18,50,14 PUSHBUTTON "&Cancel",IDCANCEL,174,35,50,14 GROUPBOX "About this program...",idc_static,7,7,225,52 CTEXT "An example program showing how to use Dialog Boxes\r\n\r\nby theforger", IDC_STATIC,16,18,144,33 END
17 Ensimmäisellä rivillä IDD_ABOUTDLG on resurssin ID, DIALOG on resurssin tyyppi ja neljä seuraavaa numeroa (0, 0, 239, 66) ovat jo-käsitellyt koordinaatit ja koko, mutta dialogeissa ne ovat pikselien sijaan dialogi-yksiköitä, joiden koko perustuu käytettyyn fonttiin. Käyttäessäsi suurta fonttia, on dialogi-ikkuna suuri ja pientä fonttia käyttäessäsi on dialogi-ikkuna sen verran pienempi. Tämä on tärkeää, sillä se varmistaa, että kontrollisii ovat oikean kokoiset esittämään niiden sisältämän tekstin. DISCARDABLE kertoo systeemille, että se voi siirtää resurssimuistia levylle kun ohjelma ei ole käytössä, säästäen systeemin resursseja Toinen rivi alkaa STYLE ja sitä seuraa ikkunatyylit joita käytetään dialogin luomisessa. Käyttääksesi valmiiksi asetettuja tyylejä, joudut ehkä lisäämään #include "windows.h".rc tiedostoosi. Seuraavaksi meillä on lista kontrolleista, jotka luodaan dialogi-ikkunaan. DEFPUSHBUTTON "&OK",IDOK,174,18,50,14 Tämä rivi määrittelee OK-painikkeen. IDOK on painikkeen tunnistin. IDOK on valmiiksi määritelty, joten meidän ei tarvitse #define sitä itse. Neljä seuraavaa numeroa ovat taas koordinaatit, sekä leveys että pituus. Kaikki taas dialogiyksiköissä. Seuraavaksi meidän pitää kirjoittaa dialogille ohjausprosessi. Se on periaatteessa samankaltainen kuin ikkunan ohjausprosessi. BOOL CALLBACK AboutDlgProc(HWND hwnd, UINT Message, WPARAM wparam, LPARAM lparam) switch(message) case WM_INITDIALOG: return TRUE; case WM_COMMAND: switch(loword(wparam)) case IDOK: EndDialog(hwnd, IDOK); case IDCANCEL: EndDialog(hwnd, IDCANCEL);
18 default: return FALSE; return TRUE; Dialogin ohjausprosessissa ja ikkunan ohjausprosessissa on muutamia tärkeitä eroavaisuuksia jotka tulee tietää. Ensimmäiseksi, et kutsu DefWindowProc() viesteille, joita et käsittele. Dialogeissa tämä tapahtuu automaattisesti. Toiseksi, yleensä palautat FALSE viesteille joita et prosessoi ja TRUE viesteille jotka prosessoit, ellei viesti erittele, että palautat jotain muuta. Kolmanneksi, et kutsu DestroyWindow()sulkemaan dialogia, vaan sen sijaan EndDialog(). Toinen parametri on arvo, joka palautetaan DialogBox() kutsuttuun koodiin. Viimeiseksi, WM_CREATEn käsittelyn sijaan käsittelet WM_INITDIALOG tekemään prosessit joita vaaditaan ennen dialogin ilmestymistä, joka sitten palauttaa TRUE arvon keskittämään näppäimistön ensiarvoiseen painikkeeseen. Seuraavaksi dialogi-ikkunan luomiseen: case WM_COMMAND: switch(loword(wparam)) case ID_HELP_ABOUT: int ret = DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_ABOUT), hwnd, AboutDlgProc); if(ret == IDOK) MessageBox(hwnd, "Dialog exited with IDOK.", "Notice", MB_OK MB_ICONINFORMATION); else if(ret == IDCANCEL) MessageBox(hwnd, "Dialog exited with IDCANCEL.", "Notice", MB_OK MB_ICONINFORMATION); else if(ret == -1) MessageBox(hwnd, "Dialog failed!", "Error", MB_OK MB_ICONINFORMATION); // Muita menun valintoja..
19 Tämä tulee sijoittaa WM_COMMAND Handleriin. Koska haluamme pääikkunamme menun luovan dialogin, tulee koodi sijoittaa pääikkunamme WndProc()iin. IDD_ABOUT on dialogiresurssin ID. Hwnd on dialogin isäntäikkunan Handle. AboutDlgProc() on dialogin kontrolloimiseen tarkoitettu dialogiproseduuri. DialogBoxia käytettäessä pääikkunasi käyttö on evätty ennenkuin dialogi on päätetty. 3.3.1 MOODITON DIALOGI-IKKUNA Seuraavaksi käsittelemme CreateDialog() function. Erona näissä on se, että kun DialogBox() käsittää oman viesti-looppinsa eikä palaa pääikkunan viesti-looppiin ennenkuin dialogi suljetaan, käyttäytyy CreateDialog() ennemmin kuin ikkuna joka on luotu CreateWindowEx() siinä mielessä, että se palaa automaattisesti alkuperäiseen, odottaen viestiä aivan kuten pääikkunakin. Täten Mooditon, kun taas DialogBox() luo Modaalisia dialogeja IDD_TOOLBAR DIALOGEX 0, 0, 98, 52 STYLE DS_MODALFRAME WS_POPUP WS_CAPTION EXSTYLE WS_EX_TOOLWINDOW CAPTION "My Dialog Toolbar" FONT 8, "MS Sans Serif" BEGIN PUSHBUTTON "&Press This Button",IDC_PRESS,7,7,84,14 PUSHBUTTON "&Or This One",IDC_OTHER,7,31,84,14 END Seuraavaksi haluamme luoda dialogin sillä aikaa kun ohjelmamme on käynnissä. Haluamme myös asettaa globaalin muuttujan pitämään ikkunan Handlea palautumaan CreateDialog()ista, jotta voimme käyttää sitä myöhemmin. HWND g_htoolbar = NULL; case WM_CREATE: g_htoolbar = CreateDialog(GetModuleHandle(NULL),
20 MAKEINTRESOURCE(IDD_TOOLBAR), hwnd, ToolDlgProc); if(g_htoolbar!= NULL) ShowWindow(g_hToolbar, SW_SHOW); else MessageBox(hwnd, "CreateDialog returned NULL", "Warning!", MB_OK MB_ICONINFORMATION); Tarkistamme palautusarvon ja jos se on erisuuri kuin NULL, näytämme ikkunan ShowWindow() funktiolla. Seuraavaksi tarvitsemme dialogiproseduurin työkalupalkkiimme: BOOL CALLBACK ToolDlgProc(HWND hwnd, UINT Message, WPARAM wparam, LPARAM lparam) switch(message) case WM_COMMAND: switch(loword(wparam)) case IDC_PRESS: MessageBox(hwnd, "Hi!", "This is a message", MB_OK MB_ICONEXCLAMATION); case IDC_OTHER: MessageBox(hwnd, "Bye!", "This is also a message", MB_OK MB_ICONEXCLAMATION); default: return FALSE; return TRUE;
21 3.4 MUOKATTAVA TEKSTIKENTTÄ Yksi yleisimmin käytetyistä kontrolleista Windows-ympäristössä on EDIT, kontrolli joka sallii käyttäjän syöttää, muokata, kopioida jne. tekstiä. Esim. Windows Notepad. SetDlgItemText(hwnd, IDC_TEXT, "This is a string"); Näin saat muokattua kontrollin sisältämää tekstiä. Tekstin palauttaminen kontrollista vaatii hieman enemmän työtä. int len = GetWindowTextLength(GetDlgItem(hwnd, IDC_TEXT)); if(len > 0) int i; char* buf; buf = (char*)globalalloc(gptr, len + 1); GetDlgItemText(hwnd, IDC_TEXT, buf, len + 1); //... do stuff with text... GlobalFree((HANDLE)buf); Ensiksikin meidän tulee laittaa syrjään muistia tekstin tallettamista varten. Tätä varten meidän tulee tietää kuinka paljon muistia siirtää syrjään GetWindowTextLength()tekee tämän, joten meidän täytyy saada Handle kontrollille käyttämällä GetDlgItem(). Nyt kun meillä on pituus, voimme siirtää syrjään muistia. Tähän käytämme GlobalAlloc() GetWindowTextLength()palauttaa syötettyjen kirjaimien määrän, jotka kontrolli sisältää. Viimeiseksi kutsumme GetDlgItemText() noutamaan kontrollin sisällön muistibufferiin jonka juuri varasimme Tämän jälkeen käytämme GlobalFree() vapauttamaan varaamamme muistin. Siinä muutama yksinkertainen graafinen elementti c-kieliseen ohjelmaan.
22 4 LÄHTEET http://en.wikipedia.org/wiki/list_of_c_functions http://en.wikipedia.org/wiki/c_%28programming_language%29 http://en.wikipedia.org/wiki/graphical_user_interface http://www.fanboy.com/wp-content/uploads/2009/02/xerox-star-interface.jpg http://www.winprog.org/tutorial/ (theforger s WIN32 API tutorial)