如何获取从无关信号传递到插槽的值?

Posted

技术标签:

【中文标题】如何获取从无关信号传递到插槽的值?【英文标题】:How to get the value passed from an unrelated signal to a slot? 【发布时间】:2021-01-18 22:49:42 【问题描述】:

我有一个用于请求数据的异步调用的信号/槽安排。通常这很好,因为接收到的数据只是更新控件。但在某些情况下,我必须等待对请求的回复以确保操作完成,然后再进行下一步。每次有效接收数据排队时都会触发一个信号。

也需要阻塞写入,但读/写机制几乎相同。

以下代码模式,使用本地事件循环,是(我相信)等待信号的标准模式。

但是信号是用额外的数据发送的,在这种情况下是地址和其他东西。

我需要检查信号是否与请求相关联,否则我可能会过早地继续下一步。

当接收槽不知道如何处理它时,我如何接收该额外(地址)数据,因为在这种情况下,槽是一个事件循环(或计时器)。

我真的必须继承 QEventLoop 还是有更简单的方法?

以下是一个稍微简化/做作的示例。

quint16 System::blockingRead(quint16 address)

    QTimer timer;
    timer.setSingleShot(true);
    QEventLoop loop;
    connect( this, &System::readComplete, &loop, &QEventLoop::quit );
    connect( &timer, &QTimer::timeout, &loop, &QEventLoop::quit );    
    timer.start(3000);
    
    ReadFromSystem(address);  //  Asynchronous call
    
    bool waiting = true;
    bool timeout = false
    do 
        loop.exec();
        waiting = loop.getReceivedAddress() == address;
        timeout = not timer.isActive();
    while(waiting and not timeout);

    if(not timeout) 
        return(loop.getExtraData());
    
    else 
        throw ECRException();
        qDebug("timeout");
    

【问题讨论】:

这是现有应用程序的一部分。我需要添加一个测试功能,在校准循环期间将远程硬件置于测试模式。现有的校准循环收集流数据。进入测试模式包括发送测试模式的命令,然后在读取新的(现在是合成的)流数据之前轮询 ack。因此,现有的校准循环需要等待并轮询,直到远程硬件响应。 因此现有的校准循环需要等待和轮询,直到远程硬件响应。它不需要等待。请阅读我的回答。 【参考方案1】:

你的代码对我来说似乎完全错误,这让我觉得你有一个 XY 问题。因此,我将不理会代码,而是尝试帮助您解决实际问题。

让我从我认为应该如何使用信号和插槽的基本误解开始,因为这对于找到合适的解决方案很重要:

    如何获取从无关信号传递到槽的值?

没有像不相关的信号这样的东西。如果您将插槽连接到信号,则可以使它们相关。

    使用本地事件循环(我相信)是等待信号的标准模式

您无需等待信号。您将一个插槽连接到它以处理它被发射的事件。

    在进行下一步之前,我必须等待对请求的回复以确保操作完成。

不,您不必等待。保持状态并做出相应的反应。

现在最后一件事是我相信您在应用程序中真正需要的。根据您的通信协议和变量定义一个enum,其中包含可能的状态,例如m_state,属于这种类型。然后更新槽中的m_state,它连接到每次有效接收数据排队时触发的信号。在这个插槽中检查m_state 并使用switch 执行一项或另一项操作,具体取决于其值。为这些一个或另一个动作中的每一个准备不同的方法是个好主意。

【讨论】:

查看评论:我真的不想为了添加硬件测试功能而重写现有应用程序。 @JasonMorgan 你有一个每次有效接收数据排队时都会触发的信号,对吗?你已经连接了一个插槽,对吧?为什么需要重写应用程序?根据需要实施插槽,一切顺利。【参考方案2】:

最终解决方案,无需重写整个内容。

子类QEventLoop,传递期望的地址,然后对接收到的队列项地址添加检查。

如果预期地址出现在队列中,则循环可以退出事件循环并返回预期值。

如果计时器到期,那么我们已经等待了太长时间,因此引发异常并退出事件循环。

每次解码有效帧时,现有代码都会发出 readComplete(TransportReply *)。

在 sys.h 中

class SysEventLoop: public QEventLoop

    Q_OBJECT

public:
    SysEventLoop(quint16 address) : QEventLoop()m_address = address;

public slots:
    void wait_for_address(TransportReply * reply)
        if(!reply)
        
            qDebug() << "Waiting: Null reply" << m_address;
            return;
        
        TransportDataUnit res = reply->result();
        quint16 addr = static_cast<quint16>(res.getAddress());
        if(m_address==addr)
        
            quit();
            qDebug() << "-----The wait is over" << m_address;
        
        else qDebug() << "Waiting:" << addr << "!=" << m_address;
    


private:
    quint16 m_address;
;

在 sys.cpp 中

quint16 System::blockingRead(quint16 address)

    QTimer timer;
    timer.setSingleShot(true);
    SysEventLoop loop(address);  //Pass the expected address

    connect( this, &System::readComplete, &loop, &SysEventLoop::wait_for_address );
    connect( &timer, &QTimer::timeout, &loop, &SysEventLoop::quit );    
    timer.start(3000);
    
    ReadFromSystem(address);  //  Asynchronous call, read request queued.
    
    loop.exec();   //Wait here until the expected address turns up.
    //The UI is not blocked.
    //Reads from addresses we did not want are ignored.

    if(not timer.isActive()) 
        return(loop.getExtraData());
    
    else 
        throw ECRException();
    

【讨论】:

以上是关于如何获取从无关信号传递到插槽的值?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Alexa 插槽中获取单个字母

如何通过信号和槽传递参数?

如何使用信号/槽机制获取发送者小部件?

两个不同类别的信号和插槽

jquery 如何获取从客户端传递过来参数的值(typeId,tableCode,empCode)

如何使用 QWebChannel 从 python 接收数据到 js?