我们正在使用Visual Studio 2015和Qt Designer(通过Form / .ui文件)为用户界面使用C ++(和Qt)进行开发。
我们现在需要在UI元素之间共享一些公共数据(例如,最近使用的路径等),而我想通过依赖注入(即在构建过程中为UI提供对公共对象的引用)来实现此目的例如(ab)使用单例模式。
有人遇到过(并解决了)类似的问题吗?有没有明智的方法呢?
更新(详细说明):
例如,我有一个自定义FooWidget
,希望在我的FooDialog.ui
表单文件中使用。
// My custom Widget
class FooWidget : public QWidget {
Q_OBJECT
public:
FooWidget(QWidget* parent);
//...
}
// The FooDialog class (scaffolding created by Qt Designer)
class FooDialog : public QDialog {
Q_OBJECT
public:
FooDialog(QWidget* parent) : QDialog(parent), ui (new Ui::FooDialog()) {
ui->setupUp(this);
//...
}
private:
Ui::FooDialog* ui;
}
// The Ui::FooDialog class autogenerated(!) by Qt Designer
// I cannot (must not) change this code, as it will be regenerated every time
class Ui_FooDialog {
public:
FooWidget* widget;
void setupUi(QWidget *fooDialog) {
//...
widget = new FooWidget(fooDialog);
//...
}
}
namespace Ui { class ScannerStatus: public Ui_ScannerStatus {}; }
我想为FooWidget提供一个公共的数据对象(例如,在我的所有Ui类之间共享文本大小和颜色),但是我不能在构造函数中这样做(因为自动生成的Ui_FooDialog对待FooWidget
作为通用的QWidget
,在构造函数中只需要/需要一个QWidget* parent
-我无法提供指向共享的TextColourAndSize
对象的指针或引用。
我知道我可以在ui->widget->setupTextColourAndSize(...)
中创建第二个FooDialog
步骤(在初始ui->setupUi(this)
之后),该步骤提供了该公共数据对象,但是具有两个init()
类型的函数似乎是一种相当糟糕的代码气味(一个够糟糕)。
答案 0 :(得分:2)
好吧,据我所知,您不需要“依赖注入”。问题被错误地陈述。
您可以直接从Qt设计器中使用此自定义小部件。
FooDialog
时,将常规小部件QWidget
放在需要FooWidget
的位置。FooWidget
(可能您必须添加有关该类型的一些简单信息)-(我很久以前就做过,并不记得所有详细信息)。对于google: qt promote widget qt designer的详细说明,您会发现很多示例。
答案 1 :(得分:0)
FooWidget
需要两个构造函数,以及一个用于依赖项的setter:
explicit FooWidget(QObject *parent = nullptr) : QWidget(parent), … {
…
}
FooWidget(Dependency *dep, QObject *parent = nullptr) : FooWidget(parent) {
setDependency(dep);
}
void setDependency(Dependency *dep) {
…
}
然后,在构建窗口小部件后设置依赖项:
FooDialog(Dependency *dep, …) … {
setupUi(this);
ui->fooWidget->setDependency(dep);
}
这可以是自动化的:父窗口小部件可以具有保存指向依赖项的指针的属性,子窗口小部件可以自动找到它:
FooDialog(Dependency *, …) : … {
setProperty("dependency", dep);
setupUi(this);
}
FooWidget(QWidget *parent) : … {
auto *dep = parent() ? parent()->property("dependency").value<Dependency*>() : nullptr;
if (dep) setDependency(dep);
}
如果Dependency
是从QObject
派生的,这将毫不费力。否则,您需要在合适的头文件中包含以下内容:
class Dependency { … };
Q_DECLARE_METATYPE(Dependency*)
在所有情况下,您都需要在Qt Designer中将fooWidget
对象提升为FooWidget
类。
答案 2 :(得分:0)
这些是很好的解决方案,但是在谈论依赖注入时,还有一个选择可以使C ++变得有趣。我当然知道,这根本不是一个明智的解决方案,但尽管如此...
foowidget.h
#ifndef FOOWIDGET_H
#define FOOWIDGET_H
#include <QWidget>
class Something
{
public:
QString getHello() const
{ return "Hello world!"; }
};
/***************************************************/
template<typename T>
class Injector
{
public:
QString getHello() const
{ return m_dataContainer.getHello(); }
private:
T m_dataContainer;
};
/***************************************************/
class FooWidget : public QWidget, public Injector<Something>
{
Q_OBJECT
public:
explicit FooWidget(QWidget* parent = nullptr);
protected:
virtual void mousePressEvent(QMouseEvent*) override;
};
#endif // FOOWIDGET_H
foowidget.cpp
#include "foowidget.h"
#include <QMessageBox>
FooWidget::FooWidget(QWidget *parent)
: QWidget(parent)
{ }
void FooWidget::mousePressEvent(QMouseEvent*)
{
QMessageBox::information(nullptr, "Test", getHello());
}
foodialog.h
#ifndef FOODIALOG_H
#define FOODIALOG_H
#include <QDialog>
class SomethingElse
{
public:
QString getHello() const
{ return "OMG! OMG"; }
};
#include "foowidget.h"
namespace Ui {
class FooDialog;
}
class FooDialog : public QDialog, public Injector<SomethingElse>
{
Q_OBJECT
public:
explicit FooDialog(QWidget *parent = nullptr);
~FooDialog();
protected:
void showEvent(QShowEvent *) override;
private:
QScopedPointer<Ui::FooDialog> ui;
};
#endif // FOODIALOG_H
foodialog.cpp
#include "foodialog.h"
#include "ui_foodialog.h"
#include <QMessageBox>
FooDialog::FooDialog(QWidget *parent)
: QDialog(parent)
, ui(new Ui::FooDialog)
{
ui->setupUi(this);
}
FooDialog::~FooDialog()
{ }
void FooDialog::showEvent(QShowEvent *)
{
QMessageBox::information(nullptr, "Test", getHello());
}
多个继承+从某些小型模板代理类派生的小部件可用于自定义小部件以及具有UI表单的小部件。我已经在上面的草图中的FooDialog上放置了FooWidget(通过传播机制),并得到了两个消息框。
通过更聪明地使用模板,可以更好地实现该想法本身,只是试图减少示例代码,无论如何这都是不必要的复杂性。但是从技术上讲,它无需任何其他初始化即可工作=)