Qt第一章的最後一個內容是部件的布局。
書中的例子用到了一個QHBoxLayout類
這個類能夠將放置在布局內的控件自動調整大小和位置,我們不需要手動去調整,比較方便。
第10行:創建一個QWidget對象
QWidget是所有用戶界面對象的基類。在這裡將會用作其它部件的父對象,在這之上顯示相應的控件。也就是說它將作為程序的主窗口。
第11行:設置窗口標題
字面意思上看也的確是設置窗口的標題。
第13行:創建一個QSpinBox對象
用到的函數:QSpinBox::QSpinBox ( QWidget * parent = 0 )
函數的說明:構造一個微調框,默認最小值為0,最大值值為99,初始值為0。
第14行:創建一個QSlider對象
用到的函數:QSlider::QSlider ( Qt::Orientation orientation, QWidget * parent = 0 )
函數的說明:構造一個滑塊,並指定滑塊方向,Qt::Vertical為垂直方向,Qt::Horizontal為水平方向。
第15~16行:設置有效范圍
QSpinBox用到的函數:void QSpinBox::setRange ( intminimum, intmaximum )
QSlider用到的函數:void QAbstractSlider::setRange ( intmin, intmax )
函數的說明:設置微調框和滑塊的有效范圍,設置完成之後,在實際使用中是不會超過這個范圍的,微調框自己手動輸入一個非法值也不會被正常輸入,這也確保了數值的有效性。
第18~21行:設置信號和槽的連接
QSpinBox和QSlider都擁有一個valueChanged(int)信號,表明當數值發生改變時會發射valueChanged信號。
同時它們也都擁有一個setValue(int)槽。
將QSpinBox的valueChanged信號和QSlider的setValue槽連接之後,當QSpinBox的數值發生改變,QSlider的值也將隨之改變。
同理,就可以理解另外一個連接會發生的事情了。
另外,這裡可能有一個疑問:微調框的值發生改變,它會調用滑塊的setValue來設置滑塊的值,這樣一來滑塊的值也發生改變,滑塊也會調用微調框的setValue來設置微調框……如此反復,似乎感覺這樣子會出現死循環…?
也不知道是不是我初學的關系,不知道其它人會不會呢?我學到這裡的時候就有這個疑問了。後來書中也解釋過了,並不會出現這種死循環的局面。
所以,需要知道的是對象何時會發射信號,它是有條件的。微調框發射valueChanged信號的條件是:當數值已經改變。
假如數值改變了,它會發射信號,由滑塊響應並調用setValue槽來改變自身的值,這時它的值"改變了",但是這裡的改變只是"替換"成微調框新的值。
如果這個新的值與滑塊原本已有的值是一樣的,這就不叫改變了。所以滑塊的值保持原樣,並不符合數值已經改變這個條件,不會再次發射信號。
一個疑問就這樣解開了,它不會造成死循環。
第22行:設置QSpinBox的值
由於已經將信號和槽進行連接了,所以在連接之後進行設置值的話,就會發射信號,相應地會有槽在執行,把QSlider的值設置為和QSpinBox一樣的數值。
第24行:創建一個QHBoxLayout對象
用到的函數:QHBoxLayout::QHBoxLayout ()
函數的說明:創建一個水平布局管理器,管理各個控件位置和大小。
第25~26行:將部件添加到水平布局對象中
用到的函數:void QBoxLayout::addWidget ( QWidget * widget, intstretch = 0, Qt::Alignmentalignment = 0 )
函數的說明:將部件添加到布局中,並調整布局內各個控件的大小與位置。
第27行:在主窗口上設置布局管理器
用到的函數:void QWidget::setLayout ( QLayout * layout )
函數的說明:設置布局管理器為這個部件的布局。
最後自然就是將主窗口show()出來了
無論怎樣調整窗口的寬度,微調框和滑塊都會自動調整大小,的確是個很方便的東西。
接下來比較詳細講的就是布局管理器了:
布局管理器就是一個能夠對其所負責窗口部件的尺寸大小和位置進行設置的對象。
Qt中有三個主要的布局管理器類:
QHBoxLayout:在水平方向上排列窗口部件,從左到右。頭文件<QHBoxLayout>。
QVBoxLayout:在豎直方向上排列窗口部件,從上到下。頭文件<QVBoxLayout>。
QGridLayout:把各個窗口部件排列在一個網格中。頭文件<QGridLayout>。
QHBoxLayout,水平布局管理器,就是這樣子:
QVBoxLayout,豎直布局管理器,就是這樣子:
QGridLayout,網格布局管理器,就是這樣子:
用到的函數:void QGridLayout::addWidget ( QWidget * widget, introw, intcolumn, Qt::Alignmentalignment = 0 )
函數的說明:widget指定要添加到布局管理器的對象。row和column為對象放置的位置。
QGridLayout將各個部件都添加到網格中,就像是表格,可以指定部件放在表格的哪一行哪一列。這也是一樣的。
這三種布局管理器可以嵌套,可以做出一個很好看的布局。
結合C++的知識與之前所學過的Qt知識,我來隨便弄一個界面吧~
#include <QApplication> #include <QPushButton> #include <QLineEdit> #include <QSlider> #include <QSpinBox> #include <QLabel> #include <QLayout> // 包含了<QLayout>就可以不用再包含以下3個頭文件了 /* #include <QHBoxLayout> #include <QVBoxLayout> #include <QGridLayout> */ enum LAYOUT_TYPE { layout_H, // QHBoxLayout layout_V, // QVBoxLayout layout_G // QGridLayout }; QLayout * getLayout(LAYOUT_TYPE type); int main(int argc, char * argv[]) { QApplication app(argc, argv); QWidget * window = new QWidget; window->setWindowTitle("Hello Qt!"); /***************** 設置頂部菜單選項 ******************/ QHBoxLayout * Top = (QHBoxLayout *)getLayout(layout_H); QPushButton * btn_Menu1 = new QPushButton("Start"); QPushButton * btn_Menu2 = new QPushButton("Online"); QPushButton * btn_Menu3 = new QPushButton("Setting"); QPushButton * btn_Menu4 = new QPushButton("Exit"); Top->addWidget(btn_Menu1); Top->addWidget(btn_Menu2); Top->addWidget(btn_Menu3); Top->addWidget(btn_Menu4); /***************** 設置中部左邊部件 ******************/ QVBoxLayout * midLeft = (QVBoxLayout *)getLayout(layout_V); QHBoxLayout * midLeftLayout1 = (QHBoxLayout *)getLayout(layout_H); QLabel * tip1 = new QLabel("Sound Volume"); // 可以手動設置QSlider的方向,Horizontal是水平,Vertical是垂直 QSlider * slider1 = new QSlider(Qt::Horizontal); slider1->setRange(0, 100); slider1->setValue(50); midLeftLayout1->addWidget(tip1); midLeftLayout1->addWidget(slider1); QHBoxLayout * midLeftLayout2 = (QHBoxLayout *)getLayout(layout_H); QLabel * tip2 = new QLabel("Sound Effect "); QSlider * slider2 = new QSlider(Qt::Horizontal); slider2->setRange(0, 100); slider2->setValue(50); midLeftLayout2->addWidget(tip2); midLeftLayout2->addWidget(slider2); midLeft->addLayout(midLeftLayout1); midLeft->addLayout(midLeftLayout2); /***************** 設置中部右邊部件 ******************/ QVBoxLayout * midRight = (QVBoxLayout *)getLayout(layout_V); QHBoxLayout * midRightLayout1 = (QHBoxLayout *)getLayout(layout_H); QLabel * tip3 = new QLabel("Game Levels"); QSpinBox * spinBox = new QSpinBox(); spinBox->setRange(1, 10); spinBox->setValue(1); midRightLayout1->addWidget(tip3); midRightLayout1->addWidget(spinBox); QHBoxLayout * midRightLayout2 = (QHBoxLayout *)getLayout(layout_H); QLabel * tip4 = new QLabel("Player Name"); QLineEdit * Edit = new QLineEdit(); midRightLayout2->addWidget(tip4); midRightLayout2->addWidget(Edit); midRight->addLayout(midRightLayout1); midRight->addLayout(midRightLayout2); // 將中部左右邊的布局管理器添加到中部主布局管理器中 QHBoxLayout * Mid = (QHBoxLayout *)getLayout(layout_H); Mid->addLayout(midLeft); Mid->addLayout(midRight); /***************** 設置底部部件 ******************/ QHBoxLayout * Bottom = (QHBoxLayout *)getLayout(layout_H); QLabel * lab = new QLabel("All right reserved."); // addStretch()用於添加分隔符,用於占位 // 就是已有的部件大小已確定為最佳的情況下, // 添加分隔符可以將多余的空位占用掉,以免部件調整自身大小以占用所有空位 // 在lab的前後加上addStretch()可以使得lab居中哦~ Bottom->addStretch(); Bottom->addWidget(lab); Bottom->addStretch(); /***************** 設置主布局管理器 ******************/ QVBoxLayout * mainLayout = (QVBoxLayout *)getLayout(layout_V); mainLayout->addLayout(Top); mainLayout->addLayout(Mid); mainLayout->addLayout(Bottom); window->setLayout(mainLayout); window->show(); return app.exec(); } QLayout * getLayout(LAYOUT_TYPE type) { QLayout * Layout; switch (type) { case layout_H: Layout = new QHBoxLayout; break; case layout_V: Layout = new QVBoxLayout; break; case layout_G: Layout = new QGridLayout; break; } return Layout; }
好吧,就總結到這裡~