通过实例交换Qt5维护信号连接

时间:2014-10-28 00:24:34

标签: c++ interface signals qt5 signals-slots

在我的 Qt5 计划中,我有一个界面,其中有一些信号

此接口的实现在启动时实现,信号从程序的不同部分(许多地方)连接。

现在我想删除该实例并创建一个新实例,可能来自另一个实现,并以某种方式维护信号连接以便所有接收信号的地方都不需要关心实施的变化。

有没有办法优雅地做到这一点,还是我必须改变程序的架构来控制一个地方的所有信号连接(很多工作)?

示例:

//PS: To be regarded as pseudocode at best, as lots of Qt boilerplate
//    and error handling code has been left out, and lots of bugs are left in :-)

struct MyInterface{
  virtual void doStuff()=0;
 signals:
  void someSignal();
}

struct MyImpX:public MyInterface{
  void doStuff(){
    qDebug()<<"MyImpX";
    if((random()%100)<5){
      emit someSignal();
    }
  }
}

struct MyImpY:public MyInterface{
  void doStuff(){
    qDebug()<<"MyImpY";
    if((random()%100)<10){
      emit someSignal();
    }
  }
}

struct MyWorker{
  QTimer t;
  MyInterface *inst=0;
  MyWorker(MyInterface *inst):
    inst(inst)
  {
    connect(&t,SIGNAL(timeout()),this,SLOT(doStuff()));
    t.start(100);
  }
  void setNewInstance(MyInterface *inst){
    this->inst=inst;
  }
  void doStuff(){
    if(0!=inst){
      inst->doStuff();
    }
  }
}


struct MyConsumer{
  public slots:
  void handleIt(){
    qDebug()<<"Handling signal";
  }
}



void main(){
 QApplication app;
 MyInterface *inst=new MyImpX();
  MyWorker con(inst);
  MyConsumer i,j,k,l;
  //In this example all the connects are in one place, but
  //in reality they are called from several locations that
  //Are hard to control.
  connect(inst,SIGNAL(someSignal()),&i,SLOT(handleIt()));
  connect(inst,SIGNAL(someSignal()),&j,SLOT(handleIt()));
  connect(inst,SIGNAL(someSignal()),&k,SLOT(handleIt()));
  connect(inst,SIGNAL(someSignal()),&l,SLOT(handleIt()));
  //[ ... At this point some time passes where the signal is working ]
  //Now the instance changes, so the old connections are lost.
  con.setNewInstance(new MyImpY());
  delete inst;
  inst=0;
  //[ ... At this point some time passes where the signal is NOT working ]
 app.exec();
}

1 个答案:

答案 0 :(得分:1)

您可以尝试根据this question实施某些内容,但我认为这样做最多只是hacky。

因此,相反,您可以拥有一个代理对象,该代理对象不会被更改,并且可以在实际对象更改时更改其连接。为此,您可能应该使用信号 - 信号连接,但您也可以编写发出信号的插槽。问题有伪代码,所以这里也有一些伪代码,以证明原理。

class MyInterfaceSignalProxy : public MyInterface { 
//...
public:
    void reconnect(MyInterface *newObj, MyInterface *oldObj=0) {
        if(oldObj) disconnect(oldObj, 0, this, 0); // disconnect old connections
        connect(newObj, SIGNAL(someSignal()), this, SIGNAL(someSignal()));
    }

signals:
    void someSignal();
}

当然你可以删除oldObj参数,例如将当前连接的对象存储为私有变量,或者只是不关心先前连接的断开连接(例如,如果oldObj将被删除或者其他在其他地方断开连接)。

然后你的main就会开始:

void main(){
  QApplication app;

  MyInterfaceSignalProxy proxy; 
  MyConsumer i,j,k,l;
  connect(&proxy,SIGNAL(someSignal()),&i,SLOT(handleIt()));
  connect(&proxy,SIGNAL(someSignal()),&j,SLOT(handleIt()));
  connect(&proxy,SIGNAL(someSignal()),&k,SLOT(handleIt()));
  connect(&proxy,SIGNAL(someSignal()),&l,SLOT(handleIt()));

  MyInterface *inst=new MyImpX();
  proxy.reconnect(inst);
  //....

  MyInterface *inst2=new MyImpY();
  proxy.reconnect(inst2, inst);
  delete inst; // whatever