通过基础 class 自动化 window 编程
Automate window programming through a base class
我为一个应用程序编写了几个 windows,它们都继承了 Gtkmm::Window
。在这一点上,我想自动化这个过程。现在,以下结构脱颖而出:
class MyWindow : public Gtk::Window
{
public:
MyWindow();
virtual ~MyWindow();
//...
private:
void registerLayouts(); // Adds layouts to the window.
void registerWidgets(); // Adds widgets to the layouts.
//...
};
构造函数:
MyWindow::MyWindow()
{
registerLayouts(); // Cannot be virtual: in constructor.
registerWidgets(); // Cannot be virtual: in constructor.
//...
}
所以问题是所有这些都必须手动完成(即 copy/pasted),每次必须对新的 window 进行编程,因为 registerLayouts()
和 registerWidgets()
在构造时被调用,因此不能是 virtual
.
理想情况下,我会有一个可以继承的基础 class,它可以让我选择重写这两个方法并处理其余的事情:它会在适当的时候调用这两个方法位置。
问题是,我还没有找到这个合适的位置。我查看了不同的信号处理程序,但似乎有 none。
你知道我该怎么做吗?
MFC 具有 CDialog::OnInitDialog()
执行与我需要的类似的功能。
您可以将工作委派给一个单独的人 class:
class MyWindow : public Gtk::Window
{
//public: *** EDIT ***
protected:
template <typename LayoutManager>
MyWindow(LayoutManager const& lm)
{
lm.registerLayouts(this);
lm.registerWidgets(this);
}
};
class SubWindow : public MyWindow
{
class LM { /* ... */ };
public:
SubWindow() : MyWindow(LM()) { }
};
(已编辑:改进的模式隐藏了 public 子 classes 的布局管理器...)
或者,整个class作为模板(可能优于上面):
template <typename LayoutManager>
class MyWindow : public Gtk::Window
{
public:
MyWindow()
{
LayoutManager lm(*this);
lm.registerLayouts();
lm.registerWidgets();
}
};
class SpecificLayoutManager { /* ... */ };
using SpecificWindow = MyWindow<SpecificLayoutManager>;
如果您还需要布局管理器进行清理(我自己不熟悉 GTK...):
template <typename LayoutManager>
class MyWindow : public Gtk::Window
{
LayoutManager lm;
public:
MyWindow() : lm(*this)
{
lm.registerLayouts();
lm.registerWidgets();
}
virtual ~MyWindow()
{
// still access to lm...
}
};
重要的旁注:在我们所做的所有变体中尚未具有完全构造的派生class – 因此在布局管理器中转换为后者是不合法的(尝试了 curiously recurring template pattern,但出于完全相同的原因放弃了这个想法:也需要在 base 的构造函数中转换为 derived。
根据评论进行编辑:关于如何管理子class的其他成员的示例(使用上面的第三个变体,模板class 与布局管理器成员之一;lm
成员现在需要 protected
):
class SubWindowLayoutManager
{
template <typename>
friend class MyWindow;
friend class SubWindow;
int someMember;
void registerLayouts() { }
void registerWidgets() { }
};
class SubWindow : public MyWindow<SubWindowLayoutManager>
{
void doSomething()
{
lm.someMember = 77;
}
};
另外一个完全没有模板的新变体:
class MyWindow : public Gtk::Window
{
protected:
class LayoutManager
{
public:
virtual void registerLayouts(MyWindow* parent) = 0;
virtual void registerWidgets(MyWindow* parent) = 0;
};
std::unique_ptr<LayoutManager> lm;
MyWindow(std::unique_ptr<LayoutManager> lm)
: lm(std::move(lm))
{
this->lm->registerLayouts(this);
this->lm->registerWidgets(this);
}
};
class SubWindow : public MyWindow
{
class LM : public LayoutManager
{
public:
void registerLayouts(MyWindow* parent) override { }
void registerWidgets(MyWindow* parent) override { }
int someMember;
};
// convenience access function:
inline LM& lm()
{
return *static_cast<LM*>(MyWindow::lm.get());
}
public:
SubWindow() : MyWindow(std::make_unique<LM>()) { }
void doSomething()
{
//static_cast<LM*>(lm.get())->someMember = 77;
lm().someMember = 77;
}
};
我为一个应用程序编写了几个 windows,它们都继承了 Gtkmm::Window
。在这一点上,我想自动化这个过程。现在,以下结构脱颖而出:
class MyWindow : public Gtk::Window
{
public:
MyWindow();
virtual ~MyWindow();
//...
private:
void registerLayouts(); // Adds layouts to the window.
void registerWidgets(); // Adds widgets to the layouts.
//...
};
构造函数:
MyWindow::MyWindow()
{
registerLayouts(); // Cannot be virtual: in constructor.
registerWidgets(); // Cannot be virtual: in constructor.
//...
}
所以问题是所有这些都必须手动完成(即 copy/pasted),每次必须对新的 window 进行编程,因为 registerLayouts()
和 registerWidgets()
在构造时被调用,因此不能是 virtual
.
理想情况下,我会有一个可以继承的基础 class,它可以让我选择重写这两个方法并处理其余的事情:它会在适当的时候调用这两个方法位置。
问题是,我还没有找到这个合适的位置。我查看了不同的信号处理程序,但似乎有 none。
你知道我该怎么做吗?
MFC 具有 CDialog::OnInitDialog()
执行与我需要的类似的功能。
您可以将工作委派给一个单独的人 class:
class MyWindow : public Gtk::Window
{
//public: *** EDIT ***
protected:
template <typename LayoutManager>
MyWindow(LayoutManager const& lm)
{
lm.registerLayouts(this);
lm.registerWidgets(this);
}
};
class SubWindow : public MyWindow
{
class LM { /* ... */ };
public:
SubWindow() : MyWindow(LM()) { }
};
(已编辑:改进的模式隐藏了 public 子 classes 的布局管理器...)
或者,整个class作为模板(可能优于上面):
template <typename LayoutManager>
class MyWindow : public Gtk::Window
{
public:
MyWindow()
{
LayoutManager lm(*this);
lm.registerLayouts();
lm.registerWidgets();
}
};
class SpecificLayoutManager { /* ... */ };
using SpecificWindow = MyWindow<SpecificLayoutManager>;
如果您还需要布局管理器进行清理(我自己不熟悉 GTK...):
template <typename LayoutManager>
class MyWindow : public Gtk::Window
{
LayoutManager lm;
public:
MyWindow() : lm(*this)
{
lm.registerLayouts();
lm.registerWidgets();
}
virtual ~MyWindow()
{
// still access to lm...
}
};
重要的旁注:在我们所做的所有变体中尚未具有完全构造的派生class – 因此在布局管理器中转换为后者是不合法的(尝试了 curiously recurring template pattern,但出于完全相同的原因放弃了这个想法:也需要在 base 的构造函数中转换为 derived。
根据评论进行编辑:关于如何管理子class的其他成员的示例(使用上面的第三个变体,模板class 与布局管理器成员之一;lm
成员现在需要 protected
):
class SubWindowLayoutManager
{
template <typename>
friend class MyWindow;
friend class SubWindow;
int someMember;
void registerLayouts() { }
void registerWidgets() { }
};
class SubWindow : public MyWindow<SubWindowLayoutManager>
{
void doSomething()
{
lm.someMember = 77;
}
};
另外一个完全没有模板的新变体:
class MyWindow : public Gtk::Window
{
protected:
class LayoutManager
{
public:
virtual void registerLayouts(MyWindow* parent) = 0;
virtual void registerWidgets(MyWindow* parent) = 0;
};
std::unique_ptr<LayoutManager> lm;
MyWindow(std::unique_ptr<LayoutManager> lm)
: lm(std::move(lm))
{
this->lm->registerLayouts(this);
this->lm->registerWidgets(this);
}
};
class SubWindow : public MyWindow
{
class LM : public LayoutManager
{
public:
void registerLayouts(MyWindow* parent) override { }
void registerWidgets(MyWindow* parent) override { }
int someMember;
};
// convenience access function:
inline LM& lm()
{
return *static_cast<LM*>(MyWindow::lm.get());
}
public:
SubWindow() : MyWindow(std::make_unique<LM>()) { }
void doSomething()
{
//static_cast<LM*>(lm.get())->someMember = 77;
lm().someMember = 77;
}
};