使用 QStateMachine 在菜单屏幕之间切换
Posted
技术标签:
【中文标题】使用 QStateMachine 在菜单屏幕之间切换【英文标题】:Transitioning between menu screens with QStateMachine 【发布时间】:2012-03-11 02:46:45 【问题描述】:我正在考虑使用QStateMachine
在游戏中的菜单屏幕之间进行转换。但是,我不确定如何在状态之间发生转换时启动一些代码(例如show()
QWidget
)。我可以用普通的旧信号很容易地做到这一点(见注释掉的代码),但我认为我可以在使用过渡切换屏幕时做一些花哨的动画。
这是我的代码:
编辑:根据 Koying 的建议更新。
ApplicationWindow.h:
#include <QtGui>
#include <QStateMachine>
#include "MainMenu.h"
#include "LoadGameMenu.h"
class ApplicationWindow : public QMainWindow
Q_OBJECT
public:
ApplicationWindow();
private slots:
void mainMenuButtonClicked();
void loadGameMenuButtonClicked();
private:
MainMenu* mainMenu;
LoadGameMenu* loadGameMenu;
QStateMachine stateMachine;
QStackedWidget* stack;
;
ApplicationWindow.cpp:
ApplicationWindow::ApplicationWindow()
resize(800, 600);
stack = new QStackedWidget(this);
mainMenu = new MainMenu();
setCentralWidget(mainMenu);
loadGameMenu = new LoadGameMenu();
QState* mainMenuState = new QState();
QState* loadGameMenuState = new QState();
QAbstractTransition* loadTransition = mainMenuState->addTransition(
mainMenu, SIGNAL(loadGameClicked()), loadGameMenuState);
connect(loadTransition, SIGNAL(triggered()), this, SLOT(loadGameMenuButtonClicked()));
QAbstractTransition* mainMenuTransition = loadGameMenuState->addTransition(
loadGameMenu, SIGNAL(backToMainMenuClicked()), mainMenuState);
connect(mainMenuTransition, SIGNAL(triggered()), this, SLOT(mainMenuButtonClicked()));
stateMachine.addState(mainMenuState);
stateMachine.addState(loadGameMenuState);
stateMachine.setInitialState(mainMenuState);
stateMachine.start();
void ApplicationWindow::mainMenuButtonClicked()
setCentralWidget(mainMenu);
void ApplicationWindow::loadGameMenuButtonClicked()
setCentralWidget(loadGameMenu);
LoadGameMenu.h:
#include <QtGui>
class LoadGameMenu : public QWidget
Q_OBJECT
public:
LoadGameMenu();
signals:
void backToMainMenuClicked();
private:
QPushButton* loadGameButton;
QPushButton* backToMainMenuButton;
;
LoadGameMenu.cpp:
#include "LoadGameMenu.h"
LoadGameMenu::LoadGameMenu()
loadGameButton = new QPushButton(tr("Load"));
backToMainMenuButton = new QPushButton(tr("Main Menu"));
QObject::connect(backToMainMenuButton, SIGNAL(clicked()),
this, SIGNAL(backToMainMenuClicked()));
QVBoxLayout* layout = new QVBoxLayout();
layout->addWidget(loadGameButton);
layout->addWidget(backToMainMenuButton);
layout->setContentsMargins(300, 400, 300, 200);
setLayout(layout);
MainMenu.h:
#include <QtGui>
class MainMenu : public QWidget
Q_OBJECT
public:
MainMenu();
signals:
void newGameClicked();
void loadGameClicked();
private slots:
void exit();
private:
QPushButton* newGameButton;
QPushButton* loadGameButton;
QPushButton* exitGameButton;
QMenu* fileMenu;
;
MainMenu.cpp:
#include "MainMenu.h"
MainMenu::MainMenu()
newGameButton = new QPushButton(tr("New Game"), this);
loadGameButton = new QPushButton(tr("Load Game"));
exitGameButton = new QPushButton(tr("Exit"));
QObject::connect(newGameButton, SIGNAL(clicked()), this, SIGNAL(newGameClicked()));
QObject::connect(loadGameButton, SIGNAL(clicked()), this, SIGNAL(loadGameClicked()));
QObject::connect(exitGameButton, SIGNAL(clicked()), qApp, SLOT(quit()));
QVBoxLayout* layout = new QVBoxLayout();
layout->addWidget(newGameButton);
layout->addWidget(loadGameButton);
layout->addWidget(exitGameButton);
layout->setContentsMargins(300, 200, 300, 200);
setLayout(layout);
void MainMenu::exit()
if( QMessageBox::question(
this,
tr("Exit?"),
tr("Do you really want to exit the game?"),
QMessageBox::Yes | QMessageBox::No,
QMessageBox::No
) == QMessageBox::Yes
)
qApp->quit();
main.cpp:
#include <QtGui>
#include "ApplicationWindow.h"
int main(int argv, char **args)
QApplication app(argv, args);
ApplicationWindow window;
window.show();
return app.exec();
那么,当转换发生时,我如何触发一些行为或动作?
干杯。
【问题讨论】:
【参考方案1】:要在状态转换中实际执行某些操作,您必须连接到转换的triggered()
信号,例如
QAbstractTransition* trMainLoad = mainMenuState->addTransition(mainMenu, SIGNAL(loadGameClicked()), loadGameMenuState);
connect(trMainLoad , SIGNAL(triggered()), SLOT(...));
【讨论】:
干杯。我已经这样做了,但现在我得到了:Unhandled exception at 0x779815de (ntdll.dll) in Hello Notepad.exe: 0xC0000005: Access violation reading location 0xabababaf.
异常发生在mainMenuButtonClicked()
内部——我不应该调用setCentralWidget
两次吗?我已经用我的新代码更新了我原来的帖子。
根据setCentralWidget()
doc:QMainWindow takes ownership of the widget pointer and deletes it at the appropriate time.
,所以当你执行setCentralWidget(loadGameMenu);
时你的mainMenu可能被破坏了
当没有对指针的引用时,适当的时间不是吗?我还能如何在QMainWindow
中显示不同的Widget
s(屏幕)?由于缺乏经验,我只是这样做 - 我愿意接受其他选择。
@Mitch 另一种选择是让它们成为 QStackedWidget 的页面;将它与 QSignalMapper (将按钮映射到小部件)结合起来,您可以非常轻松地制作一个非常漂亮的菜单系统。
感谢@tmpearce,效果很好。有兴趣的人的最终代码:pastebin.com/YhbHHJNe以上是关于使用 QStateMachine 在菜单屏幕之间切换的主要内容,如果未能解决你的问题,请参考以下文章
QStateMachine 如何在不同的 QState 中显示和隐藏 QGraphicsView 和 QObject