我正在用QT编写程序,该程序当前具有GameEngine
(数据处理)类和MainWindow
(GUI)类。
GameEngine
和MainWindow
类的单个实例由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_UserAction
与GameEngine
连接起来?
如果没有,您对我一般如何以更好的方式解决这个问题有任何建议吗?预先感谢。
答案 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;
然后在Main
和Dialog_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) );
}