在类实例和另一个类实例中的对话框之间连接插槽和信号

时间:2019-04-21 16:39:39

标签: c++ qt hierarchy

我正在用QT编写程序,该程序当前具有GameEngine(数据处理)类和MainWindow(GUI)类。

GameEngineMainWindow类的单个实例由int main函数拥有。

MainWindow实例具有一个User Action按钮,它将打开一个名为Dialog_UserAction的QDialog类的实例。该QDialog的实例由MainWindow拥有,它也是QDialog的父级(在MainWindow实例打开时禁用Dialog_UserAction GUI)。

我的问题是QDialog和GameEngine实例之间需要连接许多事件(信号)。

有什么简单的方法可以实现这一目标吗?

我已经尝试过通过Dialog_UserAction将信号从GameEngine转发到MainBoard,反之亦然。这行得通,但是对于此任务来说却是一个很杂乱的解决方案。

我还尝试过让Dialog_UserAction拥有Main,但是我不知道如何在主要情况下对User Action Button clicked事件做出反应。

最后,我还尝试让Dialog_UserAction实例拥有GameEngine,这将是一个简单的解决方案(除了MainBoard GUI不会被禁用,而{{ 1}}打开)。但是,我真的希望所有与GUI相关的实例都被排除在Dialog_UserAction上下文之外。

  

GameEngine.h:

GameEngine
  

Dialog_UserAction.h:

class GameEngine : public QObject
{
    Q_OBJECT

signals:
    void someSignalToDialog(void);

public slots:
    void on_someSignalFromDialog();
}
  

Main.cpp:

class Dialog_UserAction: public QObject
{
    Q_OBJECT

signals:
    void someSignalToGameEngine(void);

public slots:
    void on_someSignalFromGameEngine();
}
  

MainBoard.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();
}

所以,我真正要问的是: 是否有任何简单的方法可以在此设置中设置信号插槽连接,而无需在#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_UserActionGameEngine连接起来?

如果没有,您对我一般如何以更好的方式解决这个问题有任何建议吗?预先感谢。

2 个答案:

答案 0 :(得分:0)

由于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()

答案 1 :(得分:0)

因此,为澄清起见,我结束了使用Nikos C建议的Singleton设计模式。

但是我对类的实现有所不同,因此希望将其作为一个独立的答案来分享。

我发现我需要以某种方式触发对象的构造函数,并发现可以使用所谓的(我相信)惰性初始化方法来完成。另外,该类的构造函数应该是私有的,这样只有实例本身才能调用此函数,从而确保构造函数仅被调用一次。

此外,为了使对对象的访问为只读,我将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;

然后在MainDialog_UserAction(客户端)中,通过在每个上下文中创建const类实例指针来使用对Singleton GameEngine实例的访问。

  

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)                                                                );
}