22 grudnia 2009 | Tutorial 5: User Interface |
![]() |
#include <irrlicht.h> #include <iostream> using namespace irr; using namespace core; using namespace scene; using namespace video; using namespace io; using namespace gui; #ifdef _IRR_WINDOWS_ #pragma comment(lib, "Irrlicht.lib") #endif // Declare a structure to hold some context for the event receiver so that it // has it available inside its OnEvent() method. struct SAppContext { IrrlichtDevice *device; s32 counter; IGUIListBox* listbox; }; // Define some values that we'll use to identify individual GUI controls. enum { GUI_ID_QUIT_BUTTON = 101, GUI_ID_NEW_WINDOW_BUTTON, GUI_ID_FILE_OPEN_BUTTON, GUI_ID_TRANSPARENCY_SCROLL_BAR }; Event Receiver jest zdolny nie tylko do przyjmowania zdarzeń z klawiatury i myszy, ale również zdarzeń graficznego interfejsu użytkownika (qui). Zdarzenia są dostępne prawie do wszystkiego: przycisków, zmiany wyboru pola listy, zdarzeń, które informują o najechaniu na element itp. By mieć możliwość reagowania na inne zdarzenia, tworzymy odbieracz zdarzeń. Reagujemy tylko na zdarzenia gui i jeśli to jest takie zdarzenie, bierzemy id z lementu gui, który spowodował zdarzenie i wskaźnik do środowiska gui. class MyEventReceiver : public IEventReceiver { public: MyEventReceiver(SAppContext & context) : Context(context) { } virtual bool OnEvent(const SEvent& event) { if (event.EventType == EET_GUI_EVENT) { s32 id = event.GUIEvent.Caller->getID(); IGUIEnvironment* env = Context.device->getGUIEnvironment(); switch(event.GUIEvent.EventType) { Jeśli pasek przewijania zmieni swoją pozycję i jest on 'naszym' paskiem do przewijania (tym z GUI_ID_TRANSPARENCY_SCROLL_BAR id), wtedy zmieniamy przezroczystość wszystkich elementów gui. To jest bardzo proste: Jest skin object, w którym są wszystkie ustawienia dotyczące kolorów, więc po prostu przeglądamy kolory tam umieszczone i zmieniamy ich wartość alpha. case EGET_SCROLL_BAR_CHANGED: if (id == GUI_ID_TRANSPARENCY_SCROLL_BAR) { s32 pos = ((IGUIScrollBar*)event.GUIEvent.Caller)-> getPos(); for (u32 i=0; i<EGDC_COUNT ; ++i) { SColor col = env->getSkin()-> getColor((EGUI_DEFAULT_COLOR)i); col.setAlpha(pos); env->getSkin()-> setColor((EGUI_DEFAULT_COLOR)i, col); } } break; Jeżeli przycisk został naciśnięty, może być jednym z 'naszych' trzech przycisków. Jeśli jest to pierwszy, zamkniemy silnik. Jeśli drugi, utworzymy małe okno z tekstem w środku. Dodajemy ciąg znaków do pola listy żeby zobaczyć co się stało. A jeśli jest to trzeci przycisk, to tworzymy okno do wyboru plików i jednocześnie dodajemy ciąg znaków do listy powyżej. To tyle jeżeli chodzi o odbieracz zdarzeń. case EGET_BUTTON_CLICKED: switch(id) { case GUI_ID_QUIT_BUTTON: Context.device->closeDevice(); return true; case GUI_ID_NEW_WINDOW_BUTTON: { Context.listbox->addItem(L"Window created"); Context.counter += 30; if (Context.counter > 200) Context.counter = 0; IGUIWindow* window = env->addWindow( rect<s32>(100 + Context.counter, 100 + Context.counter, 300 + Context.counter, 200 + Context.counter), false, // modal? L"Test window"); env->addStaticText(L"Please close me", rect<s32>(35,35,140,50), true, // border? false, // wordwrap? window); } return true; case GUI_ID_FILE_OPEN_BUTTON: Context.listbox->addItem(L"File open"); env->addFileOpenDialog(L"Please choose a file."); return true; default: return false; } break; default: break; } } return false; } private: SAppContext & Context; }; Teraz bardziej interesująca część. Najpierw, tworzymy urządzenie Irrlicht. Tak jak w poprzednich przykładach, pytamy użytkownika którego sterownika chce używać do tego przykładu: int main() { // ask user for driver video::E_DRIVER_TYPE driverType; printf("Please select the driver you want for this example:\n"\ " (a) Direct3D 9.0c\n (b) Direct3D 8.1\n (c) OpenGL 1.5\n"\ " (d) Software Renderer\n (e) Burning's Software Renderer\n"\ " (f) NullDevice\n (otherKey) exit\n\n"); char i; std::cin >> i; switch(i) { case 'a': driverType = video::EDT_DIRECT3D9;break; case 'b': driverType = video::EDT_DIRECT3D8;break; case 'c': driverType = video::EDT_OPENGL; break; case 'd': driverType = video::EDT_SOFTWARE; break; case 'e': driverType = video::EDT_BURNINGSVIDEO;break; case 'f': driverType = video::EDT_NULL; break; default: return 1; } // create device and exit if creation failed IrrlichtDevice * device = createDevice (driverType, core::dimension2d<u32>(640, 480)); if (device == 0) return 1; // could not create selected driver. Proces tworzenia zakończył się sukcesem. Teraz ustawiamy przechwytywacz zdarzeń i zbiór wskaźników dla sterownika i dla środowiska graficznego. device->setWindowCaption(L"Irrlicht Engine - User Interface Demo"); device->setResizable(true); video::IVideoDriver* driver = device->getVideoDriver(); IGUIEnvironment* env = device->getGUIEnvironment(); Aby czcionka stała się troszkę ładniejsza, ładujemy zewnętrzną czcionkę i ustawiamy ją jako nową domyślną czcionkę do skin. Żeby utrzymać standardową czcionkę dla tool tip text, ustawiamy to do czcionki built-in. IGUISkin* skin = env->getSkin(); IGUIFont* font = env->getFont("../../media/fonthaettenschweiler.bmp"); if (font) skin->setFont(font); skin->setFont(env->getBuiltInFont(), EGDF_TOOLTIP); Dodajemy trzy przyciski. Pierwszy zamyka silnik. Drugi tworzy okno a trzeci otwiera okno do wyboru plików. Trzeci parametr jest id przycisku, z którym łatwo można zidentyfikować przycisk w odbieraczu zdarzeń. env->addButton(rect<u32>(10,240,110,240 + 32), 0, GUI_ID_QUIT_BUTTON, L"Quit", L"Exits Program"); env->addButton(rect<u32>(10,280,110,280 + 32), 0, GUI_ID_NEW_WINDOW_BUTTON, L"New Window", L"Launches a new Window"); env->addButton(rect<u32>(10,320,110,320 + 32), 0, GUI_ID_FILE_OPEN_BUTTON, L"File Open", L"Opens a file"); Teraz dodajemy statyczny tekst i pasek przewijania, który modyfikuje transparentność wszystkich elementów gui. Ustawiamy maksymalną wartość dla wartości koloru. Wtedy, tworzymy kolejny tekst statyczny i pole listy. env->addStaticText(L"Transparent Control:", rect Wreszcie, tworzymy ładne logo Silnika Irrlicht w górnym lewym rogu. env->addImage(driver->getTexture("../../media/irrlichtlogo2.png"), position2d<int>(10,10)); To wszystko, musimy tylko wszystko narysować. while(device->run() && driver) if (device->isWindowActive()) { driver->beginScene(true, true, SColor(0,200,200,200)); env->drawAll(); driver->endScene(); } device->drop(); return 0; } |