2014-10-28 24 views
1

保持信號連接在我QT5程序我有一個接口一些信號以上實例交換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

你可以嘗試實現基於this question的東西,但我認爲這會在最好的是哈克。

因此,您可以擁有一個代理對象,它不會被更改,並且可以在實際對象更改時更改其連接。爲此,您應該使用信號連接,儘管您也可以編寫發射信號的插槽。問題有僞代碼,所以這裏也有一些僞代碼來證明原理。

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參數,例如當前連接的對象存儲爲私有變量,或者只是不關心斷線早期connectios(例如,如果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 
+0

感謝一個很好的答案!我不知道信號到信號的連接是可能的,這可能會很方便。我意識到emit關鍵字可以用來代表任何對象發出信號,而不僅僅是「this」,我實際上已經解決了這個問題。因此,在我的應用程序中,我將所有信號放在代理對象上並連接到該對象,然後只需從發送信號的任何位置執行「發出proxy.signal」。 – 2014-10-28 21:53:41