QT无法正确处理循环

时间:2018-01-09 10:13:35

标签: c++ qt event-loop

我想重复在SLOT中执行的操作,直到qpushbutton关闭。所以我已完成以下连接:

connect(ui->button,SIGNAL(pressed()),this,SLOT(button_hold()));
connect(ui->button,SIGNAL(released()),this,SLOT(button_released()));

我已按以下方式实施了SLOTS

void My_class::button_hold(){
     //CLASS ATTRIBUTE key_is_released , i
     QThread::msleep(200);
     int wait_lock = 500; 
     i++; //GOAL OF THE SLOT
     QCoreApplication::processEvents(QEventLoop::AllEvents);
     while(!key_is_released){
         QThread::msleep(wait_lock); 
         i++;
         cout<<i<<endl;                
         if(wait_lock > 50) wait_lock -= 50;
         QCoreApplication::processEvents(QEventLoop::AllEvents);
     }
     key_is_released = false;
}

void My_class::button_released(){
      key_is_released = true;
 }

目标是重复button_hod()插槽中的操作(在示例中,它是为了增加i),甚至更快地减少wait_lock并保持按钮按下。问题是,如果我单击按钮两次或更多次快速方式循环永远不会结束,就像processEvents()不起作用。如果只是点击按钮并且没有按下太长时间,则使用firts msleep以便不进入循环(我只增加一次) 。如果我没有快速点击,但我按下按钮,方法效果很好。

我做错了什么?

2 个答案:

答案 0 :(得分:1)

重新进入事件循环是一个坏主意,并导致意大利面条代码。

Qt提供了一个具有UML语义的精彩状态机系统。通常最好对您设计为状态机的系统进行建模。这里有两种状态:空闲状态和活动状态:value在激活时定期递增。

状态机将Ui细节(按钮)与核心功能分离:周期性递增值。

理想情况下,您还要将状态机和值分解为控制器类,并且仅将控制器和Ui从main()或类似函数连接起来。

// https://github.com/KubaO/stackoverflown/tree/master/questions/48165864
#include <QtWidgets>
#include <type_traits>

class Ui : public QWidget {
   Q_OBJECT
   int m_value = -1;
   QStateMachine m_machine{this};
   QState m_idle{&m_machine}, m_active{&m_machine};
   QVBoxLayout m_layout{this};
   QPushButton m_button{"Hold Me"};
   QLabel m_indicator;
   QTimer m_timer;

   void setValue(int val) {
      if (m_value == val) return;
      m_value = val;
      m_indicator.setNum(m_value);
   }
   void step() {
      if (m_value < std::numeric_limits<decltype(m_value)>::max())
         setValue(m_value + 1);
   }
public:
   Ui(QWidget * parent = {}) : QWidget(parent) {
      m_layout.addWidget(&m_button);
      m_layout.addWidget(&m_indicator);
      m_machine.setInitialState(&m_idle);
      m_idle.addTransition(&m_button, &QPushButton::pressed, &m_active);
      m_active.addTransition(&m_button, &QPushButton::released, &m_idle);
      m_machine.start();
      m_timer.setInterval(200);
      connect(&m_timer, &QTimer::timeout, this, &Ui::step);
      connect(&m_active, &QState::entered, [this]{
         step();
         m_timer.start();
      });
      connect(&m_active, &QState::exited, &m_timer, &QTimer::stop);
      setValue(0);
   }
};

int main(int argc, char ** argv) {
   QApplication app{argc, argv};
   Ui ui;
   ui.show();
   return app.exec();
}

#include "main.moc"

答案 1 :(得分:0)

问题在于快速点击10次,在进入循环之前,释放槽已被调用10次,因此key_is_released将永远不会再次更新为true。而且button_hold槽尚未被调用10次。然后添加一个计数器,在button_hold插槽中增加它并在释放槽中减少它,并在while循环中添加第二个条件计数器&gt; 0!key_is_released修复所有。(只有当并非所有释放槽都有时才进入循环已经运行了)