这是我的问题:
在我正在开发的游戏中,“桌面”是我称之为WidgetManager的类。为了让我在gui和一个小部件之间传达某些事物,比如焦点,每个小部件都必须有一个指向小部件管理器的指针。问题是,用户可以将子项添加到小部件中,该小部件还不是小部件管理器的一部分。这是我的hacky解决方案的用武之地:
AguiWidgetManager* AguiWidget::getWidgetManager() const
{
if(_container)
return _container;
if(getTopWidget())
{
if(getTopWidget()->getWidgetManager())
{
((AguiWidget*) this)->_container =
getTopWidget()->getWidgetManager();
return _container;
}
}
if(getParent())
{
if(getParent()->getWidgetManager())
{
((AguiWidget*) this)->_container =
getParent()->getWidgetManager();
return _container;
}
}
return (AguiWidgetManager*)NULL;
}
我知道这在多大程度上是一个糟糕的想法和可怕的代码,并打破了常量,但我不确定如何确保小部件有一个容器。
首先我想到在添加它时将widget管理器指针设置为其父级的指针,但就像我说的那样,它的父级可能当时也没有。
由于
答案 0 :(得分:1)
如果每个Widget都是由WidgetManager创建的,您可以在创建过程中传入它。
但是,我认为,你的问题来自于将WidgetManager(可能更好地称为WidgetFactory)和顶级Widget的功能结合起来。我可以想到两种可能的解决方案,包括利弊。
1:有一个生成小部件的WidgetFactory。在引擎中,保留指向根Widget的指针。这是您的桌面,要显示的所有窗口小部件必须是此子窗口(树的基础)。
渲染小部件时,只需调用RootWidget->Render()
,它就会以递归方式呈现其子级等。
同样,要从任何给定的Widget中备份树,您可以调用widget->GetParent()
并给它父级。进一步调用将逐步启动树,直到您到达根小部件,该小部件没有父级(由引擎直接使用)。
那里的设置相对简单易用,但你需要拆分小部件和创建它的东西。
2:如果你想拥有一个移动小部件工厂,它也可以作为你的小部件军队的操作基础,你可以给它一些与小部件相同的属性。最干净的方法是让WidgetManager从Widget类派生,看起来像这样:
class Widget
{
virtual void Render() { for_each(mChildren, child->Render()); }
virtual Widget * GetParent(); // Returns pointer to parent
virtual WidgetType GetType() { return WT_Widget; }
private:
WidgetList mChildren;
Widget * mParent;
}
class WidgetManager
: public Widget
{
Widget * GetParent() { return NULL; }
WidgetType GetType() { return WT_Manager; }
}
这提供了一种处理两者的简便方法。 WidgetManager有它的子节点,并且像每个Widget一样渲染它们,并且因为你调用widget->GetParent()
并且它适用于两者而工作备份树非常简单。
如果GetParent()返回NULL,则可以通过调用GetType来验证是否已到达WidgetManager。如果返回WT_Widget
,则可能会出现问题。
编辑:您还可以让WidgetManager保存指向单个根小部件的指针,该小部件的标志设置为顶部。然后使用方法1中的想法来处理小部件树的工作。