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 的相关文章

  • 如何在线程创建和退出时调用函数?

    include
  • WP8.1 C# 绑定联系人图像

    信息很简单 我正在尝试创建一个可以显示用户联系人的应用程序 我也是一名自学成才的程序员 所以我在某些方面有编程经验 但总体来说我对数据绑定相对较新 首先 我有一个 ListView 控件 其中包含图像绑定
  • 代码块 power 函数在 c 中不起作用

    我正在使用代码块来学习c 我的代码是 include
  • 操作/Lambda 表达式内存管理问题

    我将一个操作存储在局部变量中 然后在该局部变量超出范围后使用 使用前是否有被清理的危险 这是一个例子 public List GetMaps Action
  • 宏可以按参数数量重载吗?

    如何this https stackoverflow com q 9183993 153285工作 如何实现 C99 C 11 可变参数宏以仅根据为其提供多少个参数来扩展到不同的事物 编辑 请参阅末尾以获得现成的解决方案 要获得重载的宏 首
  • 在 C# 中调用事件处理程序

    我一直在尝试学习如何在 C 中使用事件处理程序 但我无法弄清楚 handler this e 在以下代码中的作用 public event EventHandler ThresholdReached protected virtual vo
  • 使用 size_t 值反向遍历向量

    我想以相反的方向遍历向量的值 如您所知 向量的大小为 size t 当我使用以下代码时 for size t r m size 1 r gt 0 r x r f r for size t c r 1 c lt m size c x r m
  • 在 C++ 中使用表达式模板进行符号微分

    如何在 C 中使用表达式模板实现符号微分 一般来说 您需要一种表示符号的方法 即编码的表达式模板 例如3 x x 42 以及一个可以计算导数的元函数 希望您对 C 中的元编程足够熟悉 知道这意味着什么和需要什么 但可以给您一个想法 This
  • 是否有一种算法可以在线性时间内计算数组反转?

    我知道有多少倒转 en wikipedia org wiki Inversion 28discrete mathematics 29 in an n 元素数组可以在 O n log n 操作使用增强型归并排序 http www geeksf
  • C++:初始化静态字符串成员

    我在 C 中初始化静态字符串成员时遇到一些问题 我有几个类 每个类都包含几个表示 id 的静态字符串成员 当我通过调用静态函数初始化变量时 一切都很好 但是 当我想为一个变量分配另一个变量的值时 它仍然保留空字符串 这段代码有什么问题 st
  • Qt QML 数据模型似乎不适用于 C++

    我一直在使用中的示例http doc qt digia com 4 7 qdeclarativemodels html http doc qt digia com 4 7 qdeclarativemodels html这是 QML 声明性数
  • 本地主机上的 .net HTTP_X_FORWARDED_FOR NULL

    抱歉 如果其他地方已经回答了这个问题 我找不到它 如果没有 我会尝试查找访问过该站点的机器的原始 IP 根据我的基本理解 变量HTTP X FORWARDED FOR无论代理和其他过滤器如何 都会显示用户的 IP 如果这是真的 我正在尝试对
  • 函数参数评估顺序[重复]

    这个问题在这里已经有答案了 在 C 和 C 中 函数参数的求值是否有固定的顺序 我的意思是 标准怎么说 是吗left to right or right to left 我从书中得到的信息令人困惑 是否有必要function call应该使
  • C++ 错误:从“char”到“const char*”的转换无效

    我对 C 完全陌生 我创建了这个函数 bool guessWord string compWord cout lt lt Guess a letter string userLetter cin gt gt userLetter for u
  • 带双重检查锁的单例设计模式

    假设您有以下代码 1 为什么我们使用双重检查锁 为什么单锁不够好 请提供详细的例子 2 这种实施方式的主要缺点是什么 我该如何证明呢 Thanks public sealed class SomeSingleton5 private sta
  • ASP.NET MVC 中 ModelState.AddModelError 中的关键参数有什么意义?

    我在我的控制器中添加了验证检查来修改ModelState如果验证失败 例如 private bool ValidateMoney string raw string name decimal min decimal max try var
  • printf() 使用字符串表“解码器环”调试库

    我写这封信是想看看你们中是否有人见过或听说过我即将描述的想法的实现 我有兴趣为嵌入式目标开发 printf 风格的调试库 目标非常遥远 并且我和目标之间的通信带宽预算非常紧张 因此我希望能够以非常有效的格式获取调试消息 通常 调试语句如下所
  • 该组件没有由 uri 标识的资源

    我想创建一个通用数据网格以在我的所有视图 用户控件上使用 这是我的结构 Class Library called Core Class called ViewBase public class ViewBase UserControl pu
  • 字符串 c 的二叉树

    我正在尝试实现一个能够在 c 中保存字符串的二叉树 在让代码适用于整数之后 我尝试稍微修改它以处理字符数组 现在我似乎完全破解了代码 但不知道如何破解 任何帮助表示赞赏 include
  • 如何在 C# 中以编程方式创建柔和的颜色?

    根据所需的颜色数量均匀分布地生成它们 如果指定的计数为 8 则看起来像这样 List

随机推荐