前篇:《MyGui笔记(2)控件类型和皮肤》
本篇:创建控件的方法要传入控件对齐方式,创建根控件还需传入将被创建到哪一层的名称。
环境:MyGui3.2.0(OpenGL平台)
控件的对齐方式,定义在Align里面,所定义的方式如下:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
enum Enum
{ HCenter = MYGUI_FLAG_NONE, /**< 水平居中 */ VCenter = MYGUI_FLAG_NONE, /**< 垂直居中 */ Center = HCenter | VCenter, /**< 中心居中 */ Left = MYGUI_FLAG( 1), /**< 居左 (并且垂直居中) */ Right = MYGUI_FLAG( 2), /**< 居右 (并且垂直居中) */ HStretch = Left | Right, /**< 按与父窗口的比例进行水平拉伸 (并且垂直居中) */ Top = MYGUI_FLAG( 3), /**< 居上 (并且水平居中) */ Bottom = MYGUI_FLAG( 4), /**< 居下 (并且水平居中) */ VStretch = Top | Bottom, /**< 按与父窗口的比例进行垂直拉伸 (并且水平居中) */ Stretch = HStretch | VStretch, /**< 按与父窗口的比例进行拉伸 */ Default = Left | Top /**< 默认值 (居左和居上) */ }; |
并不仅这些方式,还可以自己进行组合,如:
1
2 |
Left | VStretch
/**< 居左和按与父窗口的比例进行垂直拉伸 */
HStretch | Bottom /**< 按与父窗口的比例进行水平拉伸和居下 */ |
每当父窗口进行位置或者大小改变,都会对其子控件进行重新计算位置和大小,代码如下:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
//_oldsize 父控件旧的大小 //_newSize 父控件新的大小 void Widget::_setAlign( const IntSize& _oldsize, const IntSize& _newSize) { const IntSize& size = _newSize; //getParentSize(); bool need_move = false; bool need_size = false; IntCoord coord = mCoord; // 对齐方式 if (mAlign.isHStretch()) { // 拉伸 coord.width = mCoord.width + (size.width - _oldsize.width); need_size = true; } else if (mAlign.isRight()) { // 向右移动 coord.left = mCoord.left + (size.width - _oldsize.width); need_move = true; } else if (mAlign.isHCenter()) { // 没有拉伸的水平对齐 coord.left = (size.width - mCoord.width) / 2; need_move = true; } if (mAlign.isVStretch()) { // 拉伸 coord.height = mCoord.height + (size.height - _oldsize.height); need_size = true; } else if (mAlign.isBottom()) { // 向下移动 coord.top = mCoord.top + (size.height - _oldsize.height); need_move = true; } else if (mAlign.isVCenter()) { // 没有拉伸的垂直居中 coord.top = (size.height - mCoord.height) / 2; need_move = true; } if (need_move) { if (need_size) setCoord(coord); else setPosition(coord.point()); } else if (need_size) { setSize(coord.size()); } else { _updateView(); // 无需移动和改变大小 } } |
每个根控件创建的时候,需要指定其所在层,所有的层定义在MyGUI_Layers.xml文件,这个文件内容为:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
<?xml version=
"1.0"
encoding=
"UTF-8"
?>
<MyGUI type= "Layer" version= "1.2" > <Layer type= "SharedLayer" name= "Wallpaper" > <Property key= "Pick" value= "false" /> </Layer> <Layer type= "SharedLayer" name= "Back" > <Property key= "Pick" value= "true" /> </Layer> <Layer type= "OverlappedLayer" name= "Overlapped" > <Property key= "Pick" value= "true" /> </Layer> <Layer type= "SharedLayer" name= "Middle" > <Property key= "Pick" value= "true" /> </Layer> <Layer type= "OverlappedLayer" name= "Modal" > <Property key= "Pick" value= "true" /> </Layer> <Layer type= "SharedLayer" name= "Main" > <Property key= "Pick" value= "true" /> </Layer> <Layer type= "OverlappedLayer" name= "Popup" > <Property key= "Pick" value= "true" /> </Layer> <Layer type= "SharedLayer" name= "FadeMiddle" > <Property key= "Pick" value= "false" /> </Layer> <Layer type= "OverlappedLayer" name= "Info" > <Property key= "Pick" value= "true" /> </Layer> <Layer type= "SharedLayer" name= "ToolTip" > <Property key= "Pick" value= "false" /> </Layer> <Layer type= "SharedLayer" name= "DragAndDrop" > <Property key= "Pick" value= "false" /> </Layer> <Layer type= "SharedLayer" name= "FadeBusy" > <Property key= "Pick" value= "false" /> </Layer> <Layer type= "SharedLayer" name= "Pointer" > <Property key= "Pick" value= "false" /> </Layer> <Layer type= "SharedLayer" name= "Fade" > <Property key= "Pick" value= "false" /> </Layer> <Layer type= "SharedLayer" name= "Statistic" > <Property key= "Pick" value= "false" /> </Layer> </MyGUI> |
可以看到层类型分为两种:SharedLayer和OverlappedLayer。
SharedLayer :SharedLayer为简单无重叠的层,重叠的控件可能会出现绘制顺序不正确,整个SharedLayer在一个批次中进行渲染。
OverlappedLayer :当在一个层(例如:窗口)中含有重叠的控件,那么应该使用OverlappedLayer 。每个根控件进行批次渲染,所以如果层上的控件没有打算进行彼此重叠的话,那么使用SharedLayer。
层的名称标识符,用在皮肤、布局和代码里。Pick属性设置控件是否能够响应鼠标消息,如果设置为false,鼠标指针会忽略这个层上的所有控件,直接穿透到下一层。创建根控件调用代码如下:
1
2 3 4 5 6 7 8 9 10 11 12 |
Widget* Gui::baseCreateWidget(WidgetStyle _style,
const std::string& _type,
const std::string& _skin,
const IntCoord& _coord, Align _align,
const std::string& _layer,
const std::string& _name)
{ Widget* widget = WidgetManager::getInstance().createWidget(_style, _type, _skin, _coord, /*_align, */nullptr, nullptr, _name); mWidgetChild.push_back(widget); widget->setAlign(_align); // 附加控件到层上 if (!_layer.empty()) LayerManager::getInstance().attachToLayerNode(_layer, widget); return widget; } |
层管理器LayerManager负责将控件添加到相应的层上,attachToLayerNode代码为:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
void LayerManager::attachToLayerNode(
const std::string& _name, Widget* _item)
{ MYGUI_ASSERT(nullptr != _item, "pointer must be valid"); MYGUI_ASSERT(_item->isRootWidget(), "attached widget must be root"); // 从原先的层分离 _item->detachFromLayer(); // 附加到新的层上 for (VectorLayer::iterator iter = mLayerNodes.begin(); iter != mLayerNodes.end(); ++iter) { if (_name == (*iter)->getName()) { ILayerNode* node = (*iter)->createChildItemNode(); node->attachLayerItem(_item); return; } } MYGUI_LOG(Error, "Layer '" << _name << "' is not found"); //MYGUI_EXCEPT("Layer '" << _name << "' is not found"); } |
可以看到限制了控件必须为根控件,如果控件原先有附加到其他层上,则必须先分离。接着遍历mLayerNodes,它存储着MyGUI_Layers.xml里面所有的层信息,找到对应的层名称,根据相应的层类型来创建一个子节点,将控件添加到这个子节点上。代码如下:
1
2 3 4 5 6 7 |
void LayerNode::attachLayerItem(ILayerItem* _item)
{ mLayerItems.push_back(_item); _item->attachItemToNode(mLayer, this); mOutOfDate = true; } |
可以看到这个控件加入到mLayerItems列表里面,mLayerItems存放着所有的控件指针,对于重叠层来说,这里面只存放一个。接着控件调用attachItemToNode方法,这个方法代码如下:
1
2 3 4 5 6 7 |
void LayerItem::attachItemToNode(ILayer* _layer, ILayerNode* _node)
{ mLayer = _layer; mLayerNode = _node; attachToLayerItemNode(_node, true); } |
继续调用方法attachToLayerItemNode,代码如下:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
void LayerItem::attachToLayerItemNode(ILayerNode* _item,
bool _deep)
{ MYGUI_DEBUG_ASSERT(nullptr != _item, "attached item must be valid"); mLayerNode = _item; for (VectorSubWidget::iterator skin = mDrawItems.begin(); skin != mDrawItems.end(); ++skin) { (*skin)->createDrawItem(mTexture, _item); } for (VectorLayerItem::iterator item = mLayerItems.begin(); item != mLayerItems.end(); ++item) { (*item)->attachToLayerItemNode(_item, _deep); } for (VectorLayerItem::iterator item = mLayerNodes.begin(); item != mLayerNodes.end(); ++item) { if (_deep) { ILayerNode* child_node = _item->createChildItemNode(); (*item)->attachToLayerItemNode(child_node, _deep); } } } |
更多资料:
1.MyGUI layers http://www.ogre3d.org/tikiwiki/tiki-index.php?page=MyGUI+layers