我想知道为什么您认为 Qt 工程师决定将setupUi()
方法放入每种生成的形式中。
(对于那些不了解Qt如何工作的人:setupUi()
是一种在动态内存中分配表单内每个按钮,texbox,小部件的方法。每个元素的引用都存储在指针成员变量中,该成员变量甚至没有初始化为nullptr
和它放置在public:
访问修饰符下,因此在您实际调用setupUi()
之前,这看起来也有些危险。
在我的新观点看来,这完全违反了 RAII的原则,因为这意味着任何Ui_Whatever类实际上都不是由其构造函数调用构造的:构造函数只是分配该类本身,但是在我们调用Ui_Whatever::setupUi()
之前它是不可用的。
可能是以下原因导致的设计原因:
(我问是因为我根本无法弄清楚自己的任何正当理由)
提前致谢!!
最佳答案
我同意,这完全违反了RAII原则。但是我找到了一个相当简单的解决方法:
template<typename UiClass> class QtRaiiWrapper : public UiClass
{
public:
QtRaiiWrapper(QMainWindow *MainWindow)
{
setupUi(MainWindow);
}
};
...
#include "ui_Main.h"
class MainWindow : public QMainWindow
{
Q_OBJECT
...
private:
// Ui_MainWindow m_Ui; // no RAII
QtRaiiWrapper<Ui_MainWindow> m_Ui; // RAII
};
(它可能需要一些改进,但这是基本思想,对我来说效果很好。)
关于该主题的更多讨论:
Qt选择通过setupUi进行初始化的选择不仅为此组件缺少RAII,而且还可能使RAII对于程序的其他部分无法实现,这是很糟糕的。在我的情况下,另一个对象使用GUI元素的值进行初始化(这样,我可以在QtDesigner中定义初始值,而不是在其中使用伪值并在启动时覆盖它),但是不能使用RAII,因为GUI只能在MainWindow的构造函数的内部初始化。
因此,我不同意库巴·奥伯(Kuba Ober)的意见,您无法完全控制何时确切地希望GUI初始化,因为您只能在构造函数主体而不是初始化列表中进行操作(在RAII之后,初始化列表是您可以在其中进行初始化的地方)也许大多数初始化都应该发生)。但是幸运的是,C++非常棒,我们可以为此编写一个解决方法(如上所述)。我还认为,这比更改
uic
的方式要好得多,因为一旦其他人尝试编译您的代码,他们就会看到很大的惊喜。