QTimer::singleShot 仅在间隔为 0 时调用 lambda

Posted

技术标签:

【中文标题】QTimer::singleShot 仅在间隔为 0 时调用 lambda【英文标题】:QTimer::singleShot only calling lambda when interval is 0 【发布时间】:2017-08-24 14:27:49 【问题描述】:

注意:我的原始帖子有一个重要的遗漏:我遗漏了我已经在 main 开头实例化了主 QApplication 实例。创建两个QApplication 实例是导致问题的原因。使用相同的 QApplication 实例而不是创建两个解决了该问题。

我的意图是在主应用程序之前运行QApplication 以迭代可用的蓝牙设备,以找到特定的设备。如果在某个时间限制内没有找到特定的,则终止QApplication。第一个存储的 lambda (startDiscovery) 在调用 QApplication::exec() 后立即被调用,但第二个存储的 lambda (cancelDiscovery) 永远不会被调用!相关部分如下:

#include <QtBluetooth/QBluetoothDeviceInfo>
#include <QtBluetooth/QBluetoothDeviceDiscoveryAgent>
#include <QtBluetooth/QBluetoothLocalDevice>
#include <QTimer>
#include <QString>
#include <QApplication>

#include <memory>
#define TARGET_BLUETOOTH_DEVICE_NAME "MyBluetoothDevice"  
#define BLUETOOTH_DISCOVERY_TIMEOUT 5000 //5 second timeout

int main(int argc, char *argv[])
    
    std::shared_ptr<QApplication> mainApplicationstd::make_shared<QApplication>(argc, argv);
    //Error checking for no adapters and powered off devices 
    //omitted for sake of brevity
    auto bluetoothAdapters = QBluetoothLocalDevice::allDevices();
    std::shared_ptr<QBluetoothLocalDevice> localDevicestd::make_shared<QBluetoothLocalDevice>(bluetoothAdapters.at(0).address());

    std::shared_ptr<QBluetoothDeviceDiscoveryAgent> discoveryAgentstd::make_shared<QBluetoothDeviceDiscoveryAgent>(localDevice.get());
    std::shared_ptr<QBluetoothDeviceInfo> targetDeviceInfonullptr;

    std::shared_ptr<QApplication> findBluetoothstd::make_shared<QApplication>(argc, argv);
    auto setTargetDeviceInfo = [=](QBluetoothDeviceInfo info) 
        if (info.name() == TARGET_BLUETOOTH_DEVICE_NAME) 
            targetDeviceInfo = std::make_shared<QBluetoothDeviceInfo>(info);
            discoveryAgent->stop();
            findBluetooth->exit(0);
        
    ;

    auto cancelDiscovery = [=]() 
        discoveryAgent->stop();
        findBluetooth->exit(1);
    ;

    auto startDiscovery = [=]() 
        discoveryAgent->start();
    ;

    QObject::connect(discoveryAgent.get(), &QBluetoothDeviceDiscoveryAgent::deviceDiscovered, setTargetDeviceInfo);
    QTimer::singleShot(0, startDiscovery); //startDiscovery get called fine
    QTimer::singleShot(BLUETOOTH_DISCOVERY_TIMEOUT, cancelDiscovery); //cancelDiscovery never gets called!

    findBluetooth->exec();

    //Now check if targetDeviceInfo is nullptr and run the real application etc...
    mainApplication->exec();


【问题讨论】:

【参考方案1】:

Answer:discoveryAgent-&gt;start(); 基本上阻塞了你的主线程。这就是为什么 QTimer::singleShot(BLUETOOTH_DISCOVERY_TIMEOUT, cancelDiscovery); 发布的事件永远不会得到处理 - 应用程序正在执行 discoveryAgent-&gt;start() 并且没有机会查看事件循环。

【讨论】:

我输入了相同的答案。对我来说,当运行代码的 PC 或设备上未准备好蓝牙功能时,它会显示这种行为。将其移至工作线程是有意义的。 感谢您的快速回答。不幸的是,如果我注释掉对 discoveryAgent->start() 的调用(或删除第一个 singleShot),cancelDiscovery 仍然不会被调用。 你怎么知道的?我无法复制。 我发现了我的问题。在我的实际应用程序中,我已经在 main() 的开头创建了主 QApplication 实例,这导致第二个实例无法按预期工作。 是的,我编辑了我的主要帖子以反映这一点。对此感到抱歉,感谢您的宝贵时间。【参考方案2】:

我原来的帖子有一个重要的遗漏:我遗漏了我已经在 main 开头实例化了主 QApplication 实例。创建两个 QApplication 实例是导致问题的原因。使用相同的 QApplication 实例而不是创建两个解决了该问题。

【讨论】:

以上是关于QTimer::singleShot 仅在间隔为 0 时调用 lambda的主要内容,如果未能解决你的问题,请参考以下文章

当 singleShot 为 True 时,QTimer 永远不会触发超时 [关闭]

QTimer::singleShot 在 qkeyevent 中不起作用

QTimer::SingleShot 在对象被删除后触发

QTimer::singleShot()函数使用

QTimer::singleShot(0, object SLOT(obj_slot())) 做啥?

PyQT实时显示串口数据在QtCore.QTimer.singleShot()上抛出最大递归深度超出异常