如何获取从不相关信号传递到插槽的值?
How to get the value passed from an unrelated signal to a slot?
我有一个 signal/slot 安排来请求数据的异步调用。通常这很好,因为接收到的数据只是更新控件。但在某些情况下,我必须等待对请求的回复,以确保操作已完成,然后再进行下一步。每次有效的接收数据排队时都会触发一个信号。
也有阻塞写入的需求,但read/write机制几乎相同。
以下使用本地事件循环的代码模式(我相信)是等待信号的标准模式。
但是信号是用额外的数据发送的,在这种情况下是地址和其他东西。
我需要检查信号是否与请求相关联,否则我可能会过早地继续下一步。
当接收槽不知道如何处理时,我如何接收额外的(地址)数据,因为在这种情况下,槽是一个事件循环(或计时器)。
我真的必须继承 QEventLoop 还是有更简单的方法?
下面略simplified/contrived举例
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");
}
}
你的代码对我来说似乎完全错误,这让我觉得你有一个 XY 问题。因此,我将单独留下代码,而是尝试帮助您解决实际问题。
让我从我认为应该如何使用信号和槽的根本误解开始,因为它对于找到合适的解决方案很重要:
- 如何获取从不相关信号传递到插槽的值?
不存在无关信号。如果您将插槽连接到信号,您就会使它们相关联。
- 使用本地事件循环,(我相信)是等待信号的标准模式
您无需等待信号。您将一个插槽连接到它以处理它被发射的事件。
- 我必须等待对请求的回复以确保操作已完成,然后才能进行下一步。
不,您不必等待。保持状态并做出相应反应。
现在最后一件事是我相信您在应用程序中真正需要的。根据您的通信协议和变量定义一个 enum
和可能的状态,例如m_state
,这种类型。然后更新插槽中的 m_state
,它连接到每次有效接收数据排队时触发的 信号 。在这个插槽中检查 m_state
并使用 switch
来执行一个或另一个操作,具体取决于它的值。为这些一个或另一个动作.
中的每一个准备不同的方法是个好主意
没有 re-writing 整个事情的最终解决方案。
子类QEventLoop,传递预期地址,然后在接收到的队列项地址上添加检查。
如果预期地址出现在队列中,则循环可以退出事件循环和 return 预期值。
如果计时器到期,那么我们等待的时间太长,因此引发异常并退出事件循环。
每次解码有效帧时,现有代码都会发出 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();
}
}
我有一个 signal/slot 安排来请求数据的异步调用。通常这很好,因为接收到的数据只是更新控件。但在某些情况下,我必须等待对请求的回复,以确保操作已完成,然后再进行下一步。每次有效的接收数据排队时都会触发一个信号。
也有阻塞写入的需求,但read/write机制几乎相同。
以下使用本地事件循环的代码模式(我相信)是等待信号的标准模式。
但是信号是用额外的数据发送的,在这种情况下是地址和其他东西。
我需要检查信号是否与请求相关联,否则我可能会过早地继续下一步。
当接收槽不知道如何处理时,我如何接收额外的(地址)数据,因为在这种情况下,槽是一个事件循环(或计时器)。
我真的必须继承 QEventLoop 还是有更简单的方法?
下面略simplified/contrived举例
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");
}
}
你的代码对我来说似乎完全错误,这让我觉得你有一个 XY 问题。因此,我将单独留下代码,而是尝试帮助您解决实际问题。
让我从我认为应该如何使用信号和槽的根本误解开始,因为它对于找到合适的解决方案很重要:
- 如何获取从不相关信号传递到插槽的值?
不存在无关信号。如果您将插槽连接到信号,您就会使它们相关联。
- 使用本地事件循环,(我相信)是等待信号的标准模式
您无需等待信号。您将一个插槽连接到它以处理它被发射的事件。
- 我必须等待对请求的回复以确保操作已完成,然后才能进行下一步。
不,您不必等待。保持状态并做出相应反应。
现在最后一件事是我相信您在应用程序中真正需要的。根据您的通信协议和变量定义一个 enum
和可能的状态,例如m_state
,这种类型。然后更新插槽中的 m_state
,它连接到每次有效接收数据排队时触发的 信号 。在这个插槽中检查 m_state
并使用 switch
来执行一个或另一个操作,具体取决于它的值。为这些一个或另一个动作.
没有 re-writing 整个事情的最终解决方案。
子类QEventLoop,传递预期地址,然后在接收到的队列项地址上添加检查。
如果预期地址出现在队列中,则循环可以退出事件循环和 return 预期值。
如果计时器到期,那么我们等待的时间太长,因此引发异常并退出事件循环。
每次解码有效帧时,现有代码都会发出 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();
}
}