问题描述
我正在尝试创建一个事件,该事件在我的 Singleton 工作器中每 n 秒触发一次.信号/槽连接(信号是 QTimer 超时,槽是 lambda 函数,它调用另一个 Singleton 类)不工作.连接调用成功,计时器处于活动状态,我在控制台上没有收到 QTimer 投诉.如果我尝试打印 QTimer 的剩余时间,它会显示 -1.对于我的一生,我无法弄清楚为什么永远不会打印超时"(表示正在触发事件).任何帮助将不胜感激.为简单起见,我们可以假设 OtherSingleton 具有相同的结构.我还应该注意到这个 Singleton 类对象在 QThread 中运行.
Singleton.h:
#include #include #include #include 单例类:公共 QObject{Q_OBJECT上市:静态单例&获取实例();Singleton(Singleton const&) = delete;void operator=(Singleton const&) = delete;静态无效 stop_client();静态无效 start_client();私人的:单例();静态 QTimer bytes_timer_;};
Singleton.cpp:
#include "Singleton.h"#include #include #include 单例::单例(){bytes_timer_.setParent(this);bytes_timer_.moveToThread(QThread::currentThread());bytes_timer_.setInterval(1000);qDebug() <<超时成功:"<<连接(&bytes_timer_, &QTimer::timeout, this, [&]() {qDebug() <<超时";//...}, Qt::DirectConnection);}单身汉&单例::get_instance() {静态单例实例;返回实例;}void Singleton::start_client() {bytes_timer_.start();}void Singleton::stop_client() {bytes_timer_.stop();}QTimer Singleton::bytes_timer_;
主窗口.h:
#ifndef MAINWINDOW_H#define MAINWINDOW_H#include #include #include "singleton.h"命名空间 Ui {类主窗口;}类 MainWindow : 公共 QMainWindow{Q_OBJECT上市:显式 MainWindow(QWidget *parent = nullptr);~主窗口();私人插槽:void on_pushButton_clicked();私人的:QThread线程;单身*s;用户界面::主窗口 *用户界面;};#endif//MAINWINDOW_H
MainWindow.cpp:
#include "mainwindow.h"#include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent) :QMainWindow(父),用户界面(新用户界面::主窗口){ui->setupUi(this);s = &Singleton::get_instance();s->moveToThread(&thread);}主窗口::~主窗口(){删除用户界面;}void MainWindow::on_pushButton_clicked(){线程开始();s->start_client();}
main.cpp:
#include "mainwindow.h"#include #include #include "singleton.h"int main(int argc, char *argv[]){QApplication a(argc, argv);主窗口 w;w.show();返回 a.exec();}
我有种感觉 OP 即将过度设计"其实很简单.
我制作了一个
将 QTimer
移动到不同的线程会增加很多开销.对 QTimer
的任何访问都有
- 在开始线程之前发生或
- 被互斥锁保护或
- 通过信号来完成(使用
Qt::QueueConnection
).
我考虑了一会儿来分别调整我的样本,但很快意识到必要的努力并停止了.恕我直言,除非有充分的理由,否则我不会推荐这样做.
请注意:负载过重导致超时信号发射明显延迟的应用程序可能无法及时处理由另一个线程发出的超时事件.
I am trying to create an event that gets fired off every n seconds in my Singleton worker. A signal/slot connection (with the signal being the QTimer timing out and the slot being a lambda function which makes a call to another Singleton class) is not working. The connect call is succeeding, the timer is active, and I get no QTimer complaints on the console. If I try to print QTimer's remaining time it reads -1. For the life of me, I cannot figure out why "timeout" is never being printed (indicating that the event is being triggered). Any help would be greatly appreciated. For simplicity's sake we can assume that OtherSingleton has the same structure. I should also note that this Singleton class object is running inside of a QThread.
Singleton.h:
#include <QObject>
#include <string>
#include <QTimer>
#include <QThread>
class Singleton : public QObject
{
Q_OBJECT
public:
static Singleton& get_instance();
Singleton(Singleton const&) = delete;
void operator=(Singleton const&) = delete;
static void stop_client();
static void start_client();
private:
Singleton();
static QTimer bytes_timer_;
};
Singleton.cpp:
#include "Singleton.h"
#include <QDebug>
#include <QTime>
#include <QFile>
Singleton::Singleton()
{
bytes_timer_.setParent(this);
bytes_timer_.moveToThread(QThread::currentThread());
bytes_timer_.setInterval(1000);
qDebug() << "Timeout success:" << connect(&bytes_timer_, &QTimer::timeout, this, [&]() {
qDebug() << "timeout";
// . . .
}, Qt::DirectConnection);
}
Singleton& Singleton::get_instance() {
static Singleton instance;
return instance;
}
void Singleton::start_client() {
bytes_timer_.start();
}
void Singleton::stop_client() {
bytes_timer_.stop();
}
QTimer Singleton::bytes_timer_;
MainWindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QThread>
#include "singleton.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_pushButton_clicked();
private:
QThread thread;
Singleton *s;
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
MainWindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
s = &Singleton::get_instance();
s->moveToThread(&thread);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
thread.start();
s->start_client();
}
main.cpp:
#include "mainwindow.h"
#include <QApplication>
#include <QThread>
#include "singleton.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
I somehow have the feeling that OP is about to “over-engineer” what could be actually quite simple.
I made an MCVE to demonstrate this.
testQTimerStartStop.cc
:
#include <QtWidgets>
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
// prepare application
QApplication app(argc, argv);
QTimer qTimer;
qTimer.setInterval(1000);
// setup GUI
QWidget qWinMain;
qWinMain.setWindowTitle(QString::fromUtf8("QTimer Test"));
QFormLayout qForm;
QSpinBox qEditTimer;
qEditTimer.setRange(0, 30);
qForm.addRow(
QString::fromUtf8("Count down:"),
&qEditTimer);
QPushButton qBtnStart(QString::fromUtf8("Start"));
qForm.addRow(&qBtnStart);
QPushButton qBtnStop(QString::fromUtf8("Stop"));
qForm.addRow(&qBtnStop);
qWinMain.setLayout(&qForm);
qWinMain.show();
// set initial states
qEditTimer.setValue(10);
auto updateBtns = [&]() {
const int count = qEditTimer.value();
qBtnStart.setEnabled(!qTimer.isActive() && count > 0);
qBtnStop.setEnabled(qTimer.isActive());
};
updateBtns();
// install signal handlers
QObject::connect(&qTimer, &QTimer::timeout,
[&]() {
qEditTimer.setValue(qEditTimer.value() - 1); // count down
});
QObject::connect(&qEditTimer, (void (QSpinBox::*)(int))&QSpinBox::valueChanged,
[&](int count) {
if (count <= 0) qTimer.stop();
updateBtns();
});
QObject::connect(&qBtnStart, &QPushButton::clicked,
[&](bool) { qTimer.start(); updateBtns(); });
QObject::connect(&qBtnStop, &QPushButton::clicked,
[&](bool) { qTimer.stop(); updateBtns(); });
// runtime loop
return app.exec();
}
testQTimerStartStop.pro
:
SOURCES = testQTimerStartStop.cc
QT += widgets
Build and run:
$ qmake-qt5 testQTimerStartStop.pro
$ make && ./testQTimerStartStop
g++ -c -fno-keep-inline-dllexport -D_GNU_SOURCE -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I. -isystem /usr/include/qt5 -isystem /usr/include/qt5/QtWidgets -isystem /usr/include/qt5/QtGui -isystem /usr/include/qt5/QtCore -I. -I/usr/lib/qt5/mkspecs/cygwin-g++ -o testQTimerStartStop.o testQTimerStartStop.cc
g++ -o testQTimerStartStop.exe testQTimerStartStop.o -lQt5Widgets -lQt5Gui -lQt5Core -lGL -lpthread
Qt Version: 5.9.4
Moving the QTimer
to a different thread would add a lot of overhead. Any access to the QTimer
had
- to happen before starting the thread or
- to be mutex guarded or
- to be done through signals (with
Qt::QueueConnection
).
I considered it for a moment to adapt my sample respectivley but soon realized the necessary effort and stopped. IMHO, I wouldn't recommend this unless there is a good reason to do so.
Please, consider that: An application which is under heavy load which causes significant delays of timeout signal emitting is probably not able as well to handle timeout events which are emitted by another thread in time.
这篇关于QTimer::timeout 没有触发的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!