本文目录

  • PyQt5桌面应用系列
  • 布局
  • 利器
  • 游戏
  • 总结

PyQt5桌面应用系列

  • PyQt5桌面应用开发(1):需求分析
  • PyQt5桌面应用开发(2):事件循环
  • PyQt5桌面应用开发(3):并行设计
  • PyQt5桌面应用开发(4):界面设计
  • PyQt5桌面应用开发(5):对话框
  • PyQt5桌面应用开发(6):文件对话框
  • PyQt5桌面应用开发(7):文本编辑+语法高亮与行号
  • PyQt5桌面应用开发(8):从QInputDialog转进到函数参数传递
  • PyQt5桌面应用开发(9):经典布局QMainWindow
  • PyQt5桌面应用开发(10):界面布局基本支持
  • PyQt5桌面应用开发(11):摸鱼也要讲基本法,两个字,16

布局

布局是设计报表和交互中的重要工作。但是布局的内涵有两个层面上的:总体布局和界面布局。

从报表设计的角度出发,布局应该把最重要的信息显示在最显眼的位置,把次要的信息放在次显眼的位置,把不重要的信息放在不显眼的位置。报表设计始终还是要围绕报表的目的(也就是用户利用数据、信息进行决策的目的)来进行的。围绕一个决策来布局信息的分类、汇总、分析、比较、评价、预测等功能,这些功能的实现都是为了帮助用户做出决策。

从交互设计的角度出发,应该把核心、重要的功能放在最显眼的位置,把次要的功能放在次显眼的位置,把不重要的功能放在不显眼的位置,这与报表设计相同;此外,还应该把相互关联的操作放在一起,把相互独立的功能分开。

这个在实际的设计中,可以通过分组、分页、分栏、分区等方式来实现报表信息和交互的总体布局。

而在较低的一个层次上,则是一个具体的界面上的控件如何定位、缩放、对齐,控件上相关的控件之间如何相互协调。这个层次上的布局,可以通过控件的定位位置、几何尺寸来描述。最基础的布局就是控件的位置和尺寸,这也叫绝对位置布局。在这个基础上,还能实现相对位置布局,通过以某个控件的位置和尺寸为基准,把其它控件的位置和尺寸转换相对坐标系来描述。这都是直接和更底层的布局算法,当然所有的更抽象的布局都会归结成相对布局算法和绝对布局算法。

  1. 抽象布局
  2. 相对布局
  3. 绝对布局

而抽象布局是在人类认知的概念中对一组控件的排列进行抽象的描述,比如一列、一行、一个网格、一个表格、一个树形结构,等等。抽象的层次较高的界面布局,就更加便于人类使用,为思考布局提供了工具,但是也限制了布局的灵活性;较低层次的布局,需要更多的精力来思考,但是也提供了更强大的功能和灵活性。

大部分的UI开发工具包,都提供了一定层次的抽象布局工具。例如JavaFX、Qt、Web前端工具中都有类似的概念和工具支持。Qt5提供的布局工具并不丰富,但是也足够形成复杂的界面。

利器

Qt5提供布局的方式是每一个QWidget都有一个QLayout对象,通过setLayout方法来设置。QWidget的子节点,通过加入布局类中来获得自动计算相对位置、大小和绝对位置大小的能力。Qt5中最常用的布局类有四个:QHBoxLayout、QVBoxLayout、QGridLayout、QFormLayout。

其中QHBoxLayout和QVBoxLayout是QBoxLayout的子类,这三个类描述的就是一行或者一列控件。当控件排成一列时,其x方向的位置和尺寸都保持一致,y方向的位置成线性增长,尺寸通过按比例伸缩、固定最小尺寸、固定最大尺寸、扩张、最小化等概念来计算。最后这个部分通常称为sizePolicy,也就是伸缩策略。同样,当控件拍成一行时,其y方向的位置和尺寸都保持一致,x方向的位置成线性增长,尺寸通过按比例伸缩、固定最小尺寸、固定最大尺寸、扩张、最小化等概念来计算。

QGridLayout是QLayout的子类,它描述的是一个网格布局,也就是一个二维的布局。它的每一个子控件都有一个行号和列号,通过这两个号码来描述控件的位置。每一个行和列都有一个伸缩策略,通过这个策略来计算控件的尺寸。QGridLayout的伸缩策略是通过行和列的伸缩策略来计算的,而不是通过每一个控件的伸缩策略来计算的。

QFormLayout是QLayout的子类,它描述的是一个表格布局,也就是一个二维的布局。它的每一个子控件都有一个行号和列号,通过这两个号码来描述控件的位置。每一个行和列都有一个伸缩策略,通过这个策略来计算控件的尺寸。QFormLayout的伸缩策略是通过行和列的伸缩策略来计算的,而不是通过每一个控件的伸缩策略来计算的。

最后还有一个我不知道有什么用的QStackedLayout,这个布局类描述的是一个堆栈布局,也就是一堆控件,只有一个控件是可见的,其它的控件都是不可见的。这个布局类还没有提供显式的切换方案,必须自己调用QStackedLayout的setCurrentIndex方法来切换。通常会把这个方法作为一个槽函数绑定到某个信号上。

游戏

这里我们设计一个展示这几中布局的小程序。

  • 报表:每种布局的展示;
  • 报表:QStackLayout自动(定时)切换控件。
  • 交互:切换布局;

程序源代码如下。

import random
import sys
from functools import partial
from typing import Unionfrom 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 timerif timer is not None:timer.stop()timer = Noneif layout_short_name == 'stacked':timer = QTimer(parent)def change_layout():try:layout.setCurrentIndex((layout.currentIndex() + 1) % layout.count())except Exception as e:passtimer.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_())

这个程序的结构和逻辑非常简单,不再赘述。

总结

  1. 布局分为两种层次,高层次布局和界面布局;
  2. 界面布局分为:概念布局、相对布局和绝对布局;
  3. Qt5的常用布局类有:QVBoxLayout、QHBoxLayout、QGridLayout、QFormLayout和QStackedLayout。

PyQt5桌面应用开发(10):界面布局基本支持相关推荐

  1. PyQt5桌面应用开发(9):经典布局QMainWindow

    本文目录 PyQt5桌面应用系列 桌面程序基本布局 QMainWindow概况与使用 主窗体 菜单栏 工具栏 停靠窗 状态栏 代码编辑器的例子 总结 PyQt5桌面应用系列 PyQt5桌面应用开发(1 ...

  2. PyQt5桌面应用开发(4):界面设计

    本文目录 PyQt5桌面应用系列 前言 为什么又是需求分析? PyQt5的界面设计元素 界面设计元素分类 编译为Python代码使用 转换命令行 组合使用 继承使用方式 直接使用ui文件的方法 总结 ...

  3. PyQt5桌面应用开发(17):中文书评+类结构+QWebEngineView

    本文目录 PyQt5桌面应用系列 PyQt5学习 PyQt5类结构和帮助速查 实现与解释 最终界面和完整源代码 界面 完整的代码 总结 PyQt5桌面应用系列 PyQt5桌面应用开发(1):需求分析 ...

  4. PyQt5桌面应用开发(11):摸鱼也要讲基本法之桌面精灵

    本文目录 PyQt5桌面应用系列 鼠标不要钱,手腕还不要钱吗? PyQt5源程序 python文件 资源定义 界面定义文件 技术要素 资源文件 StyleSheets QMainWindow设置 窗体 ...

  5. PyQt5桌面应用开发(8):从QInputDialog转进到函数参数传递

    本文目录 PyQt5桌面应用系列 How old are you, Dialog? QInputDialog minimalist why not lambda and how partial wor ...

  6. PyQt5桌面应用开发(2):事件循环

    本文目录 PyQt5桌面应用系列 前言 当君怀GUI日,是妾断肠时 几时得GUI去,依旧作山夫 需求分析 代码 事件循环的基本结构 PyQt5的事件机制 启动事件循环 唯将往来信,遥将连信槽 借问Si ...

  7. 安卓开发——安卓界面布局笔记

    Android布局笔记 Android的界面是有布局和组件协同完成的,布局使用不同的组件,组件按照布局的要求依次排列,就组成了用户所看见的界面. 所有的布局方式都可以归类为ViewGroup的5个类别 ...

  8. android开发UI界面布局教学,android UI学习 -- 设置界面的布局(包括style的使用,selector的使用,Checkbox自定义样式,菜单项的样式)...

    最终实现效果如下图: 具体来说就是实现了checkbox自定义选中和为选择样式,菜单项根据不同位置设置不同背景. 先上整体布局文件代码: xmlns:tools="http://schema ...

  9. android layout 界面开发,android 界面布局入门级示例(LinearLayout)

    [实例简介] [实例截图] [核心代码] xmlns:tools="http://schemas.android.com/tools" android:id="@ id/ ...

最新文章

  1. 微软发布WP SDK8.0 新增语音、应用内支付等原生API
  2. Redlock:Redis分布式锁最牛逼的实现
  3. Qt 实现钢笔画线效果详细原理
  4. Ajax:异步js和xml
  5. 基于Keras的卷积神经网络用于猫狗分类(进行了数据增强)+卷积层可视化
  6. BeautifulSoup模块过滤掉html标签,只拿文本内容(处理XSS攻击)
  7. WCF 第一章 基础 为一个ASMX服务实现一个WCF客户端
  8. java mysql 分页计算公式_关于Java的分页算法,急!
  9. 软件测试管理是什么?
  10. Word-制作“田”字格、“米”字格、“拼音”字格和“日”字格
  11. 迅雷精简版 Mac中文版
  12. 电脑版的微信怎么打开连接到服务器地址,电脑端浏览器打开微信限制页面的方法...
  13. 黑客学习路线(送给那些在学习路上迷茫的人)
  14. 关于html的表情包,HTML那些可愛的“表情包”
  15. linux 免费教程下载,Linux系统入门教程
  16. 转自一个计算机毕业生的求职经验
  17. 当你想吃夜宵的时候你会到谁
  18. python手机版下载官方3.4.6,python手机版下载苹果版
  19. Unity3D播放音频数组的问题
  20. 如何计算石英晶振的匹配电容

热门文章

  1. Ubuntu与WIndows桌面间切换
  2. openMVS深度图计算:DenseReconstruction Estimate之EVTEstimateDepthMap之patchmatch的传播优化
  3. 用 Python 实现马丁格尔交易策略(附代码)
  4. 计算机机房的维护管理论文,浅析计算机机房管理与维护
  5. Google Play Store Apps(谷歌应用程序相关数据集)
  6. oracle 字符串分割成数组_oracle 自定义字符串分割为数组方法
  7. 用按键精灵,写个简单的跳课脚本
  8. 电脑报警声c语言,报警声设计
  9. Unity Asset Store更新!
  10. 要多久人工智能的梦想才能照进现实