在主循环中运行代码

时间:2016-05-02 18:08:36

标签: qt

我需要一种在主线程中运行我自己的更新功能的方法。每次主循环运行时,我都找不到能给我打勾的信号。

我这样做错了吗?如果我们想在循环中运行某些东西,强制用户代码在线程中运行是不是Qt?

3 个答案:

答案 0 :(得分:13)

QTimer::singleShot(0, []{/* your code here */});

这就是它,真的。使用0ms计时器意味着您的代码将在下一个事件循环迭代中运行。如果您想确保在某个对象不再存在时代码将无法运行,请提供上下文对象:

QTimer::singleShot(0, contextObj, []{/* your code here */});

这是well documented

我在这里使用lambda作为例子。显然,如果代码很长,你可以提供插槽功能。

如果您希望在每个事件循环迭代中重复执行代码而不是仅执行一次,那么请使用不是单次模式的普通QTimer:

auto timer = new QTimer(parent);
connect(timer, &QTimer::timeout, contextObj, []{/* your code here */});
timer->start();

(注意:如果不设置,则默认为0ms,因此每次事件处理完成后都会发出QTimer::timeout()。)

以下是此行为的documented

毋庸置疑,如果执行的代码需要很长时间才能完成,那么您的GUI将在执行期间冻结。

答案 1 :(得分:3)

或者,如果要在每次运行事件循环时执行代码,可以通过排队连接使用slot方法调用:

class EvtLoopTicker : public QObject
{
    Q_OBJECT
public:

    EvtLoopTicker(QObject *pParent = nullptr)
        : QObject(pParent)
    {}

public slots:

    void launch()
    {
        tickNext();
    }

private slots:

    void tick()
    {
        qDebug() << "tick";

        // Continue ticking
        tickNext();
    }

private:

    void tickNext()
    {
        // Trigger the tick() invokation when the event loop runs next time
        QMetaObject::invokeMethod(this, "tick", Qt::QueuedConnection);
    }

};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    EvtLoopTicker ticker;
    ticker.launch();

    return a.exec();
}

答案 2 :(得分:2)

另一种方法是覆盖:

bool QCoreApplication::event(QEvent *e)

注册用户QEvent并将事件发布到QCoreApplicatio::instance()。显然,QTimer方法是更好的方法,但是即使发行线程不是由Qt(QThread)创建的,这种方法也可以使用。

示例:

class MainThreadEvent: public QEvent
{
  std::function<void()> f_;

public:
  template <typename F>
  explicit MainThreadEvent(F&& f) :
    QEvent(event_type()),
    f_(std::forward<F>(f))
  {
  }

  void invoke()
  {
    f_();
  }

  static auto event_type()
  {
    static int et{-1};

    return QEvent::Type(-1 == et ? et = registerEventType() : et);
  }

  template <typename F>
  static void post(F&& f)
  {
    auto const app(QCoreApplication::instance());

    app->postEvent(app, new MainThreadEvent(std::forward<F>(f)));
  }
};

class UserApplication: public QApplication
{
  using QApplication::QApplication;

  bool event(QEvent* const e) final
  {
    if (MainThreadEvent::event_type() == e->type())
    {
      return static_cast<MainThreadEvent*>(e)->invoke(), true;
    }
    else
    {
      return QApplication::event(e);
    }
  }
};

编辑:来自任意线程的update()的示例:

MainThreadEvent::post(
  [p = QPointer(this)]()
  {
    if (p)
    {
      p->update();
    }
  }
);