PDA

View Full Version : QSerialPort and QtQuick animation freezing on list and open serial ports



ricardodovalle
20th February 2014, 03:22
Anyone could help me, please.

I wrote a C++ method to find all serial ports, open, write and close and use to Q_INVOKABLE to call this method from a QML.

The problem is a freezing on push LoadingPage.qml if there are many serial ports connected, the animation start and then immediately freezes, when the function find finish, the animation start again. [SerialPort.qml]

How is it the better way to solve that?
Thanks

main.cpp


qmlRegisterType<Module::Physical>("MyType", 1, 0, "SerialPort");

Main.qml


ApplicationWindow {
SerialPort {
id: module
}
}

SerialPort.qml


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

serialport.h


Q_INVOKABLE QVector<QString> find();

serialport.cpp


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;
}

ricardodovalle
7th April 2014, 06:17
From StackOverflow, answered by Kuba Ober, source: http://stackoverflow.com/questions/21911526/qtquick-animation-freezing-on-list-and-open-serial-ports



Your code runs in the GUI thread, and since it blocks the GUI thread, the user interaction is stopped as well.

You need to perform the scan in a separate thread. The Qt Concurrent framework is perfect for this, since you're performing a self-contained action that can be done in any thread. Your find() method must be turned into a stand-alone function or a static method (since that's what it really is).

You'd then run it as follows:


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);
}
};

anda_skoa
7th April 2014, 10:05
That or processing the serial ports one at a time.

Cheers,
_

wysota
7th April 2014, 10:46
In general:

http://doc.qt.digia.com/qq/qq27-responsive-guis.html