/** 例5 用户界面
这个例子显示了如何使用Irrlicht引擎内置的用户界面。
它会给出一个如何创建以及使用窗口,按钮,滑动条,静态文本和列表框等的简要概述。
和之前一样,我们首先包含头文件并使用引擎的命名空间。
我们还持有一个指向引擎设备的指针、控制窗口的变量以及列表框的指针
*/
#include <irrlicht.h>
#include "driverChoice.h"
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
//生命一个结构其来持有事件接受器,这样可以使他在OnEvent函数内可见
struct SAppContext
{
IrrlichtDevice *device;
s32 counter;
IGUIListBox* listbox;
};
// 定义一些参数,我们将于用区分个人定义的控件
enum
{
GUI_ID_QUIT_BUTTON = 101,
GUI_ID_NEW_WINDOW_BUTTON,
GUI_ID_FILE_OPEN_BUTTON,
GUI_ID_TRANSPARENCY_SCROLL_BAR
};
/*
事件接收器不止能接受来自键鼠的消息,也能接受来自用户图形界面的消息。
事件可能来自各个地方:点击按钮,菜单选择,一个元素被选中等等。
为了能够及时的响应这些事件,我们创建了事件接受器。
我们只响应用户界面所发生的时间,如果接受到的时间是来自GUI,
我们将获取发出者的ID(及UI元素的ID)以及GUI环境的指针。
*/
class MyEventReceiver : public IEventReceiver
{
public:
MyEventReceiver(SAppContext & context) : Context(context) { }
//继承来自IEventReceiver的OnEvent虚函数,并且若有子类继承此MyEventReceiver类时仍需覆盖此方法。
//const SEvent& event:以SEvent类型接受此参数,并不能修改
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)
{
/*
如果出触发的是改变滚动条位置事件而且是我们所添加到界面的滚动条
(即id GUI_ID_TRANSPARENCY_SCROLL_BAR),我们接下来改变界面的透明度。
这很容易:这里有一个皮肤对象,所有的颜色都存储于此。
我们遍历所有的颜色存储并且调节他们的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;
/*
如果是点击按钮事件,可能是我们设置的三个按钮之一。
如果是第一个,我们就结关闭引擎。
如果是第二个,我们就创建一个新窗口并显示一些静态信息。
同时,我们也在列表框里添加我们的动作记录。
如果是第三个按钮,我们就打开一个文件系统对话框并在列表框里添加我们的动作记录。
事件接受器就结束了。
*/
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;
/*
virtual IGUIWindow* irr::gui::IGUIEnvironment::addWindow (
const core::rect< s32 > & rectangle,
bool modal = false,
const wchar_t * text = 0,
IGUIElement * parent = 0,
s32 id = -1)
*/
IGUIWindow* window = env->addWindow(
rect<s32>(100 + Context.counter, 100 + Context.counter, 300 + Context.counter, 200 + Context.counter),
false,
L"Test window");
/*
virtual IGUIStaticText* irr::gui::IGUIEnvironment::addStaticText (
const wchar_t * text,
const core::rect< s32 > & rectangle,
bool border = false,
bool wordWrap = true,
IGUIElement * parent = 0,
s32 id = -1,
bool fillBackground = false)
*/
env->addStaticText(
L"Please close me",
rect<s32>(35,35,140,50),
true,
false,
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;
}
//创建Context:MyEventReceiver(SAppContext & context) : Context(context){}
private:
SAppContext & Context;
};
/*
现在我们来看写有趣的部分。
首先,创建引擎。
就像其他例子中的一样,我们要求用户去选择他们希望的类型。
*/
int main()
{
// 询问用户
video::E_DRIVER_TYPE driverType=driverChoiceConsole();
if (driverType==video::EDT_COUNT)
return 1;
//创建设备,若失败则退出。
IrrlichtDevice * device = createDevice(driverType, core::dimension2d<u32>(640, 480));
if (device == 0)
return 1; //创建所选类型失败
/* The creation was successful, now we set the event receiver and
store pointers to the driver and to the gui environment. */
device->setWindowCaption(L"Irrlicht Engine - User Interface Demo");
device->setResizable(true);
video::IVideoDriver* driver = device->getVideoDriver();
IGUIEnvironment* env = device->getGUIEnvironment();
/*
为了让字体更好看些,我们载入额外的字体并在皮肤中设置为新的默认字体。
为了让提示文本显示标准,我们设置为内置字体。
(???:To keep the standard font for tool tip text, we set it to the built-in font.)
*/
IGUISkin* skin = env->getSkin();
IGUIFont* font = env->getFont("http://www.cnblogs.com/media/fonthaettenschweiler.bmp");
if (font)
skin->setFont(font);
skin->setFont(env->getBuiltInFont(), EGDF_TOOLTIP);
/*
我们添加三个按钮。
第一个用于关闭引擎。
第二个创建窗口,第三个打开文本系统的对话框。
第三个参数是按钮的ID,这样我们可以在事件接收器离开方便的定位按钮。
*/
env->addButton(rect<s32>(10,240,110,240 + 32), 0, GUI_ID_QUIT_BUTTON,
L"Quit", L"Exits Program");
env->addButton(rect<s32>(10,280,110,280 + 32), 0, GUI_ID_NEW_WINDOW_BUTTON,
L"New Window", L"Launches a new Window");
env->addButton(rect<s32>(10,320,110,320 + 32), 0, GUI_ID_FILE_OPEN_BUTTON,
L"File Open", L"Opens a file");
/*
现在我们添加一个静态文本和一个滚动条,来控制窗口各元素的透明度。
我们设置滚动条的最大值为255,因为这是透明度的上限。
之后我们再创建一个文本和列表框。
*/
env->addStaticText(L"Transparent Control:", rect<s32>(150,20,350,40), true);
IGUIScrollBar* scrollbar = env->addScrollBar(true,
rect<s32>(150, 45, 350, 60), 0, GUI_ID_TRANSPARENCY_SCROLL_BAR);
scrollbar->setMax(255);
//将滚动条位置设置为当前皮肤透明度的值
scrollbar->setPos(env->getSkin()->getColor(EGDC_WINDOW).getAlpha());
env->addStaticText(L"Logging ListBox:", rect<s32>(50,110,250,130), true);
IGUIListBox * listbox = env->addListBox(rect<s32>(50, 140, 250, 210));
env->addEditBox(L"Editable Text", rect<s32>(350, 80, 550, 100));
//存储相应的数据。
SAppContext context;
context.device = device;
context.counter = 0;
context.listbox = listbox;
// 创建事件接收器,并将context作为参数。
MyEventReceiver receiver(context);
//通知系统使用我们定义的事件接受器
device->setEventReceiver(&receiver);
/*
最后,我们在左上角显示一个漂漂的Irrlicht Logo。
And at last, we create a nice Irrlicht Engine logo in the top left corner.
*/
env->addImage(driver->getTexture("http://www.cnblogs.com/media/irrlichtlogo2.png"),
position2d<int>(10,10));
/*
一切就绪
*/
while(device->run() && driver)
if (device->isWindowActive())
{
driver->beginScene(true, true, SColor(0,200,200,200));
env->drawAll();
driver->endScene();
}
device->drop();
return 0;
}