QTimer::timeout 没有开火
QTimer::timeout isn't firing
我正在尝试在我的 Singleton worker 中创建一个每 n 秒触发一次的事件。 signal/slot 连接(信号是 QTimer 超时,插槽是 lambda 函数,它调用另一个 Singleton class)不工作。连接调用成功,计时器处于活动状态,我在控制台上没有收到任何 QTimer 投诉。如果我尝试打印 QTimer 的剩余时间,它会显示 -1。对于我的一生,我无法弄清楚为什么 "timeout" 从未被打印出来(表明事件正在被触发)。任何帮助将不胜感激。为了简单起见,我们可以假设 OtherSingleton 具有相同的结构。我还应该注意到,这个 Singleton class 对象是 运行 在 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();
}
如官方网站所述,您需要启动计时器
bytes_timer_.start();
不知何故,我有一种感觉,OP 即将“过度设计”实际上非常简单的东西。
我做了一个MCVE来演示这个。
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
构建并运行:
$ 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
将 QTimer
移动到不同的线程会增加很多开销。对 QTimer
的任何访问都具有
- 在启动线程之前发生或
- 受互斥保护或
- 通过信号完成(
Qt::QueueConnection
)。
我考虑了一下是否要相应地调整我的样本,但很快意识到必要的努力并停止了。恕我直言,除非有充分的理由,否则我不推荐这样做。
请考虑:负载过重导致超时信号发出显着延迟的应用程序可能无法及时处理另一个线程发出的超时事件。
我正在尝试在我的 Singleton worker 中创建一个每 n 秒触发一次的事件。 signal/slot 连接(信号是 QTimer 超时,插槽是 lambda 函数,它调用另一个 Singleton class)不工作。连接调用成功,计时器处于活动状态,我在控制台上没有收到任何 QTimer 投诉。如果我尝试打印 QTimer 的剩余时间,它会显示 -1。对于我的一生,我无法弄清楚为什么 "timeout" 从未被打印出来(表明事件正在被触发)。任何帮助将不胜感激。为了简单起见,我们可以假设 OtherSingleton 具有相同的结构。我还应该注意到,这个 Singleton class 对象是 运行 在 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();
}
如官方网站所述,您需要启动计时器
bytes_timer_.start();
不知何故,我有一种感觉,OP 即将“过度设计”实际上非常简单的东西。
我做了一个MCVE来演示这个。
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
构建并运行:
$ 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
将 QTimer
移动到不同的线程会增加很多开销。对 QTimer
的任何访问都具有
- 在启动线程之前发生或
- 受互斥保护或
- 通过信号完成(
Qt::QueueConnection
)。
我考虑了一下是否要相应地调整我的样本,但很快意识到必要的努力并停止了。恕我直言,除非有充分的理由,否则我不推荐这样做。
请考虑:负载过重导致超时信号发出显着延迟的应用程序可能无法及时处理另一个线程发出的超时事件。