Johdanto GUI-ohjelmointiin wxWidgets-kirjastolla
Mureakuha
Sisällysluettelo |
Mikä on wxWidgets ja miksi käyttää sitä?
WxWidgets on C++-GUI-kirjasto, joka peittää todellisen rajapinnan. Hieman samantapaisia kirjastoja ovat mm. Microsoftin MFC ja Borlandin VCL, mutta suurin ero näiden ja wxWidgetsin välillä on se, että wxWidgets-kirjasto toimii usealla käyttöjärjestelmällä. Tällä hetkellä tuettuina ovat mm. Windows (95 tai uudempi), Unixit ja variantit (GTK+ tai Motif), MacOS, Mac OS X ja OS/2.
Oikein kirjoitettuna sama koodi kääntyy suoraan mille tahansa näistä alustoista. Poiketen useimmista usean käyttöjärjestelmän GUI-kirjastoista, wxWidgets käyttää alustan omia "widgettejä", eli GUI-elementtejä, kuten painonappeja ja tekstikenttiä. Tämän ansiosta wxWidgets-ohjelma näyttää ja tuntuu periaatteessa samanlaiselta, mihin käyttäjä on muita sovelluksia käyttäessään tottunut.
WxWidgets on varteenotettava vaihtoehto yleisesti käytetyille abstraktiokirjastoille, kuten edellä mainituille MFC:lle ja VCL:lle, ja varsinkin alustan omalle ohjelmointirajapinnalle (esim. WinAPI), vaikka et sovellustasi tähtäisikään kuin yhdelle järjestelmälle. WxWidgetsin API on suhteellisen siististi ja loogisesti toteutettu, ja se sisältää monia ohjelmointia helpottavia ominaisuuksia. WxWidgets on lisäksi avoin ja ilmainen kirjasto, joka LGPL:n kaltaisen lisenssinsä ansiosta sopii myös kaupallisiin sovelluksiin.
Vaikka wxWidgets yleensä mielletään pääasiassa GUI-kirjastoksi, siinä on monia apuluokkia, jotka helpottavat sovelluksen kehittämisessä ja sen siirrettävyyden takaamisessa. Esimerkkinä ZIP-tiedostojen käsittely ja säikeet.
Mitä tarvitsen seuratakseni artikkelia?
wxWidgets on C++-kirjasto, joten tarvitset siitä ainakin perustiedot. Jos haluat kääntää artikkelissa esitetyt koodit, tarvitset C++-kääntäjän (esim. g++) ja wxWidgets-kirjaston.
Itse käytän G++-kääntäjää Debian Linuxilla ja wxWidgets-versioni (GTK+) on 2.6.1, mutta pyrin kertomaan asiat ympäristöriippumattomasti, joten selviät luultavasti myös muunlaisella kokoonpanolla. Kirjastosta pitäisi API-muutosten takia olla vähintään 2.4.*-versio.
WxWidgetsin asennusohjeita eri alustoille:
- Linux </dt>
- Paketit todennäköisesti löytyvät oman distrosi paketinhallinnasta, jos eivät, katso kohta "Kääntäminen".
Debianissa toimii tuttu ja turvallinen
apt-get install libwxgtk2.4-dev</dd>
- Windows
- wxWidgets DevPakit Dev-C++:lle.
Kääntäminen
Linuxilla kääntäminen on varsin yksinkertaista, jos on kaikki tarvittavat kirjastot. Kääntäminen GTK+2-version kanssa menee yksinkertaisimmin näin:
./configure --with-gtk=2 make make install ldconfig
Jos jotain tuntuu puuttuvan, asenna GTK+2:n dev-paketit (Debianissa libgtk2.0-dev). Kääntämisessä voit käyttää erilaisia vipuja, jotka on lueteltu INSTALL tai install.txt-tiedostossa. Tässä kuitenkin muutama:
- --enable-unicode
- Käännä wxWidgets käyttämään Unicodea
- --with-opengl
- Käännä mukaan OpenGL-tuki
- --enable-debug
- Lisää debug-informaatiota ohjelmiin debuggereita (kuten gdb) varten sekä määrittelee makrot __DEBUG__ ja __WXDEBUG__. Tätä vipua kannattaa käyttää lähes aina.
wxWidgets-ohjelmien rakenne
Kaikki wxWidgets-ohjelmat toteuttavat wxApp-luokasta periytetyn luokan, jolla on julkinen (public) metodi OnInit (tähän tosin on poikkeuksia, mutta ne eivät tässä vaiheessa ole merkityksellisiä). OnInit-metodia kutsutaan ohjelman alussa, joten sen voi kuvitella olevan vastaava kuin main-funktio tavallisissa C/C++-ohjelmissa. Oikeasti wxWidgets toteuttaa sisäisesti main- tai WinMain-funktion, joka kutsuu OnInit-metodia, mutta se ei ole olennaista tämän artikkelin kannalta.
OnInit ei ota parametreja ja palauttaa bool-arvon, jonka tulee olla tosi (TRUE), jos alustus onnistui ja epätosi (FALSE) alustuksen epäonnistuessa. Minimaalinen "App-luokka" on siis seuraavan kaltainen:
class MyApp : public wxApp { public: bool OnInit(); private: MyFrame *m_frame; // Selitetään seuraavassa };
Pelkkä MyApp ei kuitenkaan tee juuri mitään, joten periytämme myös toisen luokan luokasta wxFrame. WxFrame-luokka edustaa ikkunaa, jolla on yleensä otsikkopalkki (title bar), reunukset, joista ikkunan kokoa voi muuttaa (borders) yms.
Esimerkki tällaisesta ikkunasta:
Ikkunaan asetetaan "widgetit" yleensä konstruktorissa, jota kutsutaan, kun MyApp::OnInit-metodissa luodaan instanssi MyFrame-luokasta. Widgetin tekemiseksi riittää yleensä pelkästään uuden olion luominen.
wxFramen konstruktori on seuraavanlainen:
wxFrame::wxFrame(wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_FRAME_STYLE, const wxString& name = "frame");
Älä tässä vaiheessa välitä parametreista, joille on annettu oletusarvo.
Ensimmäinen parametri (wxWindow *parent) on osoitin parent-olioon. Tämä on yleensä se olio, johon widgetti sijoitetaan. Tässä tapauksessa MyFrame on hierarkiassa ylin ikkuna, joten voimme antaa parentille NULL-osoittimen.
Toinen parametri on widgetin ID. Älä huolehdi tästäkään tässä vaiheessa. Annamme sille arvon -1, jolloin se saa oletus ID:n.
Kolmas parametri määrittää framen otsikkotekstin.
MyFrame-luokka voisi näyttää vaikkapa tältä:
class MyFrame : public wxFrame { public: MyFrame(wxWindow *parent, wxWindowID id, const wxString &title); private: wxStaticText *m_text; // Selitetään myöhemmin };
Kuten mainitsin jo aikaisemmin, widgetin näytölle saattamiseen riittää pelkästään olion luominen. Tässä esimerkki:
MyFrame::MyFrame(wxWindow *parent, wxWindowID id, const wxString &title) : wxFrame(parent, id, title) { m_text = new wxStaticText( this, -1, wxT("Hello World") ); }
Koodissa käytetään merkkijonon ympärillä wxT-makroa. Jos makroa ei käytetä tulee seuraavankaltaisia virheitä, jos käytössä on Unicode-build:
conversion from `const char[11]' to `const wxString' is ambiguous
Makroa tulisi kuitenkin aina käyttää, koska silloin koodi on porttautuvampaa myöhemmin. Katso myös [1].
wxStaticText näyttää sille annetun tekstin (tässä tapauksessa "Hello World") parent-ikkunassa, joka on tässä tapauksessa this, eli MyFramen instanssi. MyFramen widgetit tuhotaan automaattisesti wxFramen destruktorissa, joten meidän ei tarvitse huolehtia niiden siivoamisesta. WxStaticTextin konstruktori on hyvin samankaltainen kuin wxFramen:
wxStaticText::wxStaticText(wxWindow* parent, wxWindowID id, const wxString& label, const wxPoint& pos, const wxSize& size = wxDefaultSize, long style = 0, const wxString& name = "staticText");
Palataan vielä MyApp-luokkaan ja sen OnInit-metodiin, jota voi pitää ohjelman alkupisteenä. Siinä luomme olion MyFrame-luokasta ja asetamme sen ohjelman "pääikkunaksi":
bool MyApp::OnInit() { m_frame = new MyFrame( NULL, -1, wxT("Hello!") ); SetTopWindow(m_frame); m_frame->Show(TRUE); return TRUE; }
Lisäksi wxWidgetsin pitää tietää, mikä "app-luokkamme" on. Tämä tehdään IMPLEMENT_APP-makrolla:
IMPLEMENT_APP(MyApp)
Tarvittavat määrittelyt löytyvät tiedostosta , eli alkuun:
#include <wx/wx.h>
Windowsilla kääntäessäsi tarvitset myös resurssitiedoston, joka ei tässä tapauksessa ole sen kummoisempi kuin:
#include "wx/msw/wx.rc"
Kääntäminen
Esimerkin koodi on kuhan koodikirjastossa.
Linuxilla (ja luultavasti muillakin unix-järjestelmillä) kääntäminen käy helposti wx-config-apuohjelman avulla (tulee wxWidgetsin mukana). Itse käänsin koodin rimpsulla:
g++ -Wall -ansi -pedantic `wx-config --libs --cppflags` -owxhello wxhello.cpp
Windowsille ei ikävä kyllä wx-config-ohjelmaa ole, joten käytämme Makefileä. Makefile MinGW:lle (toiminee myös cygwinillä). HUOM! Jotta kyseinen makefile toimisi, tulee tiedostojen nimet olla seuraavat: Itse koodi: wxhello.cpp Resurssitiedosto: wxhello_resources.rc Makefile: Makefile Tiedostojen tulee sijaita samassa hakemistossa. Kääntäminen onnistuu kirjoittamalla yksinkertaisesti 'make' (ilman hipsuja tietenkin). Muille kääntäjille (ja myös MinGW:lle) on makefilet wxWidgetsin mukana tulevissa esimerkeissä.
Macista en ikävä kyllä tiedä juuri mitään, joten en osaa antaa ohjeita sille.
Jos kaikki onnistuu, ohjeman tulisi avata seuraavankaltainen ikkuna:
Loppusanat
Kuten varmaan huomasit, tämä artikkeli ei vielä kertonut kovin paljoa wxWidgetsistä. Tarkoitus on tehdä tästä aiheesta artikkelisarja, jos lukijoilla on mielenkiintoa.
Voit kommentoida myös itse artikkelia koodikirjastossa.
Yhteystietoni löytyvät mm. sisällöntuottajat-sivulta. Parhaiten tavoitat minut #mureakuha-kanavalla IRCnetissä, jossa lorvailen nickillä Theril.
Linkit
- Dokumentaatiot eri versioihin.
- wxWidgets DevPakit Dev-C++:lle
- Dev-C++, johon on lisätty wxWidgetsiä varten GUI-editori


