Qt - 佈局管理器
什麼是佈局管理器?你一個窗口裡面一般有很多widgets對吧,你如果要自己調它們的位置,大小的話會比較麻煩,而且當視窗變大的時候它裡面的widgets又不會跟著變大,就很煩惱。所以,我們有這個東西,佈局管理器,相當於一個小管家,你只要把widgets丟進去,他自己會幫你排好它的。
方法:
然後,我們建立 QBoxLayout 物件並將小部件新增到佈局中。
最後,我們呼叫 QWidget::setLayout() 將 QBoxLayout 物件安裝到小部件上。
此時,佈局中的小部件將重新設定父物件,為上面呼叫setLayout()的視窗。
1,盒子佈局(BoxLayout)
QBoxLayout可以在水平方向或垂直方向上排列控制元件,分別派生了QHBoxLayout、QVBoxLayout子類。
QHBoxLayout:水平佈局,在水平方向上排列控制元件,即:左右排列。 QVBoxLayout:垂直佈局,在垂直方向上排列控制元件,即:上下排列。
水平佈局、垂直佈局除了構造時的方向(LeftToRight、TopToBottom)不同外,其它均相同。
公有函式
序號 | 函式&描述 |
---|---|
1 | void addLayout(QLayout* layout,int stretch = 0) 將layout新增到框的末端,使用連續拉伸因子拉伸。 |
2 | void addSpacerItem(QSpacerItem * spacerItem) 將spaceeritem新增到該盒子佈局的末尾,通常不使用這個函式,請使用addSpacing(int size) |
3 | void addSpacing(int size) 新增一個大小為size的不可伸縮空間(QSpacerItem)到這個框佈局的末尾 |
4 | void addStretch(int stretch = 0) 新增一個可伸縮空間(一個QSpacerItem),最小尺寸為零,拉伸因子stretch到這個框佈局的末尾。 |
5 | void addStrut(int size) 限制盒子的垂直尺寸最小為size |
6 | void addWidget(QWidget* widget,int stretch = 0,Qt::Alignment alignment = 0) 將小部件新增到此框佈局的末尾,並使用拉伸因子拉伸和對齊對齊。 |
7 | void setDirection(QBoxLayout::Direction direction) 設定此佈局的方向為direction。 |
8 | void setSpacing(int spacing) 設定小部件之間的間距 |
9 | void setStretch(int index,int stretch) 給index位置的控制元件設定拉伸因子stretch |
10 | bool setStretchFactor(QWidget* widget,int stretch) bool setStretchFactor(QWidget* widget,int stretch) 設定小部件的拉伸因子,如果在佈局中發現小部件(不包括子佈局),則返回true; 否則返回false。 |
下面我們以QHBoxLayout為例,來講解QBoxLayout的常用功能。
-
簡單佈局
//建立需要佈局的小部件
QLabel* nameLabel = new QLabel("name");
QLineEdit* nameEdit = new QLineEdit;
//建立佈局
QBoxLayout* hlayout = new QBoxLayout(QBoxLayout::Direction::LeftToRight);
//把小部件新增到佈局
hlayout->addWidget(nameLabel);
hlayout->addWidget(nameEdit);
//給當前視窗設定佈局
this->setLayout(hlayout);
-
佈局巢狀
//姓名
QLabel* nameLabel = new QLabel("Name");
QLineEdit* nameEdit = new QLineEdit;
QBoxLayout* nameHlayout = new QBoxLayout(QBoxLayout::Direction::LeftToRight);
nameHlayout->addWidget(nameLabel);
nameHlayout->addWidget(nameEdit);
//電話
QLabel* phoneLabel = new QLabel("Phone");
QLineEdit* phoneEdit = new QLineEdit;
QBoxLayout* phoneHlayout = new QBoxLayout(QBoxLayout::Direction::LeftToRight);
phoneHlayout->addWidget(phoneLabel);
phoneHlayout->addWidget(phoneEdit);
//佈局巢狀
QBoxLayout* mainlayout = new QBoxLayout(QBoxLayout::Direction::TopToBottom);
mainlayout->addLayout(nameHlayout);
mainlayout->addLayout(phoneHlayout);
this->setLayout(mainlayout);
基本使用
-
建立五個按鈕,新增到水平佈局
QPushButton *btn1 = new QPushButton("One");
QPushButton *btn2 = new QPushButton("Two");
QPushButton *btn3 = new QPushButton("Three");
QPushButton *btn4 = new QPushButton("Four");
QPushButton *btn5 = new QPushButton("Five");
QHBoxLayout* hlayout = new QHBoxLayout;
hlayout->addWidget(btn1);
hlayout->addWidget(btn2);
hlayout->addWidget(btn3);
hlayout->addWidget(btn4);
hlayout->addWidget(btn5);
this->setLayout(hlayout);
-
設定邊距
void setMargin(int margin);
void setContentsMargins(int left,int top,int right,int bottom);
這裡我使用setMargin(0)將外邊距設定為0。
-
設定間距
void setSpacing(int spacing)
-
新增拉伸空間(QSpacerItem)
QHBoxLayout* hlayout = new QHBoxLayout;
hlayout->addStretch(); //新增拉伸空間
hlayout->addWidget(btn1);
...
在第一個控制元件之前新增伸縮,這樣所有的控制元件就會居右顯示。
在最後一個控制元件之後新增伸縮,這樣所有的控制元件就會居左顯示。
在第一個控制元件之前,最後一個空間之後新增伸縮,這樣所有的控制元件就會居中顯示。
-
新增控制元件addWidget
void addWidget(QWidget *widget, int stretch = 0, Qt::Alignment alignment = 0)
預設是居中對齊的,我們把其中一個按鈕的高度設定大一點,就可以看到非常明顯了~
下面,我們使用向上、向下對齊來設定其它控制元件。
QHBoxLayout* hlayout = new QHBoxLayout;
hlayout->addStretch(); //新增拉伸空間
hlayout->addWidget(btn1,0,Qt::AlignmentFlag::AlignTop);
hlayout->addWidget(btn2,0,Qt::AlignmentFlag::AlignTop);
hlayout->addWidget(btn3,0);
hlayout->addWidget(btn4,0,Qt::AlignmentFlag::AlignBottom);
hlayout->addWidget(btn5,0,Qt::AlignmentFlag::AlignBottom);
-
設定佈局方向
void setDirection(QBoxLayout::Direction direction)
//可以設定從左到右、從右到左、從上到下、從下到上等。。。
setDirection(QBoxLayout::RightToLeft)
setDirection(QBoxLayout::TopToBottom);
既然使用了QHBoxLayout,一般就不建議使用TopToBottom或者BottomToTop,如果實在確定不了方向,或者方向可以隨意變化,那麼建議使用QBoxLayout。
設定拉伸係數
當窗體大小變化時,控制元件會根據拉伸係數來做相應的調整。
//設定小部件的拉伸因子,如果在佈局中發現小部件(不包括子佈局),則返回true; 否則返回false。
bool setStretchFactor(QWidget *widget, int stretch)
bool setStretchFactor(QLayout *layout, int stretch)
hlayout->setStretchFactor(btn2,1);
hlayout->setStretchFactor(btn3,2);
設定btn2的拉伸係數為1,btn3拉伸係數為2,當窗體變大時,會優先將btn3進行拉伸,當達到一定程度時,再拉伸btn2,btn2與btn3的寬度比例為1:2。
2,網格佈局(GridLayout)
網格佈局也叫格柵佈局(多行多列)
QGridLayout佔用它可用的空間(通過它的父佈局或parentWidget()),將它分成行和列,並將它管理的每個小部件放入正確的單元格中。
列和行表現相同; 我們將討論列,但行也有等價的函式。
每一列都有一個最小寬度和一個拉伸因子。 最小寬度是使用setColumnMinimumWidth()設定的最大寬度和該列中每個小部件的最小寬度。 拉伸因子使用setColumnStretch()設定,並確定列將獲得的可用空間超過或超過必要的最小空間的多少。
公有函式
序號 | 函式&描述 |
---|---|
2 | void addLayout(QLayout *layout, int row, int column, Qt::Alignment alignment = 0) void addLayout(QLayout *layout, int row, int column, int rowSpan, int columnSpan, Qt::Alignment alignment = 0) 將layout放置在網格中的位置(row、column)。 左上角的位置是(0,0)。 跨越多行/多列。 該單元格將從跨rowSpan行和columnSpan列的行、列開始。 |
3 | void addWidget(QWidget *widget, int row, int column, Qt::Alignment alignment = 0) void addWidget(QWidget *widget, int fromRow, int fromColumn, int rowSpan, int columnSpan, Qt::Alignment alignment = 0) 同上 |
4 | void setRowStretch(int row, int stretch) 將row的拉伸因子設定為stretch |
5 | void setColumnStretch(int column, int stretch) 將column的拉伸因子設定為stretch |
6 | voidsetRowMinimumHeight(int row, int minSize) 將行的最小寬度設定為minSize畫素。 |
7 | voidsetColumnMinimumWidth(int column, int minSize) 將列的最小寬度設定為minSize畫素。 |
QLabel* imageLabel = new QLabel;
QLineEdit* userNamaeEdit = new QLineEdit;
QLineEdit* passwdEdit = new QLineEdit;
QCheckBox* rememberCheckBox = new QCheckBox;
QCheckBox* autoLoginCheckBox = new QCheckBox;
QPushButton* registerBtn = new QPushButton;
QPushButton* forgetBtn = new QPushButton;
QPushButton* loginBtn = new QPushButton;
//設定圖片
imageLabel->setFixedSize(90,90);
imageLabel->setPixmap(QPixmap("://images/loginIcon.png"));
imageLabel->setScaledContents(true);
//設定輸入框
userNamaeEdit->setPlaceholderText("QQ號碼/手機/郵箱");
passwdEdit->setPlaceholderText("密碼");
//設定複選框
rememberCheckBox->setText("記住密碼");
autoLoginCheckBox->setText("自動登入");
//設定按鈕
registerBtn->setText("註冊賬號");
forgetBtn->setText("找回密碼");
loginBtn->setText("登入");
QGridLayout* layout = new QGridLayout;
layout->addWidget(imageLabel,0,0,3,1);
layout->addWidget(userNamaeEdit,0,1,1,2);
layout->addWidget(registerBtn,0,3);
layout->addWidget(passwdEdit,1,1,1,2);
layout->addWidget(forgetBtn,1,3);
layout->addWidget(rememberCheckBox,2,1);
layout->addWidget(autoLoginCheckBox,2,2);
layout->addWidget(loginBtn,3,1,1,2);
layout->setHorizontalSpacing(10);
layout->setVerticalSpacing(10);
layout->setContentsMargins(20,20,20,20);
this->setLayout(layout);
3,表單佈局(FormLayout)
QFormLayout類管理輸入小部件的表單及其關聯的標籤
QFormLayout 是一個方便的佈局類,它以兩列形式佈置其子項。 左列由標籤組成,右列由“欄位”小部件(行編輯器、旋轉框等)組成。 傳統上,這種兩列表單佈局是使用 QGridLayout 實現的。
QFormLayout 是一種更高級別的替代方案,具有以下優點:
-
遵守不同平臺的外觀和感覺準則 例如,macOS Aqua 和 KDE 指南指定標籤應該右對齊,而 Windows 和 GNOME 應用程式通常使用左對齊。
-
支援長行換行
對於顯示較小的裝置,QFormLayout可以設定為對長行進行換行,甚至對所有行進行換行。
-
建立標籤-欄位對,有非常方便的API 我們可以通過addRow(const QString &labelText, QWidget *field)來建立一個帶有給定文字的QLabel及QWidget控制元件行,它們可以自動的設定為夥伴關係。
公有函式
序號 | 函式&描述 |
---|---|
1 | void addRow(QWidget* label,QWidget* field) void addRow(QWidget* label,QLayout* field) 使用給定的label和field在此表單佈局的底部新增新行 |
2 | void addRow(const QString &labelText, QWidget* field) void addRow(const QString &labelText, QLayout* field) 這個過載會在後臺自動建立一個以labelText作為文字的QLabel。 field被設定為新的QLabel的夥伴 |
3 | void addRow(QWidget *widget) void addRow(QLayout* layout) 在表單佈局的末尾新增指定的小部件。 這個小部件橫跨兩列 |
9 | void setRowWrapPolicy(QFormLayout::RowWrapPolicy policy) true |
10 | void setSpacing(int spacing) 將垂直和水平間距設定為spacing。 |
11 | void setVerticalSpacing(int spacing) 將垂直間距設定為spacing |
12 | void setWidget(int row, QFormLayout::ItemRole role, QWidget *widget) 將給定的row中的role設定為widget,必要時使用空行擴展布局。 如果單元格已被佔用,則不插入小部件,並將錯誤訊息傳送到控制檯。 |
QLineEdit* userEdit = new QLineEdit;
QLineEdit* passwdEdit = new QLineEdit;
QPushButton* loginBtn = new QPushButton("確定");
QFormLayout* fromLayout = new QFormLayout;
fromLayout->addRow("userName:",userEdit);
fromLayout->addRow("password:",passwdEdit);
fromLayout->addWidget(loginBtn);
this->setLayout(fromLayout);
將其與下面使用QGridLayout編寫的程式碼進行比較:
QLineEdit* userEdit = new QLineEdit;
QLineEdit* passwdEdit = new QLineEdit;
QPushButton* loginBtn = new QPushButton("確定");
QLabel*userLabel = new QLabel("userName:");
QLabel*passwdLabel = new QLabel("passwdEdit:");
QGridLayout* glayout = new QGridLayout;
glayout->addWidget(userLabel,0,0);
glayout->addWidget(userEdit,0,1);
glayout->addWidget(passwdLabel,1,0);
glayout->addWidget(passwdEdit,1,1);
glayout->addWidget(loginBtn,2,1);
this->setLayout(glayout);
-
設定換行策略
void setRowWrapPolicy(QFormLayout::RowWrapPolicy policy)
列舉 描述 效果 QFormLayout::DontWrapRows 欄位總是放在它們的標籤旁邊(預設樣式) QFormLayout::WrapLongRows 標籤有足夠的空間適應,如果欄位對的最小大小大於可用空間,輸入框會被換到下一行 QFormLayout::WrapAllRows 欄位總是在它們的標籤下面。 -
設定控制元件
void setWidget(int row, QFormLayout::ItemRole role, QWidget *widget)
-
將給定角色的給定行中的小部件設定為widget,必要時使用空行擴展布局。
-
內容 | 值 | 描述 |
---|---|---|
QFormLayout::LabelRole | 0 | 標籤 |
QFormLayout::FieldRole | 1 | 欄位 |
QFormLayout::SpanningRole | 2 | 跨標籤和欄位列的小部件 |
QFormLayout * flayout = new QFormLayout;
flayout->setWidget(0,QFormLayout::ItemRole::LabelRole,new QLabel("LabelRole"));
flayout->setWidget(0,QFormLayout::ItemRole::FieldRole,new QLineEdit("FieldRole"));
flayout->setWidget(1,QFormLayout::ItemRole::SpanningRole,new QPushButton("SpanningRole"));
this->setLayout(flayout);
4,堆疊佈局(StackedLayout)
QStackedLayout繼承自QLayout。
QStackedLayout類提供了多頁面切換的佈局,一次只能看到一個介面。
QStackedLayout可用於建立類似於QTabWidget提供的使用者介面。也有建立在QStackedLayout之上的便利類QStackedWidget
sngnals
//每當佈局中的當前小部件發生變化時,都會發出此訊號。 index指定新的當前小部件的索引,如果沒有新的小部件,則-1
void currentChanged(int index)
//每當從佈局中刪除小部件時,都會發出此訊號,inded是刪除的索引。
void widgetRemoved(int index)
slots
void setCurrentIndex(int index)
void setCurrentWidget(QWidget *widget)
公有函式
序號 | 函式&描述 |
---|---|
2 | int addWidget(QWidget *widget) 把widget新增到佈局中 |
5 | int insertWidget(int index, QWidget *widget) 把widget插入到指定的下標 |
6 | void setStackingMode(QStackedLayout::StackingMode stackingMode) 設定子小部件可見性的處理方式。 |
5,分割器(Splitter)
QSplitter類實現了一個分離小部件。 splitter允許使用者通過拖動子部件之間的邊界來控制它們的大小。 任何數量的小部件都可以由單個拆分器控制。QSplitter的典型用法是建立幾個小部件並使用 insertWidget()或addWidget()新增它們。
QSplitter *splitter = new QSplitter(this);
splitter->addWidget(new QTextBrowser);
splitter->addWidget(new QTextBrowser);
splitter->addWidget(new QTextBrowser);
splitter->setHandleWidth(2);
splitter->setCollapsible(0,false);
QSplitter *sp = new QSplitter(Qt::Orientation::Vertical,splitter);
sp->addWidget(new QTextBrowser);
sp->addWidget(new QTextBrowser);
搜尋
複製