1.说明:
这个例子介绍irrlicht引擎的用户界面接口部分,
展示了Irrlicht引擎GUI设计的部分内容.
本例内容包括:
1)创建和使用窗口
2)按钮
3)滑动条
4)静态文本
5)列表盒子
2.准备:
1)确定gui界面的风格
类IGUISkin管理gui界面的风格,
包括:icon,精灵,字体,绘制风格等
这里设置了字体,用到的文件是:../media/fonthaettenschweiler.bmp
(1)获得skin对象
IGUIEnvironment类管理skin对象,
要改变默认skin就需要从它那里获取,或者为它重新设置一个自己创建的skin对象
这里直接获取:
gui::IGUISkin* skin = guie->getSkin();
(2)创建一个新的font并传给skin
创建
方法是通过IGUIEnvironment类的方法:getFont(filename)获得
gui::IGUIFont* font =guie->getFont("../media/fonthaettenschweiler.bmp");
设置
if(font)
{
skin->setFont(font);
}
2)基本控件的创建
都是通过IGUIEnvironment类中的add*方法添加
(1)添加按钮
使用gui::IGUIEnvironment下的一个函数:
virtual IGUIButton* addButton(
const core::rect<s32>& rectangle,//确定按钮边界,左上角和右下角
IGUIElement* parent=0,//父gui元素,单一元素为0
s32 id=-1, //唯一标识
const wchar_t* text=0,//按钮上显示的文字
const wchar_t* tooltiptext = 0//提示消息的文字
) = 0;
比如,创建一个退出按钮
guie->addButton(
core::rect<s32>(10, 240, 110, 240 + 32),
0,
GUI_ID_QUIT_BUTTON,
L"Quit",
L"Exits Progma");
(2)滑动条
gui::IGUIEnvironment下的函数
virtual IGUIScrollBar* addScrollBar(
bool horizontal,//是否平着画
const core::rect<s32>& rectangle,//位置边界
IGUIElement* parent=0,//父gui元素
s32 id=-1//唯一标识
) = 0;
比如:
gui::IGUIScrollBar* scrollbar = guie->addScrollBar(
true,
core::rect<s32>(250, 45, 350, 60),
0,
GUI_ID_TRANSPARENCY_SCROLL_BAR//已经自定义好的唯一标志
);
这个滑动条的作用是控制界面元素的透明度,所以条还需要设置其他参数:
1滑动条上下限范围(与透明度对应:0~255),(默认:0-100)
2滑动条初始位置(界面元素初始默认透明度值决定)(默认:0)
方法在IGUIScrollBar中:
scrollbar->setMax(value1);//这里value1=255
scrollbar->setPos(value2);
value2的值从skin获取默认gui窗口颜色,再获取alpha分量
IGUISkin* skin = guie->getSkin();
video::SColor color = skin->getColor(gui::EGUI_DEFAULT_COLOR::EGDC_WINDOW);
value2= color.getAlpha();
枚举EGUI_DEFAULT_COLOR在IGUISkin.h中
(3)列表盒子
用它来记录按钮日志
gui::IGUIListBox* listbox=guie->addListBox(core::rect<s32>(50,140,250,210));
(4)添加一个可编辑文字框
gui::IGUIEditBox* editbox = guie->addEditBox(L"Editable text",//默认内容
core::rect<s32>(350,80,550,100));
3.创建事件接收器
界面有了,但是运行之后会发现没有任何反应(除了可编辑框)
需要创建一个事件接受器,
功能:接受来自Irrlicht内部消息循环的事件,
并根据事件类型和对象的类型与某个类型的对象的id做出相应的反应
1)理解事件
在IEventReceiver.h中有跟消息有关的许多定义,命名空间为irr
(1)结构体SEvent保存了一个事件的信息.
定义如下:
struct SEvent
{
....
EVENT_TYPE EventType;
union
{
struct SUIEvent GUIEvent;//这个例程关注这个
struct SMouseInput MouseInput;
struct SkeyInput KeyInput;
struct SJoystictEvent JoystictEvent;
struct SLogEvent LogEvent;
struct SUserEvent UserEvent;
};
};
<1>事件类型
枚举EVENT_TYPE包括EET_**_EVENT形式的枚举,
包括所有支持的事件类型,比如GUI,鼠标输入,键盘输入,手柄输入等
这里用到的是EET_GUI_EVENT
<2>事件结构体
这里用的是GUIEvent:
struct SGUIEvent
{
gui::IGUIElement* Caller;//发出事件的GUI元素
gui::IGUIElement* Element;//被影响的其他的GUI元素
gui::EGUI_EVENT_TYPE EventType;//GUI事件的类型
};
2)环境变量传递
因为事件接收器需要根据事件改变界面的内容,
所以需要让它能够访问外部对象.
这里建立一个结构保存相关信息
struct SAppcontext
{
IrrlichtDevice* device;
s32 counter;//用于窗口建立时窗口坐标的管理
gui::IGUIListBox* listbox;//列表盒子
};
<3>ID分配
enum
{
GUI_ID_QUIT_BUTTON = 101,//退出按钮
GUI_ID_NEW_WINDOW_BUTTON,//新建窗口按钮
GUI_ID_FILE_OPEN_BUTTON,//打开文件按钮
GUI_ID_TRANSPARENCY_SCROLL_BAR//滑动条
};
2)事件接受器对象
(1)继承类:irr::IEventReceiver
class IEventReceiver
{
public:
virtual ~IEventReceiver() {}
virtual bool OnEvent(const SEvent& event) = 0;
};
这个类只有一个方法:OnEvent
需要注意的是:
返回true能防止Irrlicht继续对这个消息进行相应活动,但如果有特殊需求则不用该这么做
(2)事件接收器编写
这里只有框架,对于一个具体的事件的处理细节的完整代码
class MyEventReceiver:public IEventReceiver
{
private:
SAppContext &Context;
public:
MyEventReceiver(SAppContext& context):Context(context){}
virtual bool OnEvent(const SEvent& event)
{
if(event.EventType==EET_GUI_EVENT)//只处理GUI消息
{
s32 id = event.GUIEvent.Caller->getID();
gui::IGUIEnvironment* guie= Context.device->getGUIEnvironment();
//根据GUI事件的种类分类处理,这里有两类gui事件
//滑动条和按钮
//
需要精确到id
switch(event.GUIEvent.EventType)
{
//滑动条
case gui::EGUI_EVENT_TYPE::EGET_SCROLL_BAR_CHANGED:
{
...
}
break;
case gui::EGUI_EVENT_TYPE::EGET_BUTTON_LICKED:
switch(id)
{
case GUI_ID_QUIT_BUTTON://退出按钮
...
return true;
case GUI_ID_NEW_WINDOW_BUTTON://新建窗口按钮
case GUI_ID_FILE_OPEN_BUTTON://打开文件按钮
}
}
}
}
}
(3)初始化
在main函数中需要事件接收器
SappContext context;
context.device=device;
context.counter =0;
context.listbox =listbox;
MyEventReceiver recevier(context);
//为设备添加一个消息接收器
device->setEventReceiver(&receiver);
4.完整代码:
#include <irrlicht.h>
using namespace irr;
#ifdef _IRR_WINDOWS_
#pragma comment(lib,"irrlicht.lib")
#endif
//声明一个结构来保存环境信息,
//让事件接收器可以在OnEvent()方法中使用
struct SAppContext
{
IrrlichtDevice* device;
s32 counter;
gui::IGUIListBox* listbox;
};
//定义一些用于为GUI控件ID管理的值
enum
{
GUI_ID_QUIT_BUTTON = 101,//退出
GUI_ID_NEW_WINDOW_BUTTON,//新建窗口
GUI_ID_FILE_OPEN_BUTTON,//打开文件
GUI_ID_TRANSPARENCY_SCROLL_BAR//滑动条
};
/**创建一个事件接收器(只对GUI事件反应)
*当GUI控件被按下,将会传送一个附带其ID的消息
*接收器根据ID做出反应
*/
class MyEventReceiver:public IEventReceiver
{
private:
SAppContext &Context;
public:
MyEventReceiver(SAppContext& context) : Context(context){ }
virtual bool OnEvent(const SEvent& event)
{
if (event.EventType == EET_GUI_EVENT)
{
s32 id = event.GUIEvent.Caller->getID();
gui::IGUIEnvironment* guie = Context.device->getGUIEnvironment();
switch (event.GUIEvent.EventType)
{
case gui::EGUI_EVENT_TYPE::EGET_SCROLL_BAR_CHANGED://滑动条事件
if (id == GUI_ID_TRANSPARENCY_SCROLL_BAR)//对应滑动条的id
{
//获得当前滑动条的位置,class IGUIScrollBar : public IGUIElement
s32 pos = ((gui::IGUIScrollBar*)event.GUIEvent.Caller)->getPos();
//将skin内的默认颜色的透明度设置为当前值
for (u32 i = 0; i < gui::EGUI_DEFAULT_COLOR::EGDC_COUNT; ++i)
{
video::SColor col = guie->getSkin()->getColor((gui::EGUI_DEFAULT_COLOR)i);
col.setAlpha(pos);
guie->getSkin()->setColor((gui::EGUI_DEFAULT_COLOR)i, col);
}
}
break;
//按钮点击事件
case gui::EGUI_EVENT_TYPE::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;
gui::IGUIWindow* window = guie->addWindow(
core::rect<irr::s32>(100 + Context.counter, 100 + Context.counter, 300 + Context.counter, 200 + Context.counter),
false,//modal?是否独占,true则关闭才能使用其他gui元素
L"Test window"//标题
);
//在window中添加文本
guie->addStaticText(
L"Please close me",//标题
core::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");//为日志列表盒子添加内容
//通过IGUIEnvironment对象添加一个文件打开窗口
guie->addFileOpenDialog(L"Pleasse choose a file.");
return true;
default:
return false;
}
break;
default:
break;
}
}
return false;
}
};
int main(int argc, char**argv)
{
irr::IrrlichtDevice* device = irr::createDevice(video::EDT_OPENGL, core::dimension2d<irr::u32>(720, 445), 16, false, false, false, 0);
device->setWindowCaption(L"UserInterface");
device->setResizable(true);
irr::scene::ISceneManager* smgr = device->getSceneManager();
irr::video::IVideoDriver* driver = device->getVideoDriver();
gui::IGUIEnvironment* guie = device->getGUIEnvironment();
//初始化部分
//字体
gui::IGUISkin* skin = guie->getSkin();
gui::IGUIFont* font = guie->getFont("../media/fonthaettenschweiler.bmp");
if (font)
{
skin->setFont(font);
}
skin->setFont(guie->getBuiltInFont(), gui::EGUI_DEFAULT_FONT::EGDF_TOOLTIP);
//添加按钮
guie->addButton(
core::rect<s32>(10, 240, 110, 240 + 32),
0,
GUI_ID_QUIT_BUTTON,
L"Quit",
L"Exits Progma");
guie->addButton(
core::rect<s32>(10,280,110,280+32),
0,
GUI_ID_NEW_WINDOW_BUTTON,
L"New Window",
L"Launches a new Window"
);
guie->addButton(
core::rect<s32>(10, 320, 110, 320 + 32),
0, GUI_ID_FILE_OPEN_BUTTON,
L"File Open",
L"Opens a file"
);
//添加标签
guie->addStaticText(L"Transparent Control:", core::rect<s32>(150, 20, 350, 40), true);
//添加滑动条
gui::IGUIScrollBar* scrollbar = guie->addScrollBar(
true,
core::rect<s32>(250, 45, 350, 60),
0,
GUI_ID_TRANSPARENCY_SCROLL_BAR
);
scrollbar->setMax(255);
//设置滑动条位置对应所有元素的透明度
scrollbar->setPos(
guie->getSkin()->getColor(gui::EGUI_DEFAULT_COLOR::EGDC_WINDOW).getAlpha()
);
//添加一个文本
guie->addStaticText(L"Loging ListBox:",
core::rect<s32>(50, 110, 250, 130),
true
);
gui::IGUIListBox* listbox = guie->addListBox(core::rect<s32>(50, 140, 250, 210));
//添加一个可编辑框
guie->addEditBox(L"Editable Text", core::rect<s32>(350, 80, 550, 100));
//
SAppContext context;
context.device = device;
context.counter = 0;
context.listbox = listbox;
MyEventReceiver receiver(context);
device->setEventReceiver(&receiver);
guie->addImage(driver->getTexture("../media/irrlichtlogo2.png"),
core::position2di(10, 10)
);
//smgr->addCameraSceneNode(0, core::vector3df(0, 20, -20), core::vector3df(0, 0, 100));
//初始化结束
int lastfps = -1;
while (device->run())
{
driver->beginScene(true, true, video::SColor(255, 100, 100, 0));
smgr->drawAll();
guie->drawAll();
driver->endScene();
int fps = driver->getFPS();
core::stringw str = L"userinterface ]";
str += driver->getName();
str += "]FPS:",
str += fps;
device->setWindowCaption(str.c_str());
lastfps = fps;
}
device->drop();
return 0;
}