Finishing QtQuick animation in the list and opening serial ports

I wrote a C ++ method to find all serial ports, open, write and close and use for Q_INVOKABLE to call this method from QML. In QML, first I push LoadPage.qml on the StackView and then I call the serial ports find (), inside the onClicked: Button slot.

Problem: It freezes when LoadPage.qml is pressed on the StackView if many serial ports are connected, starts the animation and then freezes immediately when the find function finishes starting the animation again. [SerialPort.qml] How is the best way to solve this?

//SerialPort.qml
Button {
    text: qsTr("start")
    onClicked: {
        stackView.push(Qt.resolvedUrl("LoadingPage.qml"))
        module.find()
    }
}


QVector<QString> Physical::find()
{
    m_ports.clear();

    foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) {
        bool hasError = false;

        QSerialPort port;
        port.setPort(info);

        if (port.open(QIODevice::ReadWrite)) {
            if (!hasError && !port.setBaudRate(serial::baudRate)) {
                emit error(tr("Can't set baud to %1, error %2")
                           .arg(port.portName())
                           .arg(port.error()));
                hasError |= true;
            }
            if (!hasError && !port.setDataBits(serial::dataBits)) {
                emit error(tr("Can't set data bits to %1, error %2")
                           .arg(port.portName())
                           .arg(port.error()));
                hasError |= true;
            }

            if (!hasError && !port.setParity(serial::parity)) {
                emit error(tr("Can't set parity to %1, error %2")
                           .arg(port.portName())
                           .arg(port.error()));
                hasError |= true;
            }
            if (!hasError && !port.setStopBits(serial::stopBits)) {
                emit error(tr("Can't set stop bits to %1, error %2")
                           .arg(port.portName())
                           .arg(port.error()));
                hasError |= true;
            }
            if (!hasError && !port.setFlowControl(serial::flowCtrl)) {
                emit error(tr("Can't set flow control to %1, error %2")
                           .arg(port.portName())
                           .arg(port.error()));
                hasError |= true;
            }
            if (!hasError) {
                m_ports.append(port.portName());
            }

            QByteArray data;
            data.resize(1);
            data[0] = ID_READ;

            port.write(data);
            port.close();
        }
    }

    return m_ports;
}

      

0


source to share


1 answer


Your code runs on the GUI thread, and because it blocks the GUI thread, the user interaction stops as well.

You need to scan in a separate thread. The Qt Concurrent option is ideal for this, since you are performing a self-contained action that can be performed on any thread. Your method find()

can be turned into a standalone function or a static method (since it really is). You can also capture this

in lambda.



Then you run it like this:

class Physical {
  QFuture<QStringList> m_future;
  QFutureWatcher<QStringList> m_futureWatcher;
  // A string list is a simpler type to type :)
  static QStringList doFindPorts() {
    ...
  }
  Q_SLOT void findPortsFinished() {
    QStringList ports(m_future);
    // use the list of ports
  }

public:
  Physical() {
    connect(&m_futureWatcher, SIGNAL(finished()), SLOT(findPortsFinished()));
    m_futureWatcher.set(m_future);
    ...
  }
  Q_SLOT void findPorts() {
    if (m_future.isRunning()) return;
    m_future = QtConcurrent::run(doFindPorts);
  }
};

      

+4


source







All Articles