Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QCloseEvent wait for a function to terminate
Forum Updated to NodeBB v4.3 + New Features

QCloseEvent wait for a function to terminate

Scheduled Pinned Locked Moved Unsolved General and Desktop
3 Posts 3 Posters 227 Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • H Offline
    H Offline
    hkottmann
    wrote on last edited by
    #1

    I've wrote a small program just to check serial ports to which COM-name they are mapped. In fact i connect a Keithley Nanovoltmeter to a port, select in the gui the port name by port name until the device answers. When it answers the function keeps reading out the current voltage in a loop. But when I close the app by clicking on the X-button, this function will not be stopped and the program does not terminate correctly. So I tried to use the function closeEvent to set the stop flag and to wait until the running function terminates. But the program keeps hanging in this closeEvent function. How can I implement this?

    fc884b06-4e96-45a7-ae3a-88f22a92c24f-image.png

    #include "comportchecker.h"
    #include "ui_comportchecker.h"
    
    #include <QtSerialPort/QSerialPortInfo>
    #include <QElapsedTimer>
    #include <QTimer>
    #include <QCloseEvent>
    
    COMPortChecker::COMPortChecker(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::COMPortChecker)
    {
        ui->setupUi(this);
        const auto availablePorts = QSerialPortInfo::availablePorts();
        for (const QSerialPortInfo &info : availablePorts)
            ui->serialCombo->addItem(info.portName());
    
        ui->serialCombo->model()->sort(0);
        serial = new QSerialPort(this);
        ui->stoppButton->setEnabled(false);
    }
    
    COMPortChecker::~COMPortChecker()
    {
        delete ui;
    }
    
    void COMPortChecker::closeEvent(QCloseEvent *e)
    {
        if(!stop)
        {
            stop = true;
            do
            {
                QEventLoop loop;
                QTimer::singleShot(50, &loop, SLOT(quit()));
                loop.exec();
            } while (stop);
        }
        e->accept();
    }
    
    void COMPortChecker::on_startButton_clicked()
    {
        stop = false;
        bool found = true;
        if(serial->isOpen())
            serial->close();
        serial -> setBaudRate(9600);
        serial -> setDataBits(QSerialPort::Data8);
        serial -> setParity(QSerialPort::NoParity);
        serial -> setStopBits(QSerialPort::OneStop);
        serial -> setFlowControl(QSerialPort::NoFlowControl);
        serial -> setPortName(ui->serialCombo->currentText());
        if(!serial -> open(QIODevice::ReadWrite))
        {
            return;
            ui->statusBar->showMessage(QString("Could not open %1").arg(serial->portName()), 20000);
        }
        ui->startButton->setEnabled(false);
        ui->stoppButton->setEnabled(true);
        QStringList cmds;
        cmds << "*RST";
        cmds << "*CLS";
        cmds << ":INIT:CONT OFF;:ABORT";
        cmds << ":SENS:FUNC 'VOLT:DC'";
        cmds << ":SENS:VOLT:DC:RANG:AUTO ON";
        cmds << ":SENS:VOLT:DC:NPLC 1"; // 1 = Medium, 5 = Slow
        cmds << ":SYST:AZER:STAT ON";
        cmds << ":INIT";
        foreach (QString cmd, cmds)
        {
            QByteArray arr = cmd.append("\r").toLatin1();
            serial->write(arr);
            QEventLoop loop;
            QTimer::singleShot(50, &loop, SLOT(quit()));
            loop.exec();
        }
        QEventLoop loop;
        QTimer::singleShot(1000, &loop, SLOT(quit()));
        loop.exec();
        serial->write(":SYST:VERS?\r");
        //serial->write(":FETC?\r");
        QString answer = "";
        int counter = 0;
        do
        {
            serial->waitForReadyRead(20);
            answer.append(serial->readAll());
            counter++;
        }
        while (!answer.contains("\r") && counter < 50);
        if(counter == 50)
        {
            stop = true;
            found = false;
            ui->statusBar->showMessage(QString("No Keithley found at %1").arg(serial->portName()), 10000);
        }
        else
        {
            ui->statusBar->showMessage(QString("Keithley found at %1").arg(serial->portName()));
        }
        QElapsedTimer timer;
        timer.start();
        while (!stop)
        {
            serial->write(":SENS:CHAN 1\r");
            serial->write(":FETC?\r");
            answer = "";
            do
            {
                serial->waitForReadyRead(5);
                answer.append(serial->readAll());
            }
            while (!answer.contains("\r"));
    
            answer = answer.replace("\r", "");
            ui->vLabel->setText(answer);
            ui->msLabel->setText(QString::number(timer.restart()));
            qApp->processEvents();
        }
        serial->close();
        ui->vLabel->setText("");
        ui->msLabel->setText("");
        if(found)
            ui->statusBar->showMessage("Query closed", 5000);
        ui->startButton->setEnabled(true);
        ui->stoppButton->setEnabled(false);
        stop = false;
    }
    
    
    void COMPortChecker::on_stoppButton_clicked()
    {
        stop = true;
    }
    
    
    
    JonBJ 1 Reply Last reply
    0
    • H hkottmann

      I've wrote a small program just to check serial ports to which COM-name they are mapped. In fact i connect a Keithley Nanovoltmeter to a port, select in the gui the port name by port name until the device answers. When it answers the function keeps reading out the current voltage in a loop. But when I close the app by clicking on the X-button, this function will not be stopped and the program does not terminate correctly. So I tried to use the function closeEvent to set the stop flag and to wait until the running function terminates. But the program keeps hanging in this closeEvent function. How can I implement this?

      fc884b06-4e96-45a7-ae3a-88f22a92c24f-image.png

      #include "comportchecker.h"
      #include "ui_comportchecker.h"
      
      #include <QtSerialPort/QSerialPortInfo>
      #include <QElapsedTimer>
      #include <QTimer>
      #include <QCloseEvent>
      
      COMPortChecker::COMPortChecker(QWidget *parent)
          : QMainWindow(parent)
          , ui(new Ui::COMPortChecker)
      {
          ui->setupUi(this);
          const auto availablePorts = QSerialPortInfo::availablePorts();
          for (const QSerialPortInfo &info : availablePorts)
              ui->serialCombo->addItem(info.portName());
      
          ui->serialCombo->model()->sort(0);
          serial = new QSerialPort(this);
          ui->stoppButton->setEnabled(false);
      }
      
      COMPortChecker::~COMPortChecker()
      {
          delete ui;
      }
      
      void COMPortChecker::closeEvent(QCloseEvent *e)
      {
          if(!stop)
          {
              stop = true;
              do
              {
                  QEventLoop loop;
                  QTimer::singleShot(50, &loop, SLOT(quit()));
                  loop.exec();
              } while (stop);
          }
          e->accept();
      }
      
      void COMPortChecker::on_startButton_clicked()
      {
          stop = false;
          bool found = true;
          if(serial->isOpen())
              serial->close();
          serial -> setBaudRate(9600);
          serial -> setDataBits(QSerialPort::Data8);
          serial -> setParity(QSerialPort::NoParity);
          serial -> setStopBits(QSerialPort::OneStop);
          serial -> setFlowControl(QSerialPort::NoFlowControl);
          serial -> setPortName(ui->serialCombo->currentText());
          if(!serial -> open(QIODevice::ReadWrite))
          {
              return;
              ui->statusBar->showMessage(QString("Could not open %1").arg(serial->portName()), 20000);
          }
          ui->startButton->setEnabled(false);
          ui->stoppButton->setEnabled(true);
          QStringList cmds;
          cmds << "*RST";
          cmds << "*CLS";
          cmds << ":INIT:CONT OFF;:ABORT";
          cmds << ":SENS:FUNC 'VOLT:DC'";
          cmds << ":SENS:VOLT:DC:RANG:AUTO ON";
          cmds << ":SENS:VOLT:DC:NPLC 1"; // 1 = Medium, 5 = Slow
          cmds << ":SYST:AZER:STAT ON";
          cmds << ":INIT";
          foreach (QString cmd, cmds)
          {
              QByteArray arr = cmd.append("\r").toLatin1();
              serial->write(arr);
              QEventLoop loop;
              QTimer::singleShot(50, &loop, SLOT(quit()));
              loop.exec();
          }
          QEventLoop loop;
          QTimer::singleShot(1000, &loop, SLOT(quit()));
          loop.exec();
          serial->write(":SYST:VERS?\r");
          //serial->write(":FETC?\r");
          QString answer = "";
          int counter = 0;
          do
          {
              serial->waitForReadyRead(20);
              answer.append(serial->readAll());
              counter++;
          }
          while (!answer.contains("\r") && counter < 50);
          if(counter == 50)
          {
              stop = true;
              found = false;
              ui->statusBar->showMessage(QString("No Keithley found at %1").arg(serial->portName()), 10000);
          }
          else
          {
              ui->statusBar->showMessage(QString("Keithley found at %1").arg(serial->portName()));
          }
          QElapsedTimer timer;
          timer.start();
          while (!stop)
          {
              serial->write(":SENS:CHAN 1\r");
              serial->write(":FETC?\r");
              answer = "";
              do
              {
                  serial->waitForReadyRead(5);
                  answer.append(serial->readAll());
              }
              while (!answer.contains("\r"));
      
              answer = answer.replace("\r", "");
              ui->vLabel->setText(answer);
              ui->msLabel->setText(QString::number(timer.restart()));
              qApp->processEvents();
          }
          serial->close();
          ui->vLabel->setText("");
          ui->msLabel->setText("");
          if(found)
              ui->statusBar->showMessage("Query closed", 5000);
          ui->startButton->setEnabled(true);
          ui->stoppButton->setEnabled(false);
          stop = false;
      }
      
      
      void COMPortChecker::on_stoppButton_clicked()
      {
          stop = true;
      }
      
      
      
      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by JonB
      #2

      @hkottmann
      Your code relies on on_startButton_clicked() running to end so that it executes the final stop = false; there. Does it even do so? It has a

              do
              {
                  serial->waitForReadyRead(5);
                  answer.append(serial->readAll());
              }
              while (!answer.contains("\r"));
      

      loop in it, what is going to make it exit that loop?

      In a word, I would radically alter your on_startButton_clicked() code. It should be much smaller, no loops, no waitForReadyRead()s, no while (!stop) or that do ... while () loop, no UI updating. And no processEvents(). It is a slot on pushing a button. It should do no more than start the reading/writing process, maybe start some timer, and exit the slot. Anything further should be done in slots attached to signals for data arriving (readyRead()) or QTimer::timeouts.

      Axel SpoerlA 1 Reply Last reply
      3
      • JonBJ JonB

        @hkottmann
        Your code relies on on_startButton_clicked() running to end so that it executes the final stop = false; there. Does it even do so? It has a

                do
                {
                    serial->waitForReadyRead(5);
                    answer.append(serial->readAll());
                }
                while (!answer.contains("\r"));
        

        loop in it, what is going to make it exit that loop?

        In a word, I would radically alter your on_startButton_clicked() code. It should be much smaller, no loops, no waitForReadyRead()s, no while (!stop) or that do ... while () loop, no UI updating. And no processEvents(). It is a slot on pushing a button. It should do no more than start the reading/writing process, maybe start some timer, and exit the slot. Anything further should be done in slots attached to signals for data arriving (readyRead()) or QTimer::timeouts.

        Axel SpoerlA Offline
        Axel SpoerlA Offline
        Axel Spoerl
        Moderators
        wrote on last edited by
        #3

        I haven't compiled and tested the application, but adding to what @JonB wrote:
        There is a lot of heavy lifting with blocking code. Even though events are processed in blocking loops, UI reactions may be hampered. Recommend to sit back, check what needs to be done, which signals flag intermediate results.

        Software Engineer
        The Qt Company, Oslo

        1 Reply Last reply
        2

        • Login

        • Login or register to search.
        • First post
          Last post
        0
        • Categories
        • Recent
        • Tags
        • Popular
        • Users
        • Groups
        • Search
        • Get Qt Extensions
        • Unsolved