我需要一种在主线程中运行我自己的更新功能的方法。每次主循环运行时,我都找不到能给我打勾的信号。
我这样做错了吗?如果我们想在循环中运行某些东西,强制用户代码在线程中运行是不是Qt?
答案 0 :(得分:13)
QTimer::singleShot(0, []{/* your code here */});
这就是它,真的。使用0ms计时器意味着您的代码将在下一个事件循环迭代中运行。如果您想确保在某个对象不再存在时代码将无法运行,请提供上下文对象:
QTimer::singleShot(0, contextObj, []{/* your code here */});
我在这里使用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();
}
}
);