QStateMachine - QMouseEvent

2024-03-10

在另一个问题中,你告诉我使用 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

问题是我使用for1到20(一场比赛我必须跑20次)。 我尝试使用随机 G1 和 COM 播放来启动该程序,但应用程序冻结,直到最后一次执行for我在现场只打印卡片的最后配置。 这就是原因,因为之前我说过我希望该程序停止......

没有 QStateMachine 可以吗? 简单地告诉他:“暂停”,打印这个情况,等待鼠标然后继续?


下面是一个完整的示例,长 71 行,呈现在文学编程风格 http://www.wikiwand.com/en/Literate_programming。它也可以在github https://github.com/KubaO/stackoverflown/tree/master/questions/sm-cards-37656060。该示例由 qmake 组成.pro文件,未显示,以及main.cpp,如下所示。该示例具有以下结构:

  1. Header
  2. 卡牌项目
  3. 状态机行为
  4. Main
  5. Footer

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

请注意,显式动态内存分配的使用最少,并且没有任何手动内存管理。

卡牌项目

The CardItemclass 是一个简单的卡片图形项目。该项目是可选择的。它也可以是可移动的。交互由图形视图框架自动处理:您不必手动处理解释鼠标按下/拖动/释放 - 至少现在还不需要。

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

然后,我们利用这种通用信号源来描述当给定场景有选择时转换到目标状态的行为 iffselected为 true,或者没有选择 iffselected是假的:

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>

它以以下页脚结尾,包含 moc 生成的信号实现和对象元数据SignalSource class.

#include "main.moc"
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

QStateMachine - QMouseEvent 的相关文章

  • 如何检查QProcess是否正确执行?

    QProcess process sdcompare QString command sdcompare QStringList args sdcompare command sdcompare diff args sdcompare lt
  • 如何将 #ifdef DEBUG 添加到 Xcode?

    我的项目中有一些代码永远不应该在发布版本中使用 但在测试时很有用 我想做这样的事情 ifdef DEBUG Run my debugging only code endif 在 Xcode 4 中哪里添加 DEBUG 设置 我尝试将其放入
  • 如何修复此错误“GDI+ 中发生一般错误”?

    从默认名称打开图像并以默认名称保存 覆盖它 我需要从 Image Default jpg 制作图形 将其放在 picturebox1 image 上并在 picurebox1 上绘制一些图形 它有效 这不是我的问题 但我无法保存 pictu
  • 将内置类型转换为向量

    我的 TcpClient 类接受vector
  • 在新的浏览器进程中打开 URL

    我需要在新的浏览器进程中打开 URL 当浏览器进程退出时我需要收到通知 我当前使用的代码如下 Process browser new Process browser EnableRaisingEvents true browser Star
  • 在 Unity 进程和另一个 C# 进程之间进行本地 IPC 的最快方法 [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我希望每秒大约 30 次从 C 应用程序向我的 Unity 应用程序传送大量数据 由于 Unity 不支持映射内存和管道 我考虑了 t
  • C++中的类查找结构体数组

    我正在尝试创建一个结构数组 它将输入字符串链接到类 如下所示 struct string command CommandPath cPath cPathLookup set an alarm AlarmCommandPath send an
  • 用于检查项目文件中的项目变量和引用路径的 api

    我正在研究一个 net application VS2010 与 x 没有 解和变量号这些解决方案中的项目数量 我需要检查项目属性 特定于一定数量的项目 是否同质 并且检查 验证构建期间的参考路径 有没有一个API是这样的吗 如果没有 我该
  • C# Dns.GetHostEntry 不返回连接到 WiFi 的移动设备的名称

    我有一个 C 中的 Windows 窗体应用程序 我试图获取列表中所有客户端的主机名 下面给出的是 ra00l 来自此链接的代码示例 GetHostEntry 非常慢 https stackoverflow com questions 99
  • 获取 WPF 控件的所有附加事件处理程序

    我正在开发一个应用程序 在其中动态分配按钮的事件 现在的问题是 我希望获取按钮单击事件的所有事件 因为我希望删除以前的处理程序 我尝试将事件处理程序设置为 null 如下所示 Button Click null 但是我收到了一个无法分配 n
  • Rx 中是否有与 Task.ContinueWith 运算符等效的操作?

    Rx 中是否有与 Task ContinueWith 运算符等效的操作 我正在将 Rx 与 Silverlight 一起使用 我正在使用 FromAsyncPattern 方法进行两个 Web 服务调用 并且我想这样做同步地 var o1
  • 未经许可更改内存值

    我有一个二维数组 当我第一次打印数组的数据时 日期打印正确 但其他时候 array last i 的数据从 i 0 到 last 1 显然是一个逻辑错误 但我不明白原因 因为我复制并粘贴了 for 语句 那么 C 更改数据吗 I use g
  • PlaySound 可在 Visual Studio 中运行,但不能在独立 exe 中运行

    我正在尝试使用 Visual Studio 在 C 中播放 wav 文件 我将文件 my wav 放入项目目录中并使用代码 PlaySound TEXT my wav NULL SND FILENAME SND SYNC 我按下播放按钮 或
  • 如何将自定义 JSON 文件添加到 IConfiguration 中?

    我正在使用 asp net Autofac 我正在尝试加载自定义 JSON 配置文件 并基于该文件创建 实例化 IConfiguration 实例 或者至少将我的文件包含到默认情况下构建的 IConfiguration asp net 中
  • 等待线程完成

    private void button1 Click object sender EventArgs e for int i 0 i lt 15 i Thread nova new Thread Method nova Start list
  • .NET中的LinkedList是循环链表吗?

    我需要一个循环链表 所以我想知道是否LinkedList是循环链表吗 每当您想要移动列表中的 下一个 块时 以循环方式使用它的快速解决方案 current current Next current List First 电流在哪里Linke
  • Server.MapPath - 给定的物理路径,预期的虚拟路径

    我正在使用这行代码 var files Directory GetFiles Server MapPath E ftproot sales 在文件夹中查找文件 但是我收到错误消息说 给定物理路径但虚拟路径 预期的 我对在 C 中使用 Sys
  • 英特尔 Pin 与 C++14

    问题 我有一些关于在 C 14 或其他 C 版本中使用英特尔 Pin 的问题 使用较新版本从较旧的 C 编译代码很少会出现任何问题 但由于 Intel Pin 是操作指令级别的 如果我使用 C 11 或 C 14 编译它 是否会出现任何不良
  • memset 未填充数组

    u32 iterations 5 u32 ecx u32 malloc sizeof u32 iterations memset ecx 0xBAADF00D sizeof u32 iterations printf 8X n ecx 0
  • 使用 GROUP 和 SUM 的 LINQ 查询

    请帮助我了解如何使用带有 GROUP 和 SUM 的 LINQ 进行查询 Query the database IEnumerable

随机推荐