Как заставить работать QTimer

134
13 июня 2019, 22:20

Есть следующая структура проекта:
device.h

#ifndef DEVICE_H
#define DEVICE_H
#include <QWidget>
class device : public QWidget
{
    Q_OBJECT
signals:
    void takeMidVal(int midVal);
public:
    device(QWidget *parent = nullptr);
public slots:
    void seek(int bin);
};
#endif // DEVICE_H

device.cpp

#include "device.h"
device::device(QWidget *parent) :
    QWidget(parent)
{
}
void device::seek(int bin)
{
    int midVal = 800;
    emit(takeMidVal(midVal));
}

dialog.h

#ifndef DIALOG_H
#define DIALOG_H
#include <QApplication>
#include <QDialog>
#include <QPushButton>
#include <QVBoxLayout>
#include <math.h>
#include <windows.h>
#define ACCEPT_DIFF         100
#define SIZE_OF_SAMPLE      10
#define SIZE_OF_NOISE       10
#define MK_SILENCE             -2
#define MK_INCORRECT_RESPONSE  -1
#define MK_WAITING              0
#define MK_CORRECT_RESPONSE     1
class Dialog : public QDialog
{
    Q_OBJECT
signals:
    void sendCommand();
    void setBinToSeek(int bin);
public:
    int configRes;
    int result;
    int midCount;
    int midValue;
    bool waitFlag;
    QPushButton* btn;
    explicit Dialog(QWidget *parent = nullptr);
    ~Dialog();
public slots:
    void computeMid(int curVal);
private slots:
    void handleClick();

};
#endif // DIALOG_H

dialog.cpp

#include "dialog.h"
Dialog::Dialog(QWidget *parent) :
    QDialog(parent)
{
    QVBoxLayout *mainLayout = new QVBoxLayout;
    btn = new QPushButton();
    mainLayout->addWidget(btn);
    this->setLayout(mainLayout);
    connect(btn,SIGNAL(clicked()),this,SLOT(handleClick()));
}
void Dialog::handleClick()
{
    result = -1;
    int amplitude = 1000;
    int bin = 10;
    unsigned char min = 1;
    unsigned char max =static_cast<unsigned char>(255);
    unsigned char command = 0;
    bool success = false;
    while(max-min > 1)
    {
        command = (min + (max-min)/2);
        configRes = MK_WAITING;
        emit(sendCommand());
        while(configRes == MK_WAITING)
        {
            QApplication::instance()->processEvents();
            Sleep(100);
        }
        emit(setBinToSeek(bin));
        waitFlag = true;
        midCount = 0;
        midValue = 0;
        int sleepCount = 0;
        while(waitFlag)
        {
            if(sleepCount >= 50)
            {
                return;
            }
            QApplication::instance()->processEvents();
            Sleep(300); //wait untill get mid value of pick in other thread
            ++sleepCount;
        }
        int diff = amplitude - midValue;
        if(diff < 0)
        {
            if(-diff < ACCEPT_DIFF)
            {
                success = true;
                break;
            }
            else
            {
                min = static_cast<unsigned char>(command);
            }
        }
        else
        {
            if(diff < ACCEPT_DIFF)
            {
                success = true;
                break;
            }
            else
            {
                max = static_cast<unsigned char>(command);
            }
        }
    }
    if(success)
    {
        result = static_cast<int>(command);
        return;
    }
}
void Dialog::computeMid(int curVal)
{
    midValue += curVal;
    ++midCount;
    if(midCount >= SIZE_OF_SAMPLE)
    {
        midValue /= midCount;
        waitFlag = false;
    }
}
Dialog::~Dialog()
{
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTimer>
#include "dialog.h"
#include "device.h"
class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    QPushButton* btn;
    QTimer timer;
    Dialog* d;
    device* dev;
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
private slots:
    void createDialog();
    void handleTimeOut();
    void sendCommand();
};
#endif // MAINWINDOW_H

mainwindow.cpp:

#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
{
    dev = new device(this);
    btn = new QPushButton();
    this->layout()->addWidget(btn);
    connect(btn,SIGNAL(clicked()),this,SLOT(createDialog()));
    connect(&timer,SIGNAL(timeout()),this,SLOT(handleTimeOut()));
}
void MainWindow::sendCommand()
{
    timer.start(5000);
}
void MainWindow::createDialog()
{
    d = new Dialog();
    connect(d,SIGNAL(sendCommand()),this,SLOT(sendCommand()));
    connect(dev,SIGNAL(takeMidVal(int)),d,SLOT(computeMid(int)));
    connect(d,SIGNAL(setBinToSeek(int)),dev,SLOT(seek(int)));
    d->exec();
}
void MainWindow::handleTimeOut()
{
    d->configRes = MK_CORRECT_RESPONSE;
}
MainWindow::~MainWindow()
{
}

main.cpp

#include <QApplication>
#include <QtCore>
#include <QtGui>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

сам пример проекта
Когда я посылаю сигнал, вызывается слот sendCommand, с этим проблем нет. Но вот после возвращения из слота, по истечению таймера вызов обработчика не происходит. Как запрыгнуть в обработчик после завершения таймера?

Если перейти от абстрактного примера к реальному, то происходит следующее: из главного окна вызывается модальное. В ходе выполнения кода из модального окна, посылается сигнал в главное на отправку команды устройству по COM-порту. Причем, необходимо получить от устройства ответ и обработать его отсутствие или же его некорректность. Для этого используется таймер.
Насколько я понимаю, после отправки сигнала, выполнение кода модального окна ни на мгновение не останавливается, поэтому дальше я его сажаю в бесконечный цикл, пока не упадет флаг, говорящий что вся обработка завершена.
Но проблема в том, что таймер никак не тригерит вызов обработчика, после выхода из слота ничего не происходит, а выполнение кода модального окна так и болтается в бесконечном цикле.

Добавлено было следующее. По вызову handleClick происходит формирование команды, отправка ее на устройство1, которое влияет на вывод устройства2. После чего, происходит отправка сигнала, устройству2, чтобы оно начало возвращать некое значение. Когда собирается достаточное количество этих значений, вычисляется их среднее арифметическое, и оценивается разница между полученным и ожидаемым значением. Если разница больше минимальной, происходят корректировки в формировании команды и все повторяется заново.

Answer 1

Можно, конечно следать так

while(flag) {
   QApplication::instance()->processEvents();
}

Но, в целом, цикл этот надо удалить, он вообще не нужен. Я так понял у вас там где-то что-то должно прийти из com-порта, так вот если пришел ответ эмитируйте (emit) сигнал что подтверждение пришло, а если не пришло, то срабатывает таймер ожидания ответа, что ничего не пришло. В обоих случаях что-то там проходит и закрывается (или не закрывается) диалог прямым, то есть, обычным образом, а не через флаг.

Например, вам надо сообщить в диалоге, что время ожидания сигнала истекло. Делаем так:

d = new Dialog();
connect(d,SIGNAL(sendCommand()),this,SLOT(sendCommand()));
connect(&timer,SIGNAL(timeout()),d,SLOT(fail())); 
d->exec();

Если же мы получаем ответ из com-порта, то просто стопим таймер и никакого фейла не получаем.

READ ALSO
Ассоциативные массивы С++

Ассоциативные массивы С++

Можно ли как-то отключить сортировку по ключи в контейнере типа map? Допустим, есть код:

151
Переадресовать двумерный массив

Переадресовать двумерный массив

Недавно нашел интереснейшую задачуОчень хочу ее решить, но нет никаких идей (кроме как условиями)

129
Как преобразовать a/b` в сумму чисел вида `1/n`?

Как преобразовать a/b` в сумму чисел вида `1/n`?

Задача: преобразовать a/b в сумму чисел вида 1/nНапример, когда a=3 и b=7, то программа должна вывести 3/7 = 1/3 + 1/11 + 1/231

112
Поиск номера строки с искомым словом C++

Поиск номера строки с искомым словом C++

Цель: Пользователь вводит слово произвольной длины и имя файла, в котором это слово нужно найтиПрограмма должна вывести номер строчки, в которой...

137