0

次のQtコードでダイアログを閉じたり解放したりするのに問題があります。

 //Segment 1: To open a 'wait' dialog for some long-running tasks
 void MainWindow::ui_showProgressDialog(QString title) {
     dlgProgress = new QProgressDialog(title, tr("Cancel"), 0, 0, this);
     dlgProgress->setAttribute(Qt::WA_DeleteOnClose); // line 1
     dlgProgress->setModal(true);
     dlgProgress->show();
     connect(voidWatcher, SIGNAL(finished()),
             this, SLOT(onPopulationFile()));
 }

 //Segment 2: Attempts to close the 'wait' dialog
 void MainWindow::onPopulationFile() {
    qDebug((dlgProgress == NULL) ? "true" : "false");
    if (dlgProgress) // 
    {
        qDebug("0");
        dlgProgress->close(); // line 2
        qDebug("1");
    }
    qDebug((dlgProgress == NULL) ? "true" : "false");
 }

問題:呼び出し'ui_showProgressDialog'を2回トリガーすると、2番目の呼び出しは常にプログラムをクラッシュさせます。元々、私のコードにはセグメント1の1行目がなく、QtCreatorからは、常にセグメント2の2行目でクラッシュします。デバッグメッセージは次のように表示されます。

// first call to onPopulationFile
false
0
1
false
// second call to onPopulationFile
false
0
*** CRASH ***    

異なるスレッドからオブジェクトを削除しないというドキュメントを読みました。「onPopulationFile」の呼び出しが非メインスレッドから呼び出されるのではないかと思います。そこで、セグメントに1行目を追加して、オブジェクトを削除するタイミングをプログラムに決定させました。しかし、それはうまくいかないようです。問題への提案はありますか?

実験完了:QProgressDialogをQDialogに置き換えると、プログラムはクラッシュせずに実行され、デバッグメッセージが表示されます。

// first call to onPopulationFile
false
0
1
false
// second call to onPopulationFile
false
0
1
false

それで、

  • セグメント2の2番目のヌルテストが常に失敗するのはなぜですか?[編集:変数を明示的にNULLに設定する必要があります]
  • 「待機」ダイアログを閉じるためのより良い方法はありますか?
  • できるだけ早くメモリを解放したいので、ダイアログを閉じたり解放したりしようとしています。本当にダイアログを手動で削除する必要がありますか?

プラットフォーム:Qt Opensource 4.8(x64)、Windows 7(x64)、MinGW(rubenvb 4.7.2)

4

1 に答える 1

4

dlgProgress->setAttribute(Qt::WA_DeleteOnClose);ウィジェットを閉じると、ウィジェットが削除されます。を呼び出しているdlgProgress->close();ときに、この行の後に、それが指すオブジェクトが解放され、dlgProgress無効なポインターになりました。

dlgProgressシグナルを使用して閉じる、またはイベントを改善するには、呼び出し後にnullに設定する必要がありますQobject::destroyed()

編集:

Qt::WA_DeleteOnClosecloseイベントが発生した場合にオブジェクトが削除されることを指定します。正確にはどれくらいの時間がかかりますか。たとえば、を使用している場合QObject::deleteLater()、オブジェクトはすぐには削除されません。そうでない場合でも、次のようなコードの断片

 A* a = new A;
 a->dosomething();
 delete a;
 a->dosomething();

未定義の動作です。への2番目の呼び出しa->dosomething();は、クラッシュするか(運が良ければ)、クラッシュしない可能性があります。

于 2013-01-31T10:28:20.133 に答える