事情是這樣的,我要做這樣的一個對話框
這個BKJIA這個水印很是煩人啊,害的我還要把圖片放大!
書歸正傳,這裡的這個對話框想必很多人應該都是見過的吧,這裡有三個QPushbutton,一個QLabel,當點擊三個按鈕的時候會有不同的響應。故事的背景是這樣的,這個是用來檢測程序是否正在運行的提示對話框,比如你要安裝某程序的升級包,但是這個程序可能正在運行,這時候系統可能會提示你先關閉程序在運行安裝包,這時候你就可以做這樣的一個對話框來給用戶進行交互。
首先來說這個對話框應該怎麼做,這裡給出對話框的頭文件runningdialog.h
#pragma once #include <QObject> #include <QWidget> class QLabel; class QPushButton; class RunningDialog: public QDialog { Q_OBJECT public: RunningDialog(QWidget *parent = 0 ); signals: void clicked(); private slots: void on_retryButton_clicked(); void on_forceButton_clicked(); void on_cancleButton_clicked(); private: QLabel* m_label; QPushButton* m_retryButton; QPushButton* m_forceButton; QPushButton* m_cancleButton; };
下面就是cpp文件了
RunningDialog::RunningDialog( QWidget *parent ) : QDialog(parent) { m_label = new QLabel("Please shut down your program and try again!"); m_retryButton = new QPushButton("Retry"); m_forceButton = new QPushButton("Forced to shut down"); m_cancleButton = new QPushButton("Cancle"); QVBoxLayout* vLayout = new QVBoxLayout; QHBoxLayout* hLayout = new QHBoxLayout; hLayout->addWidget(m_retryButton); hLayout->addWidget(m_forceButton); hLayout->addWidget(m_cancleButton); vLayout->addWidget(m_label); vLayout->addLayout(hLayout); setLayout(vLayout); setWindowTitle("Warning"); connect(m_retryButton, SIGNAL(clicked()), this, SLOT(on_retryButton_clicked())); connect(m_forceButton, SIGNAL(clicked()), this, SLOT(on_forceButton_clicked())); connect(m_cancleButton, SIGNAL(clicked()), this, SLOT(on_cancleButton_clicked())); }
這裡先只給出構造函數的寫法,其他的槽在後面陸續給出。
到這裡一個上面提出的界面就已經做好了,下面對於不同的按鈕我要添加不同的功能,首先來說這個retry按鈕吧,這個的功能是要你自己手動關閉需要關閉的程序,然後點這個按鈕程序才能繼續,否則就一直卡在這裡,顯示這個對話框,當然這個對話框一定要是模態的了,就是在處理完這個對話框的要求之前,你是不能干其他事情的。
下面請看retry的槽
void RunningDialog::on_retryButton_clicked() { bool isShutDown = !isRunning(); if (isShutDown) { close(); } }
好了,這裡用到isShutDown了,這個就是判斷你的程序正在運行否的bool型成員變量,isRunning()函數是用來判斷你程序是否正在運行的函數,一個外部函數,這裡在檢測到程序如果關閉的時候應該close()這個對話框,否則用戶不能繼續操作了。
好,下面說下force這個按鈕,這個按鈕的工功能是在用戶點擊之後由程序強行關閉這個進程,然後繼續後面的操作,省去了用戶手動關閉,或者手動關閉不成功的弊病,但是這樣的做法有點粗暴,可能有些用戶還是喜歡自己手動去關閉,所以這個按鈕一般放在第二的位置,下面給出這個按鈕的槽。
void RunningDialog::on_forceButton_clicked() { //下面是對進程強制關閉的處理 HANDLE snapShot; snapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (!snapShot) { return; } PROCESSENTRY32 *processInfo; processInfo = new PROCESSENTRY32; processInfo->dwSize = sizeof(PROCESSENTRY32); Process32First(snapShot, processInfo); std::wstring exeName; std::wstring exeRun = STR_EXE; while(Process32Next(snapShot, processInfo) != false) { exeName = processInfo->szExeFile; if (!exeName.compare(exeRun)) { break; } } HANDLE handle = OpenProcess(PROCESS_TERMINATE,FALSE,processInfo->th32ProcessID); TerminateProcess(handle, 0); //處理完成 close(); }
CreateToolhelp32Snapshot得到這在運行的進程的快照,就是把所有正在運行的進程都掃到這個snapShot句柄裡面了,PROCESSENTRY32是配合這個快照使用的,用來存放快照的信息什麼的,
Process32First(snapShot, processInfo);就是得到第一個正在運行的進程的函數,這裡是有返回值的,但是為了方便這裡就不對返回值進行判斷了,下面16-23行的while循環是對進程快照中的所有進程進行一個匹配,看是否能夠和已知給定的正在運行的程序的名字STR_EXE匹配成功,STR_EXE是自己事先存好的,很多這樣的東西都放在Const.h這樣的一個文件中,方便以後自己的項目用到裡面的一些路徑,這裡找到名字匹配的就退出循環,退出的時候processInfo裡面存放的就是你要關閉的這個進程的信息,24行是獲取這個進程的句柄,26行是關閉這個進程,強制關閉完成之後,要將對話框關閉。
下面就說一下cancle這個按鈕,這個按鈕的功能很簡單,就是關閉對話框,
void RunningDialog::on_cancleButton_clicked() { close(); }
可是總有些用戶會對癢癢的去點右上角的叉叉,什麼情況,情況就是沒情況,因為這個東西沒有任何的槽和響應函數與之對應,所以點了等於無響應,
RunningDialog* exeRun = new RunningDialog; exeRun->setModal(true); while (isRunning()) { //exeRun->show(); int result = exeRun->exec(); if (QDialog::Rejected == result) { break; } }
好了,首先創建對話框,並設置成模態的,之後。。。很關鍵,這裡是一個循環,因為主調要確保這個程序關閉的萬無一失才能繼續下面的操作,否則下面的操作可能都是徒勞,所以首先一定要判斷這個程序是否還在運行,isRunning()是不是true,之後光這樣也不行,看到這裡為什麼不用show()而用了exec(),這裡用show()會有這樣的結果
button和label沒有了,為什麼會這樣,因為顯示這個對話框的消息雖然發出去了,但是沒有被處理,所以程序一直在顯示同一個對話框,造成卡了的狀態,實際上是沒有調用消息的處理函數,這裡可以添加這樣的代碼
RunningDialog* exeRun = new RunningDialog; exeRun->setModal(true); while (isRunning()) { exeRun->show(); QApplication::processEvents(); //int result = exeRun->exec(); /*if (QDialog::Rejected == result) { break; }*/ }
這樣就可以正常的顯示之前的對話框了,但是這樣還是有問題,這裡點擊cancle和右上角的叉叉是不好用的,因為這個函數式無返回值的,所以即使這次把這個消息處理了,但是while循環並沒有結束,也就是需要繼續運行while所以點關閉了之後又顯示出來了,最後我們采取這樣的方法來做。
RunningDialog* exeRun = new RunningDialog; exeRun->setModal(true); while (isRunning()) { int result = exeRun->exec(); if (QDialog::Rejected == result) { break; } }
這裡連show()都不用了,因為調用exec()之後它會自動幫你處理,處理完之後等待其它的事件發生,當你點擊不同的按鈕的時候程序會自動暫停下來去執行這個響應,並把操作的結果返回,比如你點cancle會調用close,這裡就會返回一個QDialog::Rejected,我們對返回的結果進行比較,就可以把程序break掉,避免了死循環,好了,有關這個對話框就說到這裡了。
本文出自 “賣萌程序員” 博客,請務必保留此出處http://7677869.blog.51cto.com/7667869/1283224