Programowanie graficznego interfejsu użytkownika Wykład 6 Maciej Wołoszyn mailto:woloszyn@fatcat.ftj.agh.edu.pl 5 kwietnia 2006 Spis treści 1 wxwidgets c.d. 1 1.1 Prekompilowane pliki nagłówkowe (PCH)................... 1 1.2 Model okna................................... 2 1.3 Tworzenie i usuwanie okien.......................... 3 1.4 Wybrane widgety................................ 4 1.5 Rozmieszczanie widgetów........................... 7 1.5.1 Dostępne układy............................ 8 1 wxwidgets c.d. 1.1 Prekompilowane pliki nagłówkowe (PCH) w celu przyspieszenia procesu kompilacji można skorzystać z prekompilowanych plików nagłówkowych (jeśli używamy kompilatora dającego taką możliwość) należy wydzielić w tym celu plik nagłówkowy (najwyżej jeden na jednostkę kompilacji) i skompilować go z opcjami identycznymi jak używane do kompilowania plików źródłowych Proszę o przesyłanie na ten adres informacji o znalezionych błędach, literówkach oraz propozycji zmian i uzupełnień. Dokument przygotowano za pomocą systemu LATEX. Prawa autorskie zastrzeżone. 1
Programowanie GUI Wykład 6 2 Przykład dla kompilatora gcc 1 : P01.h #include <wx/wx.h> $ g++ wx-config --cxxflags -D_REENTRANT -c P01.h plik P01.h.gch ( 35 MB) P01.cpp #include "P01.h" class MyFrame : public wxframe { //... $ g++ wx-config --cxxflags --libs P01.cpp 1.2 Model okna okno to obszar, który może: sposób kompilacji czas [s] zwykły 11.2 PCH 2.2 zawierać inne okna (w tym paski menu, narzędzi, statusu) być ukryty lub uwidoczniony dopuszczać zmianę rozmiaru narysować się zwykle jest skojarzony z obiektem klasy wxwindow lub potomnej rozmiar okna określa wymiary zewnętrzne (zawiera w sobie dekorację okna itp.) obszar wewnętrzny (client area) to część okna, węwnątrz której można rysować albo umieszczać inne okna tylko okna na najwyższym poziomie hierarchii (top-level windows, np. wxframe, wxdialog) mogą być tworzone z wartością NULL jako wskaźnik do okna macierzystego 1 Powody użycia makra _REENTRANT są omówione np. pod adresem http://gcc.gnu.org/bugzilla/ show_bug.cgi?id=11953 (dotyczy tylko gcc<4.1); w razie problemów przydatna opcja -Winvalid-pch
Programowanie GUI Wykład 6 3 1.3 Tworzenie i usuwanie okien najczęściej widgety tworzone są operatorem new: w jednym kroku wxbutton* b = new wxbutton(parent,wxid_ok); za pomocą dwóch instrukcji: konstruktora domyślnego oraz funkcji Create przyjmującej takie same argumenty jak pełny konstruktor wxbutton* b=new wxbutton; b->create(parent,wxid_ok); w drugim przypadku dopiero uruchomienie Create powoduje utworzenie widgetu gotowego do wyświetlenia (i wygenerowanie zdarzenia wxevt_create) można wcześniej określić dodatkowe właściwości obiektu przekazanie wskaźnika do okna macierzystego zapewnia dołączenie do niego bieżącego obiektu zostanie on automatycznie usunięty gdy niszczony jest rodzic wszystkie widgety za wyjątkiem tych na najwyższym poziomie hierarchii (wxframe, wxdialog) tworzone są jako widoczne będą więc widoczne, jeśli rodzic jest widoczny można je ukryć wywołując Show(false) wxframe oraz wxdialog nie są po utworzeniu wyświetlane aby umożliwić rozmieszczenie w nich innych widgetów bez niepożądanych efektów wizualnych (np. migotania) są wyświetlane dopiero po użyciu Show lub dla okien modalnych ShowModal okna typu top-level likwiduje się w bezpieczny sposób uruchamiając metodę Destroy, co zapewnia obsłużenie wszystkich oczekujących zdarzeń przed ostatecznym usunięciem obiektu dołączone do okna macierzystego widgety (typu child) rzadko są likwidowane bezpośrednio zostaną usunięte wraz z usunięciem rodzica do typowych argumentów konstruktorów okien należą (poza wskaźnikiem do okna macierzystego): identyfikator (wartość typu wxwindowid, np. wxid_any) pozycja (wxpoint, domyślna wartość wxdefaultposition) rozmiar (wxsize, domyślnie wxdefaultsize) nazwa (wxstring, rzadko używana poza środowiskami Motif i Xt)
Programowanie GUI Wykład 6 4 styl (long, domyślnie 0) pozwala określić szczegóły wyglądu okna za pomocą stałych połączonych bitowym OR, np. wxcaption wxminimize_box oprócz styli odziedziczonych po klasie wxwindow widgety w większości dodają kolejne style 1.4 Wybrane widgety klasy podstawowe: okna: wxwindows bazowa dla wszystkich okien (widgetów); bardzo duży zbiór funkcji składowych wxcontrol bazowa dla elementów sterujących, takich jak np. wxbutton wxcontrolwithitems j.w., ale dla elementów składających się z wielu pozycji wxframe skalowalne okno mogące zawierać inne widgety; często używane do tworzenia głównego okna programu wxdialog skalowalne okno wyboru wxpopupwindow minimalna ilość dekoracji okna wxmdiparentframe, wxmdichildframe (MDI = Multiple Document Interface, przestarzały?) Przykład: class MyFrame: public wxmdiparentframe { public: MyFrame(const wxstring& title); }; MyFrame::MyFrame(const wxstring& title) : wxmdiparentframe(null,wxid_any,title){ wxmdichildframe* child = new wxmdichildframe(this,wxid_any,"child"); child->show(true); } class MyApp: public wxapp { virtual bool OnInit(); };
Programowanie GUI Wykład 6 5 bool MyApp::OnInit() { MyFrame *frame = new MyFrame( "P02"); frame->show(true); return true; } IMPLEMENT_APP(MyApp) pojemniki: wxpanel okno, na którym można rozmieścić elementy sterujące (zamiast bezpośrednio na wxframe, ale wtedy bez możliwości sterowania klawiaturą i bezpośredniego rysowania na każdej platformie) wxscrolledwindow wxnotebook zakładki (karty) MyFrame::MyFrame(const wxstring& title) : wxframe(null, wxid_any, title) { wxnotebook* nb = new wxnotebook(this, wxid_any, wxdefaultposition, wxdefaultsize, wxnb_right); wxpanel* w1 = new wxpanel(nb,wxid_any); wxpanel* w2 = new wxpanel(nb,wxid_any); nb->addpage(w1, "Aaa...", true); nb->addpage(w2, "Bbb...", false); }
Programowanie GUI Wykład 6 6 elementy sterujące (kontrolki): dynamiczne (reagujące na działania użytkownika): wxbutton przycisk wxbitmapbutton przycisk z graficzną etykietą wxchoice rozwijana lista wyboru wxcombobox pole edycji z rozwijaną listą wyboru wxlistbox lista wyboru wxslider suwak wxtextctrl jedno- lub wieloliniowe pole tekstowe statyczne (nie podlegające edycji przez użytkownika programu): wxgauge pasek postępu wxstatictext etykieta tekstowa wxstaticbitmap grafika wxstaticline linia wxstaticbox obramowanie dookoła innych widgetów MyFrame::MyFrame(const wxstring& title) //...tutaj bez zmian... wxstaticbox* b = new wxstaticbox(w1, wxid_any, "Box", wxpoint(30,60), wxsize(150,50) ); wxgauge* g=new wxgauge(w1,wxid_any,10); g->setvalue(3); wxstaticline* l = new wxstaticline(w1, wxid_any,wxpoint(50,50), wxsize(200,5) ); }
Programowanie GUI Wykład 6 7 menu wxmenu menu; może byż używane na pasku menu lub jako menu kontekstowe paski: wxmenubar menu wxtoolbar narzędzi wxstatusbar statusu 1.5 Rozmieszczanie widgetów wxwidgets zapewnia mechanizmy wspomagające skalowalne rozmieszczanie elementów wewnątrz okien można uniknąć używania ustalonych współrzędnych i podawania rozmiarów (np. okienek dialogowych) obiekty odpowiadające za rozmieszczenie widgetów (sizers, pochodzą od klasy abstrakcyjnej wxsizer) zapewniają automatyczne wyliczanie potrzebnych rozmiarów i współrzędnych przy ustalaniu położenia widgetów pod uwagę brane są: minimalny dopuszczalny rozmiar margines (odstęp do brzegu lub sąsiedniego elementu) ustawiany bezpośrednio (np. 5px) wyrównanie (w pionie, poziomie zwykle tylko w jednym z tych kierunków w zależności od sposobu rozmieszczenia)
Programowanie GUI Wykład 6 8 współczynnik rozmiaru proporcje, w jakich są skalowane elementy, jeśli dostępne jest więcej miejsca niż wymagane minimum obiekt reprezentujący rozmieszczenie (tzw. sizer) używany jest w następujący sposób: 1. utworzenie obiektu (będącego na najwyższym poziomie hierarchii) 2. powiązanie z oknem macierzystym za pomocą wxwindow::setsizer 3. dodawanie do hierarchii kolejnych składników (widgetów lub dalszych rozmieszczeń) jedną z wersji metody wxsizer::add, np. Add(wxWindow* window, int proportion=0, int flag=0, int border=0, wxobject* userdata=null) okno dopasuje się rozmiarem do swojej zawartości, jeśli użyjemy funkcji wxsizer::fit wxsizer::setsizehints zapewni, że okno nie będzie mogło być zmniejszone poniżej swojej początkowej wielkości dostępna jest również funkcja wxwindow::setsizerandfit umożliwiająca od razu ustawienie rozkładu oraz wywołanie wxsizer::fit i wxsizer::setsizehints 1.5.1 Dostępne układy wxboxsizer układ pionowy (poszczególne elementy wyrównywane do lewej, środka lub prawej; współczynnik rozmiaru decyduje o wymiarach w pionie) lub poziomy MyFrame::MyFrame(const wxstring& title) : wxframe(null, wxid_any, title) { const int BORDER=10; wxpanel* p = new wxpanel(this); wxboxsizer* s = new wxboxsizer(wxhorizontal); } wxgauge* g = new wxgauge(p,wxid_any,10); g->setvalue(7); s->add(g,2,wxalign_center wxall,border); wxbutton* b = new wxbutton(p,wxid_ok,"ok"); s->add(b,1,wxalign_bottom wxall,border); p->setsizer(s); s->fit(this); s->setsizehints(this);
Programowanie GUI Wykład 6 9 wxstaticboxsizer pochodzi od wxstaticbox, dodatkowo może automatycznie umieszczać wxstaticbox wokół zawartych w sobie elementów wxpanel* p = new wxpanel(this); wxstaticboxsizer* s = new wxstaticboxsizer(wxvertical,p,"box"); const int BORDER=10; wxgauge* g= new wxgauge(p,wxid_any,10); g->setvalue(7); s->add(g,2,wxall,border); wxbutton* b = new wxbutton(p,wxid_ok,"ok"); s->add(b,3,wxall wxalign_center, BORDER); p->setsizer(s); s->fit(this); s->setsizehints(this);
Programowanie GUI Wykład 6 10 wxgridsizer rozmieszczenie w dwuwymiarowej sieci o równych szerokościach oraz równych wysokościach poszczególnych komórek do konstruktora przekazuje się liczbę kolumn i wierszy oraz ew. dodatkowe odstępy między elementami: wxgridsizer(int rows, int cols, int vgap, int hgap) wxgridsizer(int cols, int vgap = 0, int hgap = 0) wxpanel* p = new wxpanel(this); wxgridsizer* s=new wxgridsizer(2,2,0,0); wxgauge* g1= new wxgauge(p,wxid_any,100); g1->setvalue(25); s->add(g1,0,wxall,5); wxbutton* b1= new wxbutton(p,wxid_ok,"ok"); s->add(b1,0,wxall,5); wxbutton* b2= new wxbutton(p,wxid_cancel, "Cancel, cancel..."); s->add(b2,0,wxall,5); wxgauge* g2= new wxgauge(p,wxid_any,60); g2->setvalue(50); s->add(g2,0,wxall,5);
Programowanie GUI Wykład 6 11 p->setsizer(s); s->fit(this); s->setsizehints(this); wxflexgridsizer podobne do wxgridsizer z tym, że nie wszystkie kolumny muszą być jednakowej szerokości oraz nie wszystkie rzędy muszą być jednakowo wysokie dodatkowo funkcjami wxflexgridsizer::addgrowablecol wxflexgridsizer::addgrowablerow można wymusić poszerzanie tylko wybranych kolumn/wierszy podczas zmiany rozmiaru okna wxpanel* p = new wxpanel(this); wxflexgridsizer* s = new wxflexgridsizer(2,2,10,10); wxgauge* g1= new wxgauge(p,wxid_any,100); g1->setvalue(25); s->add(g1,0,wxall);
Programowanie GUI Wykład 6 12 wxbutton* b1= new wxbutton(p,wxid_ok,"ok"); s->add(b1,0,wxall); wxbutton* b2 = new wxbutton(p, wxid_cancel, "Cancel, cancel..."); s->add(b2,0,wxall); wxgauge* g2= new wxgauge(p,wxid_any,60); g2->setvalue(50); s->add(g2,0,wxall); p->setsizer(s); s->fit(this); s->setsizehints(this);