QStateMachine - QMouseEvent [英] QStateMachine - QMouseEvent

查看:232
本文介绍了QStateMachine - QMouseEvent的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在另一个问题你告诉我使用QStateMachine。



我是第一次使用Qt,这是我第一次使用对象,所以我做了很多逻辑错误,所以使用QStateMachine这是一个大问题...



这是唯一的办法做?我尝试解释我的程序:



我想创建一个卡的游戏,在以前的版本中,我使用了一个旧的图形库与这一系列命令:

   - >打印卡在现场
- >等待鼠标输入(使用do-while)
- > if(isMouseClick(WM_LBUTTONDOWN))
- > if(鼠标位置在第一张卡上)
- >选择该卡。所以我想做同样的事情QGraphics。

这样我告诉程序:

   - >打印卡
- >等待鼠标事件
- >打印我已选择的事件的卡。



现在我要更改程序图形,我已经介绍过QGraphics。
我创建了一个场景并打印所有对象card,现在我想告诉程序:

   - >打印对象并等待鼠标输入
- >如果一个卡是用左clik选择
- >在现场打印该卡,等待1/2秒,然后继续执行程序

问题是我使用 1到20(我必须在匹配中运行20次)。
我试图用随机的G1和COM播放程序,但应用程序冻结,直到最后一次执行和我在现场打印最后配置的卡。
这是原因,因为以前我说我想让程序停止...



有没有QStateMachine可以做?

解决方案

下面的例子中,是一个完整的示例,71行长,显示在





我们的场景:

  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机器; 
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; s_ready); 

如果取消选择项目,我们回到 s_idle

  on_selected(& s_selected,& scene,false,& s_idle); 
on_selected(& s_ready,& scene,false,& s_idle);

由于我们没有太多好处,我们可以取消选择所有项目c $ c> 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 :: grey: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){}
};

然后我们利用这样的通用信号源描述当给定场景转换到目的地状态时的行为有选择iff 选择为true或没有选择iff 选择为false:

  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 类。

  #includemain.moc


In another question you tell me to use QStateMachine.

I'm new to Qt and it's the first time i use the objects so I make a lot of logical mistake, so using QStateMachine it's a big problem...

It's the only way to do thath ? I try to explain my program:

I want to create a card's game and in the previous version I've used an old graphics library with this sequence of commands:

-> 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. 

In this way I tell the program:

-> print cards 
-> wait for a mouse event 
-> print the card that I've selected with that event. 

Now I want to change the program graphics and I've introduced QGraphics. I've created a scene and print all the objects "card" on it so now i want to tell the program:

-> 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

The problem is that I use a for 1 to 20 (I must run that 20 times in a match). I've tried to lauch the program with a random G1 and COM play but the application freeze until the last execution of the for and I print on the scene only the last configuration of cards. That is the reason because previously I said I want the program to stop...

It is possible to do without QStateMachine ? Simply telling him: "pause", print this situation, wait for mouse and go ahead ?

解决方案

The below is a complete example, 71 lines long, presented in the literate programming style. It is also available on github. The example consists of a qmake .pro file, not shown, and main.cpp, shown in the entirety below. The example has the following structure:

  1. Header
  2. Card Item
  3. State Machine Behaviors
  4. Main
  5. Footer

Main

First, let's set up our scene:

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"));

The state machine has three states:

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

We'll use helper functions to declaratively add behaviors to the machine. This isn't the only possible pattern, but it works and is fairly easy to apply. First, when any items are selected, the state changes from s_idle to s_selected:

   on_selected(&s_idle, &scene, true, &s_selected);

Then, after a timeout, the state changes to s_ready:

   on_delay(&s_selected, 500, &s_ready);

If the items are deselected, we go back to s_idle:

   on_selected(&s_selected, &scene, false, &s_idle);
   on_selected(&s_ready, &scene, false, &s_idle);

Since we don't have much better to do, we can simply deselect all items once the s_ready state has been entered. This makes it clear that the state was entered. Of course, it'll be immediately left since the selection is cleared, and we indicated above that s_idle is the state to be when no items are selected.

   QObject::connect(&s_ready, &QState::entered, &scene, &QGraphicsScene::clearSelection);

We can now start the machine and run our application:

   machine.start();

   view.show();
   return app.exec();
}

Note the minimal use of explicit dynamic memory allocation, and no manual memory management whatsoever.

Card Item

The CardItem class is a simple card graphics item. The item is selectable. It could also be movable. The interaction is handled automatically by the graphics view framework: you don't have to deal with interpreting mouse presses/drags/releases manually - at least not yet.

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

State Machine Behaviors

It is helpful to factor out the state machine behaviors into functions that can be used to declare the behaviors on a given state.

First, the delay - once the src state is entered, and a given number of millisconds elapses, the machine transitions to the destination state:

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

To intercept the selection signals, we'll need a helper class that emits a generic signal:

class SignalSource : public QObject {
   Q_OBJECT
public:
   Q_SIGNAL void sig();
   SignalSource(QObject * parent = Q_NULLPTR) : QObject(parent) {}
};

We then leverage such universal signal source to describe the behavior of transitioning to the destination state when the given scene has a selection iff selected is true, or has no selection iff selected is false:

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

Header and Footer

The example begins with the following header:

// https://github.com/KubaO/stackoverflown/tree/master/questions/sm-cards-37656060
#include <QtWidgets>

It ends with the following footer, consisting of moc-generated implementations of the signals and object metadata for the SignalSource class.

#include "main.moc"

这篇关于QStateMachine - QMouseEvent的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆