Irrlicht学习笔记(5)--UserInterface

来源:互联网 发布:网络测试员是干什么的 编辑:程序博客网 时间:2024/05/08 10:19

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 IGUIElements32 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;}


0 0
原创粉丝点击