Qt Designer是否可以使用依赖项注入(用于.ui文件)?

时间:2019-01-28 09:52:54

标签: c++ visual-studio qt dependency-injection qt-designer

我们正在使用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()类型的函数似乎是一种相当糟糕的代码气味(一个够糟糕)。

3 个答案:

答案 0 :(得分:2)

好吧,据我所知,您不需要“依赖注入”。问题被错误地陈述。

您可以直接从Qt设计器中使用此自定义小部件。

  1. 在创建FooDialog时,将常规小部件QWidget放在需要FooWidget的位置。
  2. 然后将这个小部件“升级”到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(通过传播机制),并得到了两个消息框。

通过更聪明地使用模板,可以更好地实现该想法本身,只是试图减少示例代码,无论如何这都是不必要的复杂性。但是从技术上讲,它无需任何其他初始化即可工作=)