1. 程式人生 > WINDOWS開發 >Qt 對話方塊窗體關閉時,如何自動銷燬窗體類物件、清空記憶體

Qt 對話方塊窗體關閉時,如何自動銷燬窗體類物件、清空記憶體

一、問題:

在主視窗點選彈出一個對話方塊後,對話方塊中包含了一個定時器。在關閉對話方塊後定時器物件仍在執行。

mainwindow.cpp

1 void MainWindow::on_actionKSE5K_triggered()//add actionKSE5K
2 {
3     m_jokey_ksg = new JokeyDialog(this);
4    // m_jokey_ksg->setModal(true);
5     m_jokey_ksg->show();
6 }

jokeydialog.cpp

 1 JokeyDialog::JokeyDialog(QWidget *parent) :
2 QDialog(parent), 3 ui(new Ui::JokeyDialog) 4 { 5 ui->setupUi(this); 6 7 m_RTdata_flash_timer = new QTimer(this); 8 connect(m_RTdata_flash_timer,SIGNAL(timeout()),this,SLOT(handleRTDATA_flashTimeout())); 9 m_RTdata_flash_timer->start(RTDATA_FLASH_TIME); 10 11
} 12 13 JokeyDialog::~JokeyDialog() 14 { 15 delete m_RTdata_flash_timer; //no use 16 delete ui; 17 }

二、解決方法

this->setAttribute(Qt::WA_DeleteOnClose,true); // false 則不立即清空
 1 JokeyDialog::JokeyDialog(QWidget *parent) :
 2     QDialog(parent), 3     ui(new Ui::JokeyDialog)
 4 {
 5     ui->setupUi(this
); 6 this->setAttribute(Qt::WA_DeleteOnClose,true); 7 m_RTdata_flash_timer = new QTimer(this); 8 connect(m_RTdata_flash_timer,SLOT(handleRTDATA_flashTimeout()));
9 m_RTdata_flash_timer->start(RTDATA_FLASH_TIME); 10 11 } 12 13 JokeyDialog::~JokeyDialog() 14 { 15 delete m_RTdata_flash_timer; //no use 16 delete ui; 17 }

三、參考內容:
關於視窗關閉的操作,在這裡指出常用的三個槽,即quit(),exit()以及close()。
首先說明視窗退出時,系統提示對話方塊的程式碼編輯。對主程式的退出,可以呼叫成員函式exit(),同時也可以呼叫槽quit(),二者此時都能起到關閉應用程式的作用。
只是應注意二者呼叫的方式不同。如下程式示例:

1 {
2  QApplication* app;
3  app->exit(0);
4 }
5 或者:
6 {
7  QApplication* app;
8  app->quit();
9 }

注意 通過設定

QWidget::setAttribute(Qt::WA_DeleteOnClose)

,在關閉對話方塊(手動close獲取esc closeEvent)的時候會自動呼叫解構函式

此時二者是等價的,即void QApplication::quit ()等價於函式呼叫 QApplication::exit( 0 )。
此時,若需要給出使用者提示,則只需要在程式當中新增QMessageBox的訊息判斷語句,以提示使用者是否確定退出應用程式。
另外,quit()作為槽,也可以連線訊號和槽的形式,響應某個訊號後關閉應用程式。如:

QPushButton *quitButton = new QPushButton( "Quit" );
connect( quitButton,SIGNAL(clicked()),qApp,SLOT(quit()) );

如果關閉的不是應用程式,而是關閉視窗等部件的形式,則必須呼叫close()函式,已關閉部件。如下:

if (!(QMessageBox::information(this,tr("CT Control View"),tr("Do you really want to log out CT Control View?"),tr("Yes"),tr("No"))))
{
 this->close();
}

其中通過一條if語句,判斷條件為一個對話方塊,根據使用者的選擇做出是否關閉該部件,this在這裡代表當前視窗部件物件的地址。當用戶選擇“Yes”時,該視窗部件退出;反之則取消退出操作。

至此,我們已經簡單瞭解了應用程式和視窗等部件的退出或關閉的程式碼編輯。然而,如果使用者點選視窗右上角的X按鍵時,你會發現視窗仍然會在不給出任何提示的情況下直接退出了,即便你在程式當中已添加了提示的對話方塊語句。
那為什麼此時的關閉操作沒有按我們希望的那樣先給出提示對話方塊呢?原因是此時的關閉操作並沒有引起呼叫帶有提示訊息的關閉或退出語句。
當用戶點選X關閉視窗時,系統會自動將這個事件告之某個特定的函式,即void QWidget::closeEvent ( QCloseEvent*e ),因此,這種情況應特別注意。
在關閉視窗前,可先定義一條訊息語句,以提示使用者是否確定關閉視窗。如:

 1 void mainWindow::closeEvent( QCloseEvent * event )
 2 {
 3     switch( QMessageBox::information( this,tr("CT Control View"), 4      tr("Do you really want to log out CT Control View?"), 5      tr("Yes"),tr("No"),0,1 ) ) 
 6   {
 7      case 0:
 8    event->accept();
 9          break;
10      case 1:
11   default: 
12          event->ignore();
13          break; 
14   }   
15 }

編譯程式後,系統會在使用者響應close操作時,自動呼叫該語句。也許這個時候你還會問,上面的那個功能函式究竟是把它定義成槽呢,還是定義成成員函式。答案是二者都可以。
一方面槽本身就是一個特殊的成員函式,除了能與訊號連線之外,其功能與函式無異。另一方面,此時不需要額外設定連線訊號和槽,新增該功能函式之後,視窗一旦有了close操作,機會立即響應該。

儘管新增closeEvent( QCloseEvent * event )這一功能函式之後,視窗會在關閉時給出提示對話方塊。但有時候還會發生這樣一種情況:在點選確認關閉後,還會再會出現一個對話方塊,即提示對話方塊會出現兩次。那這又是什麼原因呢?其實很簡單,那是因為closeEvent( QCloseEvent * event )只會響應close的操作,出現兩次對話方塊無疑是在自定義的關閉函式中又新增一條提示對話方塊語句,確認關閉後,響應close操作,這時系統又會馬上呼叫closeEvent( QCloseEvent * event )這個函式。
因此,解決的辦法是隻定義一個帶提示對話方塊的關閉函式,對不同的關閉操作都相應closeEvent( QCloseEvent * event )這個函式即可。

最後,如果想要在關閉主視窗或主程式時,所有開啟的獨立的子視窗都能同時被關閉。那麼這個時候一般是在main.cpp檔案中連線訊號void QApplication::lastWindowClosed ();關於lastWindowClosed()的詳細介紹,這裡不作說明,需要使用時可以使用Qt Assistant檢視其使用發法。如:

 1 int main( int argc,char ** argv )
 2 {
 3     QApplication a( argc,argv );
 4     ABMainWindow *mw = new ABMainWindow();
 5     mw->setCaption( "Qt Example - Addressbook" );
 6     a.setMainWidget( mw );
 7     mw->show();
 8     a.connect( &a,SIGNAL( lastWindowClosed() ),&a,SLOT( quit() ) );
 9     int result = a.exec();
10     delete mw;
11     return result;
12 }

這樣,系統會在關閉主視窗部件時,同時關閉開啟的其它子視窗程式。比較值得說明的是,並不是使用了a.connect( &a,&a,SLOT( quit() ) )這條語句後就一定能實現該功能。在此之前,必須特別注意是否設定了主視窗部件,即呼叫setMainWidget這一功能函式,這樣,當關閉這一主視窗部件時,才會響應關閉這一時刻已開啟的其它子視窗部件。