PyQt5桌面應用系列
- PyQt5桌面應用開發(fā)(1):需求分析
- PyQt5桌面應用開發(fā)(2):事件循環(huán)
- PyQt5桌面應用開發(fā)(3):并行設計
- PyQt5桌面應用開發(fā)(4):界面設計
- PyQt5桌面應用開發(fā)(5):對話框
- PyQt5桌面應用開發(fā)(6):文件對話框
- PyQt5桌面應用開發(fā)(7):文本編輯+語法高亮與行號
- PyQt5桌面應用開發(fā)(8):從QInputDialog轉(zhuǎn)進到函數(shù)參數(shù)傳遞
- PyQt5桌面應用開發(fā)(9):經(jīng)典布局QMainWindow
- PyQt5桌面應用開發(fā)(10):界面布局基本支持
- PyQt5桌面應用開發(fā)(11):摸魚也要講基本法,兩個字,16
布局
布局是設計報表和交互中的重要工作。但是布局的內(nèi)涵有兩個層面上的:總體布局和界面布局。
從報表設計的角度出發(fā),布局應該把最重要的信息顯示在最顯眼的位置,把次要的信息放在次顯眼的位置,把不重要的信息放在不顯眼的位置。報表設計始終還是要圍繞報表的目的(也就是用戶利用數(shù)據(jù)、信息進行決策的目的)來進行的。圍繞一個決策來布局信息的分類、匯總、分析、比較、評價、預測等功能,這些功能的實現(xiàn)都是為了幫助用戶做出決策。
從交互設計的角度出發(fā),應該把核心、重要的功能放在最顯眼的位置,把次要的功能放在次顯眼的位置,把不重要的功能放在不顯眼的位置,這與報表設計相同;此外,還應該把相互關(guān)聯(lián)的操作放在一起,把相互獨立的功能分開。
這個在實際的設計中,可以通過分組、分頁、分欄、分區(qū)等方式來實現(xiàn)報表信息和交互的總體布局。
而在較低的一個層次上,則是一個具體的界面上的控件如何定位、縮放、對齊,控件上相關(guān)的控件之間如何相互協(xié)調(diào)。這個層次上的布局,可以通過控件的定位位置、幾何尺寸來描述。最基礎的布局就是控件的位置和尺寸,這也叫絕對位置布局。在這個基礎上,還能實現(xiàn)相對位置布局,通過以某個控件的位置和尺寸為基準,把其它控件的位置和尺寸轉(zhuǎn)換相對坐標系來描述。這都是直接和更底層的布局算法,當然所有的更抽象的布局都會歸結(jié)成相對布局算法和絕對布局算法。
- 抽象布局
- 相對布局
- 絕對布局
而抽象布局是在人類認知的概念中對一組控件的排列進行抽象的描述,比如一列、一行、一個網(wǎng)格、一個表格、一個樹形結(jié)構(gòu),等等。抽象的層次較高的界面布局,就更加便于人類使用,為思考布局提供了工具,但是也限制了布局的靈活性;較低層次的布局,需要更多的精力來思考,但是也提供了更強大的功能和靈活性。
大部分的UI開發(fā)工具包,都提供了一定層次的抽象布局工具。例如JavaFX、Qt、Web前端工具中都有類似的概念和工具支持。Qt5提供的布局工具并不豐富,但是也足夠形成復雜的界面。
利器
Qt5提供布局的方式是每一個QWidget都有一個QLayout對象,通過setLayout方法來設置。QWidget的子節(jié)點,通過加入布局類中來獲得自動計算相對位置、大小和絕對位置大小的能力。Qt5中最常用的布局類有四個:QHBoxLayout、QVBoxLayout、QGridLayout、QFormLayout。
其中QHBoxLayout和QVBoxLayout是QBoxLayout的子類,這三個類描述的就是一行或者一列控件。當控件排成一列時,其x方向的位置和尺寸都保持一致,y方向的位置成線性增長,尺寸通過按比例伸縮、固定最小尺寸、固定最大尺寸、擴張、最小化等概念來計算。最后這個部分通常稱為sizePolicy,也就是伸縮策略。同樣,當控件拍成一行時,其y方向的位置和尺寸都保持一致,x方向的位置成線性增長,尺寸通過按比例伸縮、固定最小尺寸、固定最大尺寸、擴張、最小化等概念來計算。
QGridLayout是QLayout的子類,它描述的是一個網(wǎng)格布局,也就是一個二維的布局。它的每一個子控件都有一個行號和列號,通過這兩個號碼來描述控件的位置。每一個行和列都有一個伸縮策略,通過這個策略來計算控件的尺寸。QGridLayout的伸縮策略是通過行和列的伸縮策略來計算的,而不是通過每一個控件的伸縮策略來計算的。
QFormLayout是QLayout的子類,它描述的是一個表格布局,也就是一個二維的布局。它的每一個子控件都有一個行號和列號,通過這兩個號碼來描述控件的位置。每一個行和列都有一個伸縮策略,通過這個策略來計算控件的尺寸。QFormLayout的伸縮策略是通過行和列的伸縮策略來計算的,而不是通過每一個控件的伸縮策略來計算的。
最后還有一個我不知道有什么用的QStackedLayout,這個布局類描述的是一個堆棧布局,也就是一堆控件,只有一個控件是可見的,其它的控件都是不可見的。這個布局類還沒有提供顯式的切換方案,必須自己調(diào)用QStackedLayout的setCurrentIndex方法來切換。通常會把這個方法作為一個槽函數(shù)綁定到某個信號上。
游戲
這里我們設計一個展示這幾中布局的小程序。
- 報表:每種布局的展示;
- 報表:QStackLayout自動(定時)切換控件。
- 交互:切換布局;
程序源代碼如下。文章來源:http://www.zghlxwxcb.cn/news/detail-436143.html
import random
import sys
from functools import partial
from typing import Union
from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtGui import QFont
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QHBoxLayout, QGridLayout, QFormLayout, \
QStackedLayout, QComboBox, QLabel, QMainWindow, QDockWidget
# module shared variables
colors = ['yellow', 'red', 'cyan', 'green', 'white',
'gray', 'orange', 'darkgray', 'transparent']
name_layouts = {'vbox': QVBoxLayout,
'hbox': QHBoxLayout,
'grid': QGridLayout,
'form': QFormLayout,
'stacked': QStackedLayout}
timer: Union[QTimer, None] = None
# module shared functions
def show_layout(parent: QMainWindow, layout_short_name: str):
random.shuffle(colors)
widgets = [QLabel(c, win) for c in colors]
for i, (c, w) in enumerate(zip(colors, widgets)):
w.setStyleSheet(f"background-color: {c}")
w.setAlignment(Qt.AlignCenter)
w.setFont(QFont("SimHei", 24))
widget = QWidget(parent)
if not (layout_short_name in name_layouts):
raise ValueError(
f"{layout_short_name} not in {list(name_layouts.keys())}")
layout = name_layouts[layout_short_name]()
for i, w in enumerate(widgets):
if layout_short_name == 'grid':
layout.addWidget(w, i // 3, i % 3)
elif layout_short_name == 'form':
layout.addRow(w.text() + ":", w)
else:
layout.addWidget(w)
global timer
if timer is not None:
timer.stop()
timer = None
if layout_short_name == 'stacked':
timer = QTimer(parent)
def change_layout():
try:
layout.setCurrentIndex((layout.currentIndex() + 1) % layout.count())
except Exception as e:
pass
timer.timeout.connect(change_layout)
timer.start(1000)
widget.setLayout(layout)
parent.setCentralWidget(widget)
class QCycleComboBox(QComboBox):
"""
A combobox that cycles through its items when the mouse wheel is used, or the up/down keys are pressed.
"""
def __init__(self, parent: QWidget = None) -> None:
super(QCycleComboBox, self).__init__(parent)
def wheelEvent(self, event):
if event.angleDelta().y() > 0:
self.setCurrentIndex((self.currentIndex() - 1) % self.count())
else:
self.setCurrentIndex((self.currentIndex() + 1) % self.count())
def keyPressEvent(self, e) -> None:
if e.key() == Qt.Key_Up:
self.setCurrentIndex((self.currentIndex() - 1) % self.count())
if e.key() == Qt.Key_Down:
self.setCurrentIndex((self.currentIndex() + 1) % self.count())
else:
return super(QCycleComboBox, self).keyPressEvent(e)
if __name__ == '__main__':
app = QApplication([])
win = QMainWindow()
choice = QCycleComboBox(win)
choice.addItems(name_layouts.keys())
dock = QDockWidget('Layouts selection', win)
dock.setWidget(choice)
dock.setFeatures(QDockWidget.NoDockWidgetFeatures)
win.addDockWidget(Qt.TopDockWidgetArea, dock)
choice.currentTextChanged.connect(partial(show_layout, win))
show_layout(win, 'vbox')
win.setWindowTitle("Layouts")
win.setGeometry(100, 100, 800, 600)
win.show()
sys.exit(app.exec_())
這個程序的結(jié)構(gòu)和邏輯非常簡單,不再贅述。文章來源地址http://www.zghlxwxcb.cn/news/detail-436143.html
總結(jié)
- 布局分為兩種層次,高層次布局和界面布局;
- 界面布局分為:概念布局、相對布局和絕對布局;
- Qt5的常用布局類有:QVBoxLayout、QHBoxLayout、QGridLayout、QFormLayout和QStackedLayout。
到了這里,關(guān)于PyQt5桌面應用開發(fā)(10):界面布局基本支持的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!