在VC中利用Qt Designer建立自訂的slot
Qt自己出了個IDE,Qt Creator,支援GNU的編譯器與GDB除錯器
整合度之高,感覺真像是先前使用Borland C++ Builder的經驗一樣
不過,假如已經習慣了VC的編譯環境,就只能望著Qt Creator乾瞪眼嗎?
好在從Qt釋出了Visual Studio add-in (for open-source version)以後
Qt跟VC之間的距離就越來越近了
不用管什麼三部曲、uic與moc
視窗拉一拉,元件放一放,一個可口的GUI就完成了
打造複雜的GUI再也不是夢想!
在設計GUI的過程中,往往會碰到需要自行定義被觸發事件(signal)的處理方法(slot)
signal沒啥問題,通常是按鈕、選單等元件發出(e.g. 滑鼠點擊)
但是slot呢?並不是每個signal都找得到合適的預設slot
比方說,按一個按鈕開啟檔案對話框,然後載入一張圖片
應該找不到一個slot是剛好設定為「開啟檔案對話框」的吧!
這個時候,就需要自訂的slot來解決問題
signal跟slot的宣告,可以依照自己的喜好來設計(不過要照規則唷)
或是由Designer協助建立signal與slot的連結關係
為什麼要由Designer來協助呢?個人認為有兩個好處
1. 由Designer建立signal與slot的連結,不容易出錯
當使用Designer建立連結時,會幫你檢查signal傳送資料的型別與參數量與slot的是否相符
如果兩者的函式簽名對應不起來,你連看到slot的機會都沒有,大大的降低了出錯的可能性
2. 統一管理,程式碼不再亂糟糟
Designer提供了signal/slot編輯器,所有的連結關係都由此編輯器完成
在實做類別中,就不需要再手動寫連結signal/slot的程式碼了
講了一堆,就拿上面提到的例子開始吧~
以下的操作,以VC2008作為編譯環境
Qt版本是4.5.0 (open-source 編譯版),配上Visual Studio add-in 1.0.0
首先,開啟VC,建立一個新的Qt應用程式專案
假設應用程式的class name叫做MyQtApp
設定完成後,點兩下”myqtapp.ui”,帶出Qt Designer
就開始畫UI囉
在這個小範例中,需要兩個元件,一個是QLabel,用來顯示影像
另一個就是QPushButton,用來開啟檔案對話框用的
那檔案對話框呢?嗯…必須由程式產生了[註1],所以暫時先不管
最後設計好的視窗看起來會像這樣:
接著,重點出現了,要設定pushButton的signal/slot連結
按下pushButton,自然會用到clicked()這個signal
但是,要連到哪個slot呢?
利用編輯信號與信號槽的狀態下
發送者選擇pushButton,信號是clicked(bool) [註2]
而對象是我們的應用程式MyQtAppClass,信號槽是空白一片
沒關係,按下「編輯」後
在信號槽的地方增加一個新的信號槽
這個slot function的名稱隨便你設計,但是簽名要與發送的信號一致
在這裡,引數的型別一定要是bool
按下「確定」後,原先空白一片的信號槽出現剛剛新增的slot function囉!
設定連結後,最後可以在信號與信號槽編輯器看到剛剛建立的連結結果
到這裡,Qt Designer的工作已經完成了
剩下的工作就是coding,定義剛剛新增的slot function
回到VC2008中,開啟myqtapp.h
宣告剛剛新增的slot function,假設放在private好了,因此myqtapp.h看起來就像
class MyQtApp : public QWidget
{
Q_OBJECT
public:
MyQtApp(QWidget *parent = 0, Qt::WFlags flags = 0);
~MyQtApp();
private:
Ui::MyQtAppClass ui;
private slots:
void slotOpenImage( bool );
};
重點就是那第13行,函式名稱要跟剛剛新增的一樣,簽名也要相同
別忘了,slot function一定不可以有返回值(void)
接著,定義slotOpenImage( bool ),就跟尋常的member function沒兩樣了
void MyQtApp::slotOpenImage( bool _b )
{
QFileDialog file_dialog( this, tr( "Open Image" ), "./", tr( "PNG image (*.png)" ) );
file_dialog.setFileMode( QFileDialog::ExistingFile );
QStringList filenames;
if ( file_dialog.exec() == QDialog::Accepted )
{
filenames = file_dialog.selectedFiles();
}
else
return;
QPixmap pixmap;
pixmap.load( filenames.front() );
ui.label->setPixmap( pixmap );
}
其中QFileDialog需要include “QFileDialog”
詳細的用法就不多說了,請翻閱Qt小幫手(assistant)
一切順利的話,執行後按下「Open Image…」
就可以看到選擇影像檔案的對話框跑出來囉
選好影像檔案後開啟,會顯示在QLabel元件上,有沒有很簡單啊!
其實,在沒有VC add-in介入時,也能用同樣的方法來建立signal/slot之間的連結
只是缺少了「自動」編譯*.ui與建立moc的步驟,感覺就瑣碎了些
幸好,有VC add-in的幫忙,讓整個過程銜接得更順
雖然沒有像原生IDE那樣完整的環境
不過這還是讓VC使用者在使用Qt時,省下許多的時間與減少手動的不便
[註1] 在Qt中有許多元件是沒有「設計時期」的,必須經由寫程式的方式使用該元件
譬如QPushButton,可以讓使用者從元件盒中拖放到設計的視窗
並修改其屬性等等,這就是具有「設計時期」的元件
我倒是比較希望未來Qt也能加強這類僅有「執行時期」的元件
讓程式撰寫更加的簡化
為什麼會這樣想?都是因為曾經習慣了BCB,才會這樣懷念XD
[註2] 關於QPushButton的clicked()信號
在Qt 4.3.4版時(我用的上一版)並不需要bool這個引數
但是這一版(4.5.0)如果不使用含有bool引數的clicked()信號
會發生雖然可以連結signal/自訂的slot,但是卻無法觸發的怪異情形
而,若clicked()信號是連結到原有的slot上(如close()),卻又都正常
不曉得是自己這邊的問題還是怎麼回事,只好都先改用clicked(bool)信號了










写得很好哦..很有用
Comment 由 LeoOo | 六月 17, 2009