QTimer :: timeout не запускается - PullRequest
       43

QTimer :: timeout не запускается

0 голосов
/ 22 февраля 2019

Я пытаюсь создать событие, которое будет запускаться каждые n секунд в моем работнике Singleton.Соединение сигнал / слот (с сигналом, являющимся тайм-аутом QTimer, и слотом, являющимся лямбда-функцией, которая выполняет вызов в другой класс Singleton) не работает.Вызов подключения успешно завершен, таймер активен, и я не получаю жалоб QTimer на консоли.Если я попытаюсь напечатать оставшееся время QTimer, он будет читать -1.Что касается меня, я не могу понять, почему «тайм-аут» никогда не печатается (что указывает на то, что событие запускается).Любая помощь будет принята с благодарностью.Для простоты можно предположить, что OtherSingleton имеет такую ​​же структуру.Я также должен отметить, что этот объект класса Singleton работает внутри 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();
}

Ответы [ 2 ]

0 голосов
/ 23 февраля 2019

У меня почему-то возникает ощущение, что 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

Snapshot of testQTimerStartStop (animated)

Перемещение QTimer в другой поток добавило бы много накладных расходов.Любой доступ к QTimer должен был

  • произойти до запуска потока или
  • для защиты мьютексом или
  • через сигналы (с Qt::QueueConnection).

Я на мгновение подумал, чтобы адаптировать свой образец соответственно, но вскоре осознал необходимые усилия и остановился.ИМХО, я бы не рекомендовал это, если нет веских причин для этого.

Пожалуйста, учтите, что: Приложение, которое находится под большой нагрузкой и вызывает значительные задержки в выдаче сигнала тайм-аута, вероятно, также не в состояниидля обработки событий тайм-аута, которые отправляются другим потоком во времени.

0 голосов
/ 22 февраля 2019

как указано на официальном сайте, вам необходимо запустить таймер

bytes_timer_.start();

https://doc.qt.io/qt-5/qtimer.html#start-1

...