初步學習Qt布局


布局管理

以下是Qt手冊中的《布局管理》的譯文

在一個Widget中,Qt布局管理系統提供了一個簡單而有效的方式來自動組織子widget,以保證他們能夠很好地利用可用空間。

介紹

Qt包含一個布局管理類的集合,它們被用來描述widgets如何在應用程序的用戶界面中呈現的。當可用空間發生變化時,這些布局將自動調整widgets的位置和大小,以確保它們布局的一致性和用戶界面主體可用。

所有QWidget的子類都可以用布局來管理它們的子類。QWidget::setLayout()函數給widget提供一個布局。當布局通過這種方式設置到widget,它將負責以下任務:

l 子widget的定位

l 窗口的合理默認空間

l 窗口的合理最小空間

l 調整大小處理

l 當內容發生變化時自動調整

n 字體、大小或者內容變化

n 顯示或 隱藏widget

n 移除子widget

Qt的布局類

QGraphicsAnchorLayout

Layout where one can anchor widgets together in Graphics View

在制圖視圖中布局widget

QGraphicsAnchor

Represents an anchor between two items in a QGraphicsAnchorLayout

QBoxLayout

Lines up child widgets horizontally or vertically

水平或垂直整理子widget

QHBoxLayout

Lines up widgets horizontally

水平整理子控件

QVBoxLayout

Lines up widgets vertically

垂直整理子控件

QFormLayout

Manages forms of input widgets and their associated labels

label-inputwidget模式表單布局

QGridLayout

Lays out widgets in a grid

網格布局

QLayout

The base class of geometry managers

布局,幾何管理的基類

QLayoutItem

Abstract item that a QLayout manipulates

管理的抽象元素

QSpacerItem

Blank space in a layout

空白區域布局

QWidgetItem

Layout item that represents a widget

布局元素

QSizePolicy

Layout attribute describing horizontal and vertical resizing policy

大小策略

QStackedLayout

Stack of widgets where only one widget is visible at a time

棧模式布局,一次只顯示一個

QButtonGroup

Container to organize groups of button widgets

管理按鈕的容器

QGroupBox

Group box frame with a title

帶標題的組箱框架

QStackedWidget

Stack of widgets where only one widget is visible at a time

棧模式的widget,一次只顯示一個

水平、垂直、網格和表格布局

給widgets一個很好布局的最好方式是使用內置的布局管理器: QHBoxLayout, QVBoxLayout, QGridLayout, and QFormLayout. 這些類都從QLayout繼承而來,它們都來源於QObject(而不是QWidget)。創建更加復雜的布局,可以讓它們彼此嵌套完成。

l QHBoxLayout是水平布局,將從左往右(or right to left for right-to-left languages )widget布局成水平行

clip_image002

l QVBoxLayout是垂直布局,從頂部到底部

clip_image004

l QGridLayout 是二位的網格布局。它可以容納多個單元格:

clip_image006

l QFormLayout是兩列label-field式的表單布局

clip_image008

代碼舉例

下面代碼創建QHBoxLayout來管理5個QPushButtons的幾何圖形:

QWidget *window = new QWidget;

QPushButton *button1 = new QPushButton("One");

QPushButton *button2 = new QPushButton("Two");

QPushButton *button3 = new QPushButton("Three");

QPushButton *button4 = new QPushButton("Four");

QPushButton *button5 = new QPushButton("Five");

QHBoxLayout *layout = new QHBoxLayout;

layout->addWidget(button1);

layout->addWidget(button2);

layout->addWidget(button3);

layout->addWidget(button4);

layout->addWidget(button5);

window->setLayout(layout);

window->show();

QGridLayout示例如下:

    QWidget *window = new QWidget;
    QPushButton *button1 = new QPushButton("One");
    QPushButton *button2 = new QPushButton("Two");
    QPushButton *button3 = new QPushButton("Three");
    QPushButton *button4 = new QPushButton("Four");
    QPushButton *button5 = new QPushButton("Five");
 
    QGridLayout *layout = new QGridLayout;
    layout->addWidget(button1, 0, 0);
    layout->addWidget(button2, 0, 1);
    layout->addWidget(button3, 1, 0, 1, 2);
    layout->addWidget(button4, 2, 0);
    layout->addWidget(button5, 2, 1);
 
    window->setLayout(layout);
    window->show();

QFormLayout示例如下:

    QWidget *window = new QWidget;
    QPushButton *button1 = new QPushButton("One");
    QLineEdit *lineEdit1 = new QLineEdit();
    QPushButton *button2 = new QPushButton("Two");
    QLineEdit *lineEdit2 = new QLineEdit();
    QPushButton *button3 = new QPushButton("Three");
    QLineEdit *lineEdit3 = new QLineEdit();
 
    QFormLayout *layout = new QFormLayout;
    layout->addRow(button1, lineEdit1);
    layout->addRow(button2, lineEdit2);
    layout->addRow(button3, lineEdit3);
 
    window->setLayout(layout);
    window->show();
布局技巧

當使用布局的時候,在創建子widget時,沒必要給它傳遞父類。布局會自動重新定義它們的父類(通過QWidget::setParent())以確保它們是裝載布局的widget的子類。

注意1布局中的控件是裝載布局控件的子控件,不是布局的子控件。控件只能以其他控件作為父類,不可以以布局作為父類。在布局上,可以使用addLayout來嵌套布局;被嵌套的布局,將變成上層布局的子布局。

向布局添加widgets

添加布局到widgets時,布局過程執行如下:

1. 所有widgets將根據它們的 QWidget::sizePolicy() and QWidget::sizeHint()首先分配一些空間。

2. 如果有widgets設置了大於0的拉伸系數,接下來它們將按照拉伸系數的比例來分配空間。

3. 如果有widgets設置的拉伸系數是0,它將在沒有其他widgets需要空間時獲取更多空間。其中,帶Expanding大小策略的widget將首先獲得空間。

4. 所有分配了小於最小空間(或者設置了最小的size hint)的widget將按要求分配最小空間。(在拉伸系數成為決定因子時,widgets沒必要再用最小值或者最小hint)。

5. 任何分配了大於最大空間的widget將按要求分配最大空間。(拉伸系數起着決定作用)

拉伸系數

通常,widgets創建的時候沒有設置拉伸系數。當widget整理到一個布局中時,它們將根據QWidget::sizePolicy()或者最小大小hint(取決於誰更大)分配一定空間。拉伸系數被用於按比例改變widget的分配空間。

如果3個widget用QHBoxLayout 來布局,不帶拉伸系數,它們將得到像下面的布局:

clip_image010

如果帶上拉伸系數,情況將變成這樣:

clip_image012

自定義widget的布局

當編寫自定義widget類時,需要顯示提供它的布局屬性。如果widget有Qt自帶的布局,它能夠自己滿足自己。如果沒有任何子布局,或者使用手動布局,可以通過下面的機制來改變widget的行為:

l 實現QWidget::sizeHint() 來返回首先大小

l 實現QWidget::minimumSizeHint()來返回widget可以擁有的最小空間

l 調用QWidget::setSizePolicy來描述widget所需的空間

當size hint、minimum size或size policy改變時,調用QWidget::updateGeometry()。這將促使布局重新進行計算。連續多次調用QWidget::updateGeometry()只會發生一次布局重新計算。

即便實現了QWidget::heightForWidth(),也有必要提供合理的sizeHint()。

進一步了解,參見:Trading Height for Width.

布局問題

The use of rich text in a label widget can introduce some problems to the layout of its parent widget. Problems occur due to the way rich text is handled by Qt's layout managers when the label is word wrapped.

In certain cases the parent layout is put into QLayout::FreeResize mode, meaning that it will not adapt the layout of its contents to fit inside small sized windows, or even prevent the user from making the window too small to be usable. This can be overcome by subclassing the problematic widgets, and implementing suitable sizeHint() andminimumSizeHint() functions.

In some cases, it is relevant when a layout is added to a widget. When you set the widget of a QDockWidget or a QScrollArea (with QDockWidget::setWidget() andQScrollArea::setWidget()), the layout must already have been set on the widget. If not, the widget will not be visible.

在QLabel中使用富文本會給布局的父類widget帶來一些問題。問題發生的原因是因為當label被文字環繞時,富文本被Qt的布局管理器控制。

在某些情況下,父類布局被放入QLayout::FreeResize模式,這意味着它將不適應內容布局所設置的最小窗口,或者甚至阻止用戶讓窗口小到不可用的情況。這個可以通過將問題控件作為子類來解決,並實現合適的sizeHint()minimumSizeHint()函數。

在一些情況下,當布局被添加到widget時需要特別注意。當設置QDockWidget or a QScrollArea widget時(用QDockWidget::setWidget() andQScrollArea::setWidget()),布局必須已經被設置到widget上。否則,這些widget將不可見。

手動布局

如果想自定義一個獨特的布局,可以按 如上所述地自定義一個widget。實現QWidget::resizeEvent()來計算所需的大小分配並在每個子類中調用setGeometry()

需要布局需要重新計算大小時,widget將提供一個事件接口QEvent::LayoutRequest 。實現QWidget::event()來接收QEvent::LayoutRequest事件。

自定義布局管理

自定義布局的唯一方法是繼承QLayout來完成自己布局管理器。Border LayoutFlow Layout 例子將說明如何來完成。

下面將舉個例子來說明。CardLayout 類,受同名java布局管理的啟發。它分層管理每個元素,每個元素的通過QLayout::spacing()來設置位移量。

編寫自定義布局類,必須定義以下內容:

l 由布局控制的存放元素的數據結構。每個元素都是一個QLayoutItem。在這個例子中,我們將使用QList

l addItem(),描述如何添加元素到布局。

l setGeometry(),描述如何完成布局

l sizeHint(),布局的首選大小

l itemAt(),描述如何遞歸布局

l takeAt(),描述如何移除布局中的元素。

在大多數情況下,還需要實現minimumSize()

頭文件

card.h

#ifndef CARD_H
#define CARD_H
 
#include <QtGui>
#include <QList>
 
class CardLayout : public QLayout
{
public:
    CardLayout(QWidget *parent, int dist): QLayout(parent, 0, dist) {}
    CardLayout(QLayout *parent, int dist): QLayout(parent, dist) {}
    CardLayout(int dist): QLayout(dist) {}
    ~CardLayout();
 
    void addItem(QLayoutItem *item);
    QSize sizeHint() const;
    QSize minimumSize() const;
    int count() const;
    QLayoutItem *itemAt(int) const;
    QLayoutItem *takeAt(int);
    void setGeometry(const QRect &rect);
 
private:
    QList<QLayoutItem*> list;
};
#endif
實現文件

card.cpp

#include "card.h"
int CardLayout::count() const
{
        // QList::size() returns the number of QLayoutItems in the list
    return list.size();
}
 
int CardLayout::count() const
{
        // QList::size() returns the number of QLayoutItems in the list
    return list.size();
}
 
int CardLayout::count() const
{
        // QList::size() returns the number of QLayoutItems in the list
    return list.size();
}
 
CardLayout::~CardLayout()
{
     QLayoutItem *item;
     while ((item = takeAt(0)))
         delete item;
}
 
void CardLayout::setGeometry(const QRect &r)
{
    QLayout::setGeometry(r);
 
    if (list.size() == 0)
        return;
 
    int w = r.width() - (list.count() - 1) * spacing();
    int h = r.height() - (list.count() - 1) * spacing();
    int i = 0;
    while (i < list.size()) {
        QLayoutItem *o = list.at(i);
        QRect geom(r.x() + i * spacing(), r.y() + i * spacing(), w, h);
        o->setGeometry(geom);
        ++i;
    }
}
QSize CardLayout::sizeHint() const
{
    QSize s(0,0);
    int n = list.count();
    if (n > 0)
        s = QSize(100,70); //start with a nice default size
    int i = 0;
    while (i < n) {
        QLayoutItem *o = list.at(i);
        s = s.expandedTo(o->sizeHint());
        ++i;
    }
    return s + n*QSize(spacing(), spacing());
}
 
QSize CardLayout::minimumSize() const
{
    QSize s(0,0);
    int n = list.count();
    int i = 0;
    while (i < n) {
        QLayoutItem *o = list.at(i);
        s = s.expandedTo(o->minimumSize());
        ++i;
    }
    return s + n*QSize(spacing(), spacing());
}
 
進一步說明

自定義布局沒有控制寬和高。

忽略了 QLayoutItem::isEmpty(),這意味着布局將把隱藏widget作為可見的。

對於復雜布局,通過緩存計算將大大提高速度。在那種情況下,實現QLayoutItem::invalidate() 來標記數據是臟數據。

調用QLayoutItem::sizeHint()等的代價比較大。在通過函數中,需要再次使用,最好將結果保存在本地變量中。

在同樣函數的同一個元素中,不應該調用兩次 QLayoutItem::setGeometry()。 這個調用將耗費巨大,如果它用幾個子widget,因為布局管理器每次都要做一個完整的布局。替代方法:先計算geometry,然后再設置(這種事情,不僅應該在布局時注意,在實現resizeEvent()時也需要按同樣方法來做)。

參考

1. Qt手冊《Layout Management》

窗體小部件和布局

窗體小部件

窗體小部件(Widgets)是Qt中創建用戶界面的主要元素。窗體小部件可以顯示數據和狀態信息,接受用戶輸入,和提供組織其他窗體小部件的容器。

沒有嵌入到父級窗體小部件的部件被稱為窗口(window)。

布局

布局是一個種高雅而靈活的方式來自動把子類窗體小部件組織到它們的容器中。每個窗體小部件通過sizeHint和sizePolicy屬性向布局提供大小需求,布局根據可用空間進行分配。

窗體小部件的樣式

樣式(styles)繪制窗體小部件,並封裝了GUI的外觀和感覺。Qt的內置窗體小部件使用QStyle類完成幾乎所有的繪制工作,以確保它們看來確實是一致的、本地窗體小部件。

QSS(Qt Style Sheets)允許自定義窗體小部件的外觀。

窗體小部件的類

Qt Widget Gallery

基礎部件

QCheckBox

Checkbox with a text label

QComboBox

Combined button and popup list

QCommandLinkButton

Vista style command link button

QDateEdit

Widget for editing dates based on the QDateTimeEdit widget

QDateTimeEdit

Widget for editing dates and times

QDial

Rounded range control (like a speedometer or potentiometer)

QDoubleSpinBox

Spin box widget that takes doubles

QFocusFrame

Focus frame which can be outside of a widget's normal paintable area

QFontComboBox

Combobox that lets the user select a font family

QLCDNumber

Displays a number with LCD-like digits

QLabel

Text or image display

QLineEdit

One-line text editor

QMenu

Menu widget for use in menu bars, context menus, and other popup menus

QProgressBar

Horizontal or vertical progress bar

QPushButton

Command button

QRadioButton

Radio button with a text label

QScrollArea

Scrolling view onto another widget

QScrollBar

Vertical or horizontal scroll bar

QSizeGrip

Resize handle for resizing top-level windows

QSlider

Vertical or horizontal slider

QSpinBox

Spin box widget

QTabBar

Tab bar, e.g. for use in tabbed dialogs

QTabWidget

Stack of tabbed widgets

QTimeEdit

Widget for editing times based on the QDateTimeEdit widget

QToolBox

Column of tabbed widget items

QToolButton

Quick-access button to commands or options, usually used inside a QToolBar

QWidget

The base class of all user interface objects

高級部件

QCalendarWidget

Monthly based calendar widget allowing the user to select a date

QColumnView

Model/view implementation of a column view

QDataWidgetMapper

Mapping between a section of a data model to widgets

QDesktopWidget

Access to screen information on multi-head systems

QListView

List or icon view onto a model

QMacCocoaViewContainer

Widget for Mac OS X that can be used to wrap arbitrary Cocoa views (i.e., NSView subclasses) and insert them into Qt hierarchies

QMacNativeWidget

Widget for Mac OS X that provides a way to put Qt widgets into Carbon or Cocoa hierarchies depending on how Qt was configured

QTableView

Default model/view implementation of a table view

QTreeView

Default model/view implementation of a tree view

QUndoView

Displays the contents of a QUndoStack

QWSEmbedWidget

Enables embedded top-level widgets in Qt for Embedded Linux

QWebView

Widget that is used to view and edit web documents

QX11EmbedContainer

XEmbed container widget

QX11EmbedWidget

XEmbed client widget

Phonon::VideoWidget

Widget that is used to display video

組織者部件

QButtonGroup

Container to organize groups of button widgets

QGroupBox

Group box frame with a title

QSplitter

Implements a splitter widget

QSplitterHandle

Handle functionality of the splitter

QStackedWidget

Stack of widgets where only one widget is visible at a time

QTabWidget

Stack of tabbed widgets

抽象部件類

QAbstractButton

The abstract base class of button widgets, providing functionality common to buttons

QAbstractScrollArea

Scrolling area with on-demand scroll bars

QAbstractSlider

Integer value within a range

QAbstractSpinBox

Spinbox and a line edit to display values

QDialog

The base class of dialog windows

QFrame

The base class of widgets that can have a frame

參考

Widgets and Layouts  4.8


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM