| 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:", rectWreszcie, 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;
}
|