我编写了一个C ++方法来查找所有串口,打开,写入和关闭,并使用Q_INVOKABLE从QML调用此方法。在QML中,首先我将一个LoadingPage.qml推送到StackView,然后在onClicked:Button插槽中调用find()串行端口。
问题:如果连接了很多串口,那么将一个LoadingPage.qml推送到StackView是一个冻结,动画开始然后立即冻结,当函数找到动画再次启动时。 [SerialPort.qml] 如何解决这个问题的方法更好?
//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 :(得分:4)
您的代码在GUI线程中运行,并且由于它阻止了GUI线程,因此用户交互也会停止。
您需要在单独的线程中执行扫描。 Qt Concurrent框架非常适用于此,因为您正在执行可以在任何线程中完成的自包含操作。您的find()
方法可以转换为独立函数或静态方法(因为它实际上就是这样)。您还可以在lambda中捕获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()));
...
}
Q_SLOT void findPorts() {
if (m_future.isRunning()) return;
m_future = QtConcurrent::run(doFindPorts);
m_futureWatcher.setFuture(m_future);
}
};
答案 1 :(得分:0)
设置未来的正确界面是setFuture
并在启动线程后调用
m_future = QtConcurrent::run(doFindPorts);
m_futureWatcher.setFuture(m_future);