Можно ли использовать внедрение зависимостей в Qt Designer (для файлов .ui)? - PullRequest
0 голосов
/ 28 января 2019

Мы разрабатываем на C ++ (и Qt) с использованием Visual Studio 2015 и Qt Designer для нашего пользовательского интерфейса (с помощью файлов формы / .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_FooDialog обрабатывает FooWidget как универсальный QWidget, который требует / принимает только QWidget* parent в конструкторе - я не могу предоставить указатель или ссылку на мой общий TextColourAndSize object.

Я знаю, что мог бы создать второй ui->widget->setupTextColourAndSize(...) шаг в FooDialog (после начального ui->setupUi(this)), который предоставляет этот общий объект данных, но имеющий две функции типа init(), выглядит какдовольно неприятный запах кода (достаточно плохой).

Ответы [ 3 ]

0 голосов
/ 28 января 2019

FooWidget нужны два конструктора и установщик для зависимости:

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*)

При любых обстоятельствах вам необходимо повысить класс fooWidget до FooWidget класса.в Qt Designer.

0 голосов
/ 30 января 2019

Это были хорошие решения, но, говоря о внедрении зависимостей, есть также возможность повеселиться с 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());
}

множественное наследование +Получение виджетов из небольшого прокси-класса шаблонов работает как для пользовательских виджетов, так и для тех, которые имеют формы пользовательского интерфейса.Я поместил FooWidget в FooDialog (через механизм распространения) в скриншоте выше и получил два окна сообщений.

Сама идея может быть реализована лучше, с более разумным использованием шаблона, просто попытался уменьшить пример кода,в любом случае, это непростое осложнение.Но технически это работает без каких-либо дополнительных инициализаций =)

0 голосов
/ 28 января 2019

Хорошо, из того, что я вижу, вам не нужно "внедрение зависимости".Вопрос был неверно сформулирован.

Вы можете использовать этот пользовательский виджет напрямую из Qt designer.

  1. Когда вы создаете FooDialog, поместите обычный виджет QWidget на место, где вам нужноиметь FooWidget.
  2. Затем «продвинуть» обычный виджет на FooWidget (возможно, вам придется добавить некоторую простую информацию об этом типе) - (Я делал это давным-давно и не помню всех деталей).

Для получения подробных инструкций просто google: qt продвигать виджет qt designer , вы найдете множество примеров, как это сделать.

...