スロットを信号に接続します。しかし、今は一時的にそれらを切断したいと思います。
クラス宣言の一部を次に示します。
class frmMain : public QWidget
{
...
private:
QTimer *myReadTimer;
...
private slots:
void on_btnDownload_clicked();
...
};
frmMain
のコンストラクターで、myReadTimer
が5秒ごとに呼び出されるように、ReadMyCom
をスロットに接続します。
myReadTimer=new QTimer(this);
myReadTimer->setInterval(5000);
connect(myReadTimer,SIGNAL(timeout()),this,SLOT(ReadMyCom()));
しかし、スロットon_btnDownload_clicked
で。 myReadTimer
がon_btnDownload_clicked
のスコープ内で信号を発信しないようにします。したがって、on_btnDownload_clicked
の先頭でそれらを切断し、最後に再接続します。このような:
void frmMain::on_btnDownload_clicked()
{
//some method to disconnect the slot & singal
...//the code that I want myReadTimer to leave me alone
//some method to reconnect the slot & singal
}
Stackoverflowで検索し、QObject
デストラクタを呼び出すような回答を得ました。しかし、私はそれを使用する方法がわかりません。
また、次のようにdisconnect
を使用しようとしました:
QMetaObject::Connection myConnect;
myConnect=connect(myReadTimer,SIGNAL(timeout()),this,SLOT(ReadMyCom()));
...
disconnect(& myConnect);
しかし、まだ機能しません。だから誰かがこれを行う方法を手伝ってくれますか?
QObject
には非常に便利な関数があります。これは時々便利です:QObject::blockSignals()
これは、必要なことを実行する非常に単純なfire-and-forgetクラスです。私はそれがデザインであることを信用していません。私はずっと前にインターネットでそれを見つけました。ただし、すべてのオブジェクトへのすべての信号をブロックすることに注意してください。これが望んでいない場合は、ニーズに合わせてクラスを変更できます。
class SignalBlocker{
public:
SignalBlocker(QObject *o): object(o), alreadyBlocked(object->signalsBlocked()){
if (!alreadyBlocked){
object->blockSignals(true);
}
}
~SignalBlocker() {
if (!alreadyBlocked){
object->blockSignals(false);
}
}
private:
QObject *object;
bool alreadyBlocked;
};
あなたの場合、使い方は簡単になります
void frmMain::on_btnDownload_clicked()
{
SignalBlocker timerSignalBlocker(myReadTimer);
...//the code that I want myReadTimer to leave me alone
// signals automatically unblocked when the function exits
}
UPDATE:
Qt 5.3から、APIに非常によく似たクラスが公式に追加されたことがわかります。わずかに大きな機能セットを使用して、上記と同様のジョブを実行します。 APIの変更に合わせてコードベースを最新の状態に保つために、代わりに公式の QSignalBlocker クラスを使用することをお勧めします。
ただし、使用方法はまったく同じです。
切断するものに応じて、切断を呼び出す方法は多数あります。 QObject documentation page を参照して、それらがどのように機能するかについて説明してください。
0を使用して「すべてのスロットを切断する」ことを意味する例を次に示します。
void frmMain::on_btnDownload_clicked()
{
// disconnect everything connected to myReadTimer's timeout
disconnect(myReadTimer, SIGNAL(timeout()), 0, 0);
...//the code that I want myReadTimer to leave me alone
// restore the connection
connect(myReadTimer,SIGNAL(timeout()),this,SLOT(ReadMyCom()));
}
または、次のように 'connect'構文をコピーして、切断する正確な信号とスロットのペアを指定できます。
disconnect(myReadTimer,SIGNAL(timeout()),this,SLOT(ReadMyCom()));
タイマーを使用しているので、これはもっと簡単かもしれません:
void frmMain::on_btnDownload_clicked()
{
// stop the timer (so you won't get any timeout signals)
myReadTimer->stop();
...//the code that I want myReadTimer to leave me alone
// restart the timer (using whatever interval was set previously)
myReadTimer->start();
}
元のアプローチとの違い:
interval
になります。シングルスレッドQtアプリケーションでは、既にシグナルを処理している場合、別のシグナルはそのコードの「途中でジャンプ」しません。代わりに、現在のスロットが戻った直後に処理するイベントとしてキューに入れられます。
したがって、タイマーを停止または切断する必要はまったくありません。
元のアプローチとの違い:
on_btnDownload_clicked
の実行に時間がかかる場合、on_btnDownload_clicked
の完了後に複数のReadMyCom
イベントがキューに入れられる可能性があります。 (この時点では、基本的にしばらくの間GUIを基本的に「ロックアップ」する操作があることに注意してください。関数をリファクタリングするか、独自のスレッドを与える方が理にかなっています。)