Irrlicht学习笔记(5)--UserInterface

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://新建窗口按钮
                                     ...
                                      return true;
                        case GUI_ID_FILE_OPEN_BUTTON://打开文件按钮
                                     ...
                                      return true;
                       }
            }
        }
    }
}
(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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值