Соединение слотов и сигналов между экземпляром класса и диалогом внутри другого экземпляра класса - PullRequest
1 голос
/ 21 апреля 2019

Я пишу программу на QT, которая в настоящее время имеет класс GameEngine (обработка данных) и класс MainWindow (GUI).

Отдельные экземпляры классов GameEngine и MainWindow принадлежат функции int main.

Экземпляр MainWindow имеет кнопку User Action, которая откроет экземпляр класса QDialog с именем Dialog_UserAction. Экземпляр этого QDialog принадлежит MainWindow, который также является родителем QDialog (для отключения графического интерфейса пользователя MainWindow, когда экземпляр Dialog_UserAction открыт).

Моя проблема в том, что многие события (сигналы) должны быть связаны между QDialog и экземпляром GameEngine.

Есть ли какой-нибудь простой способ, которым я могу этого достичь?

Я уже пробовал перенаправить сигналы с Dialog_UserAction на GameEngine через MainBoard и наоборот. Это работает, но это довольно грязное решение для этой задачи.

Я также пытался разрешить владение Dialog_UserAction Main, но я не знаю, как реагировать на User Action Button clicked событие в главном контексте.

Наконец, я также попытался разрешить владение Dialog_UserAction экземпляром GameEngine, что было бы простым решением (за исключением того, что графический интерфейс MainBoard не будет отключен, пока открыт Dialog_UserAction). Но я бы действительно предпочел, чтобы все связанные с GUI экземпляры не попадали в контекст GameEngine.

GameEngine.h:

class GameEngine : public QObject
{
    Q_OBJECT

signals:
    void someSignalToDialog(void);

public slots:
    void on_someSignalFromDialog();
}

Dialog_UserAction.h:

class Dialog_UserAction: public QObject
{
    Q_OBJECT

signals:
    void someSignalToGameEngine(void);

public slots:
    void on_someSignalFromGameEngine();
}

main.cpp:

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);
    QApplication::setWindowIcon(QIcon(":/images/MageKnightLogo.jpg"));
    GameEngine gameEngine;
    Window_MainBoard mainBoard;

    mainBoard.showFullScreen();

    return a.exec();
}

MainBoard.cpp:

#include "Dialog_UserAction.h"

...

void Window_MainBoard::on_pushButton_enterUserAction_clicked() {
    Dialog_UserAction actionDialog(this);

    // connect signals and slots here?

    if (actionDialog.exec() == QDialog::Accepted)
    {
        // Send signal with data to GameEngine
    }
}
...

Итак, я действительно спрашиваю: Есть ли какой-нибудь простой способ, которым я могу настроить соединения сигнальных слотов в этой настройке, где я могу соединить Dialog_UserAction с GameEngine без пересылки сигналов в контексте MainBoard?

Если нет, есть ли у вас какие-либо предложения о том, как я мог бы подойти к этому лучше вообще? Заранее спасибо.

Ответы [ 2 ]

0 голосов
/ 22 апреля 2019

Итак, просто для пояснения, я прекратил использовать шаблон проектирования Singleton, предложенный Никосом С.

Но я реализовал класс немного по-другому, и поэтому хотел поделиться этим как отдельным ответом.

Я обнаружил, что мне нужно каким-то образом вызвать конструктор объекта, и решил, что это можно сделать с помощью так называемого (я полагаю) метода Lazy Initialization. Кроме того, конструктор класса должен быть закрытым, чтобы его мог вызывать только сам экземпляр, и, таким образом, следил за тем, чтобы конструктор вызывался только один раз.

Кроме того, я сделал метод GameEngine::Instance() как const static GameEngine* -тип, чтобы доступ к объекту был только для чтения.

GameEngine.h

class GameEngine
{

public:
    const static GameEngine* instance() { // Singleton instance reference getter
        if (instance_ == nullptr)
            instance_ = new GameEngine(); // This triggers the constructor of the object
        return instance_;
    }

private:
    GameEngine(); // The constructor is made private!
};

GameEngine.cpp

// Place this declaration in the top of the file to create the global class instance pointer
// The initial value of the pointer must be nullptr to let the constructor be correctly triggered at the first instance()-call
GameEngine* GameEngine::instance_ = nullptr;

Затем в Main и Dialog_UserAction (клиенты) доступ к экземпляру Singleton GameEngine используется путем создания указателя экземпляра класса const в каждом контексте.

main.cpp

#include "GameEngine.h"

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);
    Window_MainBoard mainBoard;

    const GameEngine* gameEngine = GameEngine::instance(); // Const pointer to the Singleton instance of the GameEngine class (global object)

    QObject::connect(gameEngine, SIGNAL(someSignalToDialog), &mainBoard, SLOT(on_someSignalFromGameEngine));
}

Dialog_UserAction.cpp

#include "GameEngine.h"

// Constructor
Dialog_UserAction::Dialog_UserAction(QWidget *parent) : QDialog(parent), ui(new Ui::Dialog_UserAction) {
    ui->setupUi(this);

    // Const pointer to the Singleton instance of the GameEngine class (global object)
    const GameEngine* gameEngine = GameEngine::instance();

    connect(this, SIGNAL(someSignalToGameEngine), gameEngine, SLOT(on_someSignalFromDialog)                                                                );
}
0 голосов
/ 21 апреля 2019

Поскольку объект GameEngine является одноэлементным (существует только один экземпляр), вы можете сделать так, чтобы объект Dialog_UserAction подключал свои сигналы непосредственно к объекту GameEngine. Вы можете сделать это в конструкторе Dialog_UserAction.

Чтобы получить легкий доступ к объекту GameEngine, просто добавьте к нему статическую функцию-член, которая возвращает статический GameEngine* член.

GameEngine.h

class GameEngine
{
public:
    GameEngine()
    {
        Q_ASSERT(instance_ == nullptr); // Only one instance allowed.
        instance_ = this;
    }

    static GameEngine* instance() noexcept
    { return instance_; }

private:
    static GameEngine* instance_;
};

GameEngine.cpp

GameEngine* GameEngine::instance_ = nullptr;

Теперь вы можете подключить Dialog_UserAction сигналы к GameEngine::instance().

...