如何解决如何获得从无关信号传递到插槽的值?
我有一个信号/插槽安排,用于异步调用以请求数据。通常,这很好,因为接收到的数据只会更新控件。但是在某些情况下,我必须等待对请求的答复,以确保操作已完成,然后再进行下一步。每次将有效的接收数据排队时都会触发一个信号。
还需要阻止写操作,但是读/写机制几乎相同。
以下使用本地事件循环的代码模式(我相信)是等待信号的标准模式。
我需要检查信号是否与请求相关,否则我可能很快就继续下一步。
当接收插槽不知道如何处理该数据时,如何接收该额外的(地址)数据,在这种情况下,该插槽是事件循环(或计时器)。
我真的必须继承QEventLoop还是有更简单的方法?
以下是一个稍微简化/设计的示例。
quint16 System::blockingRead(quint16 address)
{
QTimer timer;
timer.setSingleShot(true);
QEventLoop loop;
connect( this,&System::readComplete,&loop,&QEventLoop::quit );
connect( &timer,&QTimer::timeout,&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");
}
}
解决方法
您的代码对我来说似乎是完全错误的,这使我认为您遇到了XY问题。因此,我将不理会代码,而是尝试帮助您解决实际的问题。
让我从我认为应该如何使用信号和时隙的根本误会开始,因为这对于找到合适的解决方案很重要:
- 如何获取从无关信号传递到插槽的值?
没有诸如无关信号之类的东西。如果您将插槽连接到信号,则会使它们相关。
- 使用本地事件循环是(我认为)等待信号的标准模式
您不必等待信号。您将插槽连接到该插槽以处理其发出的事件。
- 在继续下一步之前,我必须等待对请求的答复以确保操作已完成。
不,您不必等待。保持状态并做出相应反应。
现在,最后一件事是我认为您的应用真正需要的是什么。根据您的通讯协议和变量(例如,变量)定义一个enum
并带有可能的状态。 m_state
,这种类型。然后更新插槽中的m_state
,该插槽连接到每次将有效的接收数据排队时触发的信号。在这个插槽中,检查m_state
并根据其值使用switch
来执行一个或另一个操作。为这些一个或另一个动作中的每个动作准备不同的方法是个好主意。
最终解决方案,无需重新编写整个内容。
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,&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();
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。