在另一个问题中,您告诉我使用QStateMachine。
我对Qt很陌生,这是我第一次使用对象,所以我犯了很多逻辑上的错误,所以使用QStateMachine是个大问题。
这是唯一的办法?我试着解释一下我的计划:
我想要创建一个卡片的游戏,在以前的版本中,我使用了一个旧的图形库,其中包含以下命令:
-> print cards on the scene
-> wait for a mouse input (with a do-while)
-> if(isMouseClick(WM_LBUTTONDOWN))
-> if(mouse position is on the first card)
-> select that card. So i wish to do the same thing with QGraphics. 我用这种方式告诉节目:
-> print cards
-> wait for a mouse event
-> print the card that I've selected with that event. 现在我想改变程序图形,我已经介绍了QGraphics。我已经创建了一个场景,并在上面打印了所有的对象“卡片”,所以现在我想告诉程序:
-> print the object and wait the mouse input
-> if a card is to selected with the left clik
-> print that card in scene, wait 1/2 second and go ahead with the program问题是我使用的是for 1到20 (必须在一次匹配中运行20次)。我尝试用随机的G1和COM播放程序,但是应用程序冻结到for的最后一次执行,而我在现场只打印卡片的最后配置。这是因为我之前说过我想让节目停止..。
没有QStateMachine是可以做到的吗?简单地告诉他:“暂停”,打印这个情况,等待鼠标继续前进?
发布于 2016-06-06 22:44:52
下面是一个完整的示例,71行长,在识字编程风格中显示。它也可以在github上使用。该示例由未显示的qmake .pro文件和main.cpp组成,如下所示。该示例具有以下结构:

Main
首先,让我们建立我们的场景:
int main(int argc, char ** argv) {
QApplication app{argc, argv};
QGraphicsScene scene;
QGraphicsView view{&scene};
scene.addItem(new CardItem(0, 0, "A"));
scene.addItem(new CardItem(20, 0, "B"));状态机有三个状态:
QStateMachine machine;
QState s_idle{&machine}; // idle - no card selected
QState s_selected{&machine}; // card selected, waiting 1/2 second
QState s_ready{&machine}; // ready with card selected
machine.setInitialState(&s_idle);我们将使用帮助函数以声明方式向机器添加行为。这并不是唯一可能的模式,但它是有效的,并相当容易应用。首先,当选择任何项时,状态从s_idle更改为s_selected
on_selected(&s_idle, &scene, true, &s_selected);然后,超时之后,状态更改为s_ready
on_delay(&s_selected, 500, &s_ready);如果取消选择项,则返回到s_idle
on_selected(&s_selected, &scene, false, &s_idle);
on_selected(&s_ready, &scene, false, &s_idle);由于我们没有更好的工作要做,所以一旦输入了s_ready状态,我们就可以简单地取消选择所有项。这就清楚地表明这个州已经进入。当然,在清除所选内容后,它将立即保留,并且我们在上面指出,当没有选择任何项时,s_idle是状态。
QObject::connect(&s_ready, &QState::entered, &scene, &QGraphicsScene::clearSelection);我们现在可以启动机器并运行我们的应用程序:
machine.start();
view.show();
return app.exec();
}注意,显式动态内存分配的使用最少,而且没有任何手动内存管理。
卡片项目
CardItem类是一个简单的卡片图形项。项目是可选择的。它也可以是可移动的。交互是由图形视图框架自动处理的:您不需要处理手动解释鼠标按压/拖拽/发布的问题--至少现在还没有。
class CardItem : public QGraphicsObject {
Q_OBJECT
const QRect cardRect { 0, 0, 80, 120 };
QString m_text;
QRectF boundingRect() const Q_DECL_OVERRIDE { return cardRect; }
void paint(QPainter * p, const QStyleOptionGraphicsItem*, QWidget*) {
p->setRenderHint(QPainter::Antialiasing);
p->setPen(Qt::black);
p->setBrush(isSelected() ? Qt::gray : Qt::white);
p->drawRoundRect(cardRect.adjusted(0, 0, -1, -1), 10, 10);
p->setFont(QFont("Helvetica", 20));
p->drawText(cardRect.adjusted(3,3,-3,-3), m_text);
}
public:
CardItem(qreal x, qreal y, const QString & text) : m_text(text) {
moveBy(x, y);
setFlags(QGraphicsItem::ItemIsSelectable);
}
};状态机行为
将状态机行为分解为可用于声明给定状态下的行为的函数是很有帮助的。
首先,延迟--一旦输入了src状态,给定的毫秒数就过去了,机器就会过渡到目标状态:
void on_delay(QState * src, int ms, QAbstractState * dst) {
auto timer = new QTimer(src);
timer->setSingleShot(true);
timer->setInterval(ms);
QObject::connect(src, &QState::entered, timer, static_cast<void (QTimer::*)()>(&QTimer::start));
QObject::connect(src, &QState::exited, timer, &QTimer::stop);
src->addTransition(timer, SIGNAL(timeout()), dst);
}要拦截选择信号,我们需要一个发出泛型信号的助手类:
class SignalSource : public QObject {
Q_OBJECT
public:
Q_SIGNAL void sig();
SignalSource(QObject * parent = Q_NULLPTR) : QObject(parent) {}
};然后,我们利用这样的通用信号源来描述当给定场景有选择当且仅当selected为真或没有选择当且仅当selected为假时,向目的地状态转换的行为:
void on_selected(QState * src, QGraphicsScene * scene, bool selected, QAbstractState * dst) {
auto signalSource = new SignalSource(src);
QObject::connect(scene, &QGraphicsScene::selectionChanged, signalSource, [=] {
if (scene->selectedItems().isEmpty() == !selected) emit signalSource->sig();
});
src->addTransition(signalSource, SIGNAL(sig()), dst);
}页眉和页脚
该示例以以下标题开头:
// https://github.com/KubaO/stackoverflown/tree/master/questions/sm-cards-37656060
#include <QtWidgets>它以下面的页脚结束,由SignalSource类的信号和对象元数据的moc生成的实现组成。
#include "main.moc"发布于 2016-06-06 14:16:02
在qt中,您不需要积极等待事件(通常也不应该)。只需子类小部件的事件处理方法,它是主接口的一部分。
例如,这是使用QGraphicsItem的子类来更改游戏状态的代码。你也可以对场景本身、小部件等做同样的事情.但通常应该是这样的。
void CardGameGraphicsItem::mousePressEvent(QGraphicsSceneMouseEvent* event)
{
if(event->button() == Qt::RightButton)
{
makeQuickChangesToGameState();
scene()->update(); //ask for a deffered ui update
}
QGraphicsItem::mousePressEvent(event);
}即使您正在以某种方式使用状态机,makeQuickChangesToGameState()也应该触发机器状态更改,并尽快返回。
https://stackoverflow.com/questions/37656060
复制相似问题