MyGUI 学习笔记(1)
蛋疼的MyGUI,虽然很好用,但是没有文档,网上几乎没有资源,依赖ogre的MyGUI我依然没能编译运行,一运行demo就崩溃,不知道是不是ogre版本的问题,我用ogre3.0.1+ogre1.7.3,知道为什么的,请告诉我谢谢。
以下都是基于directx渲染的MyGUI的学习,其实ogre渲染的也差不多。
MyGUI资源来源:
MyGUI 官网
Ogre 官网wiki
Baidu/google
资料太少,唯有自己边学边做笔记,如有错的地方,请指导:
GUI初始化
1.GUI实现过程:
先来看下demo的baseManager,通过baseManager观察整个MyGUI的初始化过程:
BaseManager实质是简单了封装了MyGUI和调用d3d初始化的过程。
1.1来看下create的代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
bool BaseManager::create()
{
//创建窗口
WNDCLASS wc = {0, (WNDPROC)DXWndProc, 0, 0, GetModuleHandle(NULL), LoadIcon(NULL, IDI_APPLICATION),LoadCursor(NULL, IDC_ARROW), (HBRUSH)GetStockObject(BLACK_BRUSH), NULL, TEXT(WND_CLASS_NAME),};
RegisterClass(&wc);
hWnd = CreateWindow(wc.lpszClassName, TEXT("Direct3D9 Render Window"), WS_POPUP,0, 0, 0, 0, GetDesktopWindow(), NULL, wc.hInstance, this);
if (!hWnd)
{
//OutException("fatal error!", "failed create window");
return false;
}
hInstance = wc.hInstance;
const unsigned int width = 1024;
const unsigned int height = 768;
bool windowed = true;
// createRender封装了d3d的初始化过程
createRender(width, height, windowed);
windowAdjustSettings(hWnd, width, height, !mD3dpp.Windowed);
//封装了OIS
createInput((size_t)hWnd);
_windowResized();
//重点代码:
createGui();
createPointerManager((size_t)hWnd);
createScene();
return true;
}
CreateGUI:
void BaseManager::createGui()
{
mPlatform = new MyGUI::DirectXPlatform();
mPlatform->initialise(mDevice);
//重点代码:
setupResources();
mGUI = new MyGUI::Gui();
mGUI->initialise(mResourceFileName);
mInfo = new diagnostic::StatisticInfo();
}
void BaseManager::setupResources()
{
MyGUI::xml::Document doc;
if (!doc.open(std::string("resources.xml")))
doc.getLastError();
MyGUI::xml::ElementPtr root = doc.getRoot();
if (root == nullptr || root->getName() != "Paths")
return;
MyGUI::xml::ElementEnumerator node = root->getElementEnumerator();
while (node.next())
{
if (node->getName() == "Path")
{
bool root = false;
if (node->findAttribute("root") != "")
{
root = MyGUI::utility::parseBool(node->findAttribute("root"));
if (root) mRootMedia = node->getContent();
}
addResourceLocation(node->getContent(), false);
}
}
}
而各个demo就会继承baseManager从而实现具体的skins和layout的载入和显示,实现各种UI界面。
如第一个demo:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
void DemoKeeper::createScene()
{
getGUI()->load("Wallpaper0.layout");//载入layout文件其实这是一张背景图
MyGUI::VectorWidgetPtr& root = MyGUI::LayoutManager::getInstance().load("BackHelp.layout");
//root是一个vector<Widget *>,下面是在BackHelp.layout里面找到Text这个widget。
root.at(0)->findWidget("Text")->setCaption("Sample colour picker implementation. Select text in Edit and then select colour to colour selected part of text.");
//加载皮肤文件
MyGUI::Gui::getInstance().load("colour_slider_skin.xml");
//加载两个面板
//里面加载了各自的layout
mColourPanel = new
ColourPanel();
mEditPanel = new
EditPanel();
//注册事件
mColourPanel->eventColourAccept = MyGUI::newDelegate(this, &DemoKeeper::nColourAccept);
}
1.2初始化流程大概就是:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
mPlatform = new MyGUI::DirectXPlatform();
mPlatform->initialise(mDevice);
//加载资源:环境
mPlatform->getDataManagerPtr()->addResourceLocation(_name, _recursive);
mGUI = new MyGUI::Gui();
mGUI->initialise(mResourceFileName);
1.3加载layout,skins文件
1.3.1资源加载分析:
先调用BaseManager::setupResources
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
void
BaseManager::setupResources()
{
MyGUI::xml::Document
doc;
if (!doc.open(std::string("resources.xml")))
doc.getLastError();
MyGUI::xml::ElementPtr
root = doc.getRoot();
if (root == nullptr || root->getName() != "Paths")
return;
MyGUI::xml::ElementEnumerator
node = root->getElementEnumerator();
while (node.next())
{
if (node->getName() == "Path")
{
bool
root = false;
if (node->findAttribute("root") != "")
{
root = MyGUI::utility::parseBool(node->findAttribute("root"));
if (root) mRootMedia = node->getContent();
}
addResourceLocation(node->getContent(), false);
}
}
}
这个函数操作resources.xml
resources.xml:
<?xml version="1.0" encoding="UTF-8"?>
<Paths>
<Path root="true">http://www.cnblogs.com/../Media</Path>
<Path>http://www.cnblogs.com/../Media/MyGUI_Media</Path>
</Paths>
可以看到resources.xml里面指定了资源目录和资源路径。
看到:在第一个demo就在继承basemanager的setupResources里加载了本身的资源目录:
void DemoKeeper::setupResources()
{
base::BaseManager::setupResources();
addResourceLocation(getRootMedia() + "/Demos/Demo_Colour");
addResourceLocation(getRootMedia() + "/Common/Wallpapers");
}
1.4加載Layout
getGUI()->load("Wallpaper0.layout");
1.5找到widget
mMouseMoveSpeedScroll =MyGUI::Gui::getInstancePtr()->findWidget<MyGUI::HScroll>("MouseMoveSpeedScroll");
mEffectSoundCheck = MyGUI::Gui::getInstancePtr()->findWidget<MyGUI::Button>("EffectSoundCheck");
1.6實現委託、綁定事件:
mEffectSoundCheck->eventMouseButtonClick=MyGUI::newDelegate(this,&VSGuiOptionPanel::notifyEffectSoundCheck);
1.7實現函數notifyEffectSoundCheck
Void notifyEffectSoundCheck()
{
//....
}
1.8 MyGUI的Hello World:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
void
CTest::createScene()
{
MyGUI::LayoutManager::getInstancePtr()->loadLayout("test.layout");
MyGUI::Gui * m_pGUI = getGUI();
m_btn = m_pGUI->findWidget<MyGUI::Button>("testBtn");
m_btn->eventMouseButtonPressed = MyGUI::newDelegate(this,&CTest::notifyMouseClick);
}
void
CTest::notifyMouseClick(MyGUI::Widget* _sender, int
_left, int
_top, MyGUI::MouseButton
_id)
{
if(_id == MyGUI::MouseButton::Left)
{
MyGUI::Window *m_pWIn = getGUI()->findWidget<MyGUI::Window>("win");
m_pWIn->setCaption(L"hello world");
}
}
Skin和layout
2.1Layout 文件的分析:
<?xml version="1.0" encoding="UTF-8"?>
<MyGUI type="Layout">
<Widget type="Widget" skin="testa1" position="10 10 120 120" align="Default" layer="Main" name="testWidget"/>
<Widget type="Button" skin="testa1" position ="230 230 50 50" align="Default" layer="Main" name="testBtn"/>
</MyGUI>
可以看到layout也是一个xml。而且widget 里面有各种各样的参数,比如:
在按钮上写字:
<Widget type="Button" skin="Button" position="14 22 160 26" name="New">
<Property key="Widget_Caption" value="New"/>
</Widget>
要查这些参数,在MyGUI_widgetName.h 里面查找setProperty这个函数。可以看到各种各样的property。
比如:
void StaticText::setProperty(const
std::string& _key, const
std::string& _value)
{
if (_key == "Text_TextColour") setTextColour(utility::parseValue<Colour>(_value));
else
if (_key == "Text_TextAlign") setTextAlign(utility::parseValue<Align>(_value));
else
if (_key == "Text_FontName") setFontName(_value);
else
if (_key == "Text_FontHeight") setFontHeight(utility::parseValue<int>(_value));
else
if (_key == "Text_AutoReturn") setAutoReturn(utility::parseValue<bool>(_value));
else
{
Base::setProperty(_key, _value);
return;
}
eventChangeProperty(this, _key, _value);
}
2.2 Skin:
Skin文件的描述(来自ogre 官网):
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<?xml version="1.0" encoding="UTF-8"?>
<MyGUI type="Resource" version="1.1">
<Resource type="ResourceSkin" name = "__Skin_name__" size = "__width height__" texture = "__Texture_file_name__" >
<!- size 属性是默认的widget size,subskins 和子widget 的对齐都依赖于这个size-->
<Property key="__Property_name__" value = "__Property_value__" />
<!- 一些widget类型有指定的属性,你可以在skins文件中设置,而不是在layout或在代码中设置-->
<Child type="__Widget_type__" skin="__Some_skin_name__" offset = "__left top width height__" align = "__Some_align__" name = "__Child_widget_name__">
<!- Offset 和 align 是儿子widget的皮肤属性 -->
<Property key="__Property_name__" value = "__Property_value__" />
<!- 子widget也有一些指定的属性-->
</Child>
<!- 如同窗口有按钮,按钮就是子widget,所以皮肤也有子widget-->
<BasisSkin type="__SubSkin_type__" offset = "__left top width height__" align = "__Some_align__">
<!- 和子widget一样的偏移和对齐方式-->
<State name="__state_name__" offset = "__left top width height__"/>
<!- Here is defined part of texture for different widget states. ''Offset''指在纹理上的偏移部分,这部分将被渲染显示-->
</BasisSkin>
<!-- ''BasisSkin'' with type ''MainSkin'' or ''SubSkin'' is an actual part of texture that will be rendered.
Usually skins contain one part (part of texture stretched over whole widget) - SubSkin_type should be ''MainSkin'',
three parts (left part, stretched central part and right part) - SubSkin_type should be ''SubSkin''
or nine parts (one in center and 8 around) - SubSkin_type should be SubSkin.
You may have any amount of ''BasisSkin'' elements one for each texture part.
-->
<BasisSkin type="SimpleText" offset = "__left top width height__" align = "__Some_align__">
<!- Offset and align here works same way as for child widgets -->
<State name="__state_name__" colour="__R G B or #RRGGBB (hex)__"/>
<!- ''SimpleText'' may contain state description, it is optional. If it contain node - default colour will be used for all states. -->
</BasisSkin>
<!- ''SimpleText'' is place where widget text is placed. Also if this text should be selectable or editable you should use ''EditText'' type instead. >
</Resource>
<!- Lots of other skins here ... -->
</MyGUI>
<!-- ''BasisSkin'' with type ''MainSkin'' or ''SubSkin'' is an actual part of texture that will be rendered.
Usually skins contain one part (part of texture stretched over whole widget) - SubSkin_type should be ''MainSkin'',
three parts (left part, stretched central part and right part) - SubSkin_type should be ''SubSkin''
or nine parts (one in center and 8 around) - SubSkin_type should be SubSkin.
You may have any amount of ''BasisSkin'' elements one for each texture part.
-->
本人翻译水平太差了,杯具
2.3注意:
要在这张UI纹理图中获取比如一个框:
<Resource type="ResourceSkin" name = "testa1" size = "233 158" texture="uiShopGroup.png">
<BasisSkin type="MainSkin" offset="0 0 233 183",align="Stretch">
<State name="normal" offset="0 0 50 50"/>
</BasisSkin>
</Resource>
我们就要在state里指定left top width height。注意是在state里面。
第2点:对于某些widget来说,会有不同的state,比如按钮,有按下,悬停等状态,如下;
<State name="disabled" offset = "0 0 64 64"/>
<State name="normal" offset = "0 64 64 64"/>
<State name="highlighted" offset = "0 128 64 64"/>
<State name="normal_checked" offset = "0 192 64 64"/>
<State name="pushed" offset = "0 252 64 64"/>
第3点:默认情况下,skin是放在core_skin.xml 里面
第4点:相同的skin可以由不同的layout加载,从而实现skin重用,实现的效果也不一样。
第5点:就是这段话:
Usually skins contain one part (part of texture stretched over whole widget) - SubSkin_type should be ''MainSkin'',
three parts (left part, stretched central part and right part) - SubSkin_type should be ''SubSkin''
or nine parts (one in center and 8 around) - SubSkin_type should be SubSkin.
这段话的意思是指,有些skin的纹理可以整张拉大,延伸。比如图中的一些按钮。这些一般是MainSkin,
有些skin是分3部分,中间延伸,两边固定的,比如血条之类的。
有些skin是纹理分9份(九宫格),其中四个角固定,其他四块延伸。比如一些窗口。
以上三种都可以通过skin的align来指定。
例如9宫格的panel(代码来源于http://hi.baidu.com/sysnoah/home):
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<Resource type="ResourceSkin" name="NFSkin_Panel9" size="11 11" texture="ItemIcon1.png">
<BasisSkin type="SubSkin" offset="0 0 3 3" align="Left Top">
<State name="normal" offset="429 70 3 3"/>
</BasisSkin>
<BasisSkin type="SubSkin" offset="3 0 3 3" align="HStretch Top">
<State name="normal" offset="435 70 3 3"/>
</BasisSkin>
<BasisSkin type="SubSkin" offset="6 0 5 3" align="Right Top">
<State name="normal" offset="447 70 5 3"/>
</BasisSkin>
<BasisSkin type="SubSkin" offset="0 3 3 3" align="Left VStretch">
<State name="normal" offset="429 76 3 3"/>
</BasisSkin>
<BasisSkin type="SubSkin" offset="3 3 3 3" align="Stretch">
<State name="normal" offset="432 5 65 57"/>
</BasisSkin>
<BasisSkin type="SubSkin" offset="6 3 5 3" align="Right VStretch">
<State name="normal" offset="447 76 5 3"/>
</BasisSkin>
<BasisSkin type="SubSkin" offset="0 6 3 5" align="Left Bottom">
<State name="normal" offset="429 87 3 5"/>
</BasisSkin>
<BasisSkin type="SubSkin" offset="3 6 3 5" align="HStretch Bottom">
<State name="normal" offset="435 87 3 5"/>
</BasisSkin>
<BasisSkin type="SubSkin" offset="6 6 5 5" align="Right Bottom">
<State name="normal" offset="447 87 5 5"/>
</BasisSkin>
</Resource>
2.4皮肤文件的属性:
假设要自己实现控件,要继承widget,往往还要实现这个函数,这个函数就是包含widget的皮肤属性,你也可以加上你要的皮肤属性。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
void
Widget :: initialiseWidgetSkin (ResourceSkin * _info, const
IntSize & _size)
{
/*............省略...............................*/
Widget :: setState ("normal") ;//*/ /*/ FIXME - explicit call
/// / Parse properties
const
MapString & properties = _info-> getProperties ();
if (! properties.empty ())
{
MapString :: const_iterator
iter = properties.end ();
if ((iter = properties.find ("NeedKey"))! = properties.end ()) setNeedKeyFocus (utility :: parseBool (iter-> second));
if ((iter = properties.find ("NeedMouse"))! = properties.end ()) setNeedMouseFocus (utility :: parseBool (iter-> second));
if ((iter = properties.find ("Pointer"))! = properties.end ()) mPointer = iter-> second;
if ((iter = properties.find ("Visible"))! = properties.end ()) {setVisible (utility :: parseBool (iter-> second));}
// / / OBSOLETE
if ((iter = properties.find ("AlignText"))! = properties.end ()) _setTextAlign (Align :: parse (iter-> second));
if ((iter = properties.find ("Colour"))! = properties.end ()) _setTextColour (Colour :: parse (iter-> second));
if ((iter = properties.find ("Show"))! = properties.end ()) {setVisible (utility :: parseBool (iter-> second));}
if ((iter = properties.find ("TextAlign"))! = properties.end ()) _setTextAlign (Align :: parse (iter-> second));
if ((iter = properties.find ("TextColour"))! = properties.end ()) _setTextColour (Colour :: parse (iter-> second));
if ((iter = properties.find ("FontName"))! = properties.end ()) _setFontName (iter-> second);
if ((iter = properties.find ("FontHeight"))! = properties.end ()) _setFontHeight (utility :: parseInt (iter-> second));
}
/*............省略...............................*/
}
中文显示
3.1(非常简单,请参考网上文章)
常用的Widget
各个事件的原型:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//Delegates to the event widget
typedef
delegates::CDelegate1<Widget*> EventHandle_WidgetVoid;
typedef
delegates::CDelegate2<Widget*, Widget*> EventHandle_WidgetWidget;
typedef
delegates::CDelegate2<Widget*, bool> EventHandle_WidgetBool;
typedef
delegates::CDelegate2<Widget*, int> EventHandle_WidgetInt;
typedef
delegates::CDelegate2<Widget*, size_t> EventHandle_WidgetSizeT;
typedef
delegates::CDelegate3<Widget*, int, int> EventHandle_WidgetIntInt;
typedef
delegates::CDelegate4<Widget*, int, int, MouseButton> EventHandle_WidgetIntIntButton;
typedef
delegates::CDelegate2<Widget*, KeyCode> EventHandle_WidgetKeyCode;
typedef
delegates::CDelegate3<Widget*, KeyCode, Char> EventHandle_WidgetKeyCodeChar;
typedef
delegates::CDelegate3<Widget*, const
std::string&, const
std::string&> EventHandle_WidgetStringString;
typedef
delegates::CDelegate3<Widget*, Widget*&, size_t &> EventHandle_WidgetRefWidgetRefSizeT;
typedef
delegates::CDelegate2<Widget*, const
ToolTipInfo& > EventHandle_WidgetToolTip;
/** Event : Widget lost mouse focus.\n
signature : void method(MyGUI::Widget* _sender, MyGUI::Widget* _new)\n
@param _sender widget that called this event
@param _new widget with mouse focus or nullptr
*/
EventHandle_WidgetWidget
eventMouseLostFocus;
/** Event : Widget got mouse focus.\n
signature : void method(MyGUI::Widget* _sender, MyGUI::Widget* _old)\n
@param _sender widget that called this event
@param _old widget with mouse focus or nullptr
*/
EventHandle_WidgetWidget
eventMouseSetFocus;
/** Event : Widget mouse move with captured widget.\n
signature : void method(MyGUI::Widget* _sender, int _left, int _top)\n
@param _sender widget that called this event
@param _left - pointer position
@param _top - pointer position
*/
EventHandle_WidgetIntInt
eventMouseDrag;
/** Event : Mouse move over widget.\n
signature : void method(MyGUI::Widget* _sender, int _left, int _top)\n
@param _sender widget that called this event
@param _left - pointer position
@param _top - pointer position
*/
EventHandle_WidgetIntInt
eventMouseMove;
/** Event : Mouse wheel over widget.\n
signature : void method(MyGUI::Widget* _sender, int _rel)\n
@param _sender widget that called this event
@param _rel relative wheel position
*/
EventHandle_WidgetInt
eventMouseWheel;
/** Event : Mouse button pressed.\n
signature : void method(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id)\n
@param _sender widget that called this event
@param _left - pointer position
@param _top - pointer position
@param _id Mouse button id
*/
EventHandle_WidgetIntIntButton
eventMouseButtonPressed;
/** Event : Mouse button released.\n
signature : void method(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id)\n
@param _sender widget that called this event
@param _left - pointer position
@param _top - pointer position
@param _id Mouse button id
*/
EventHandle_WidgetIntIntButton
eventMouseButtonReleased;
/** Event : Mouse button pressed and released.\n
signature : void method(MyGUI::Widget* _sender)
@param _sender widget that called this event
*/
EventHandle_WidgetVoid
eventMouseButtonClick;
/** Event : Mouse button double click.\n
signature : void method(MyGUI::Widget* _sender)
@param _sender widget that called this event
*/
EventHandle_WidgetVoid
eventMouseButtonDoubleClick;
/** Event : Widget lost keyboard focus.\n
signature : void method(MyGUI::Widget* _sender, MyGUI::Widget* _new)\n
@param _sender widget that called this event
@param _new widget with keyboard focus or nullptr
*/
EventHandle_WidgetWidget
eventKeyLostFocus;
/** Event : Widget got keyboard focus.\n
signature : void method(MyGUI::Widget* _sender, MyGUI::Widget* _old)\n
@param _sender widget that called this event
@param _old widget with keyboard focus or nullptr
*/
EventHandle_WidgetWidget
eventKeySetFocus;
/** Event : Key pressed.\n
signature : void method(MyGUI::Widget* _sender, MyGUI::KeyCode _key, MyGUI::Char _char)\n
@param _sender widget that called this event
@param _key code
@param _char of pressed symbol (for multilanguage applications)
*/
EventHandle_WidgetKeyCodeChar
eventKeyButtonPressed;
/** Event : Key released.\n
signature : void method(MyGUI::Widget* _sender, MyGUI::KeyCode _key)\n
@param _sender widget that called this event
@param _key code
*/
EventHandle_WidgetKeyCode
eventKeyButtonReleased;
/** Event : Root widget changed mouse focus.\n
info : this event sends only to root widget\n
signature : void method(MyGUI::Widget* _sender, bool _focus);
@param _sender widget that called this event
@param _focus Is widget got mouse focus.
*/
EventHandle_WidgetBool
eventRootMouseChangeFocus;
/** Event : Root widget changed keyboard focus.\n
info : this event sends only to root widget\n
signature : void method(MyGUI::Widget* _sender, bool _focus);
@param _sender widget that called this event
@param _focus Is widget got keyboard focus.
*/
EventHandle_WidgetBool
eventRootKeyChangeFocus;
/** Event : Event about changing tooltip state.\n
signature : void method(MyGUI::Widget* _sender, const MyGUI::ToolTipInfo& _info);
@param _sender widget that called this event
@param _info about tooltip
*/
EventHandle_WidgetToolTip
eventToolTip;
/** Event : Extendeble event for special cases or plugins.\n
signature : void method(MyGUI::Widget* _sender, const std::string& _key, const std::string& _value);
@param _sender widget that called this event
@param _key
@param _value
*/
EventHandle_WidgetStringString
eventActionInfo;
/** Event : Internal request for parent and item index, used for any widget.\n
signature : void method(MyGUI::Widget* _sender, MyGUI::Widget*& _container, size_t& _index);
@param _sender widget that called this event
@param _container parent
@param _index of container
*/
EventHandle_WidgetRefWidgetRefSizeT
_requestGetContainer;
/** Event : Widget property changed through setProperty (in code, or from layout)\n
signature : void method(MyGUI::Widget* _sender, const std::string& _key, const std::string& _value);
@param _sender widget that called this event
@param _key
@param _value
*/