百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

Python入坑系列-Pyside6桌面编程之Layout设置精美布局效果

haoteby 2024-11-09 13:02 33 浏览

通过本文章,你可以掌握以下内容:

  1. Pyside6 Layout介绍
  2. Pyside6 Layout布局解释及示例
  3. 自定义Layout,实现部件自动换行

1、Pyside6 Layout介绍

QtWidgets.QLayout是Qt中用于管理窗口或对话框中小部件(控件)布局的基类。它是一个抽象基类,定义了所有布局类共有的接口和行为。QLayout及其子类的主要作用是自动管理小部件的位置和大小,以便于创建整洁和灵活的图形用户界面(GUI),对于复杂界面布局是很重要的,主要作用包括:

  • 自动管理小部件位置:QLayout自动计算小部件的位置,使得小部件根据布局规则排列,无需手动指定每个小部件的具体位置。
  • 自动调整大小:当窗口大小变化时,QLayout能够自动调整其管理的小部件的大小和位置,确保布局的一致性和响应性。
  • 简化界面设计:通过使用布局,开发者可以更加专注于界面的结构设计,而不是具体的位置和大小调整,从而简化了界面设计过程。
  • 支持嵌套:布局可以嵌套使用,即一个布局可以包含其他布局,这允许创建复杂的界面结构

2、Pyside6 Layout布局解释及示例

以下是继承自QtWidgets.QLayout的布局,每种布局有对应的行为。

布局

行为

对应html

QHBoxLayout

线性水平布局

类似于display: flex; flex-direction: row;的Flexbox布局

QVBoxLayout

线性垂直布局

类似于display: flex; flex-direction: column;的Flexbox布局

QGridLayout

在可转位网格 XxY 中

类似于html的table行和列

QStackedLayout

堆叠 (z) 于彼此前面

类似于css的z-index,并控制隐藏显示效果

QHBoxLayout

QHBoxLayout是Qt中的一个布局管理器类,用于按水平方向排列小部件。它继承自QLayout,提供了一种简便的方式来自动管理窗口或对话框中小部件的位置和大小。使用QHBoxLayout,可以将小部件从左到右依次排列,而不需要手动指定每个小部件的具体位置。

简单的示例如下:

import sys
from PySide6.QtWidgets import *
class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setWindowTitle("QHBoxLayout之水平布局")
        self.setMinimumSize(400,300)
        layout = QHBoxLayout()
        layout.addWidget(QPushButton("1"))
        layout.addWidget(QPushButton("2"))
        layout.addWidget(QPushButton("3"))
        widget = QWidget()
        widget.setLayout(layout)
        self.setCentralWidget(widget)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    app.exec()

QVBoxLayout

QVBoxLayout是Qt中的一个布局管理器类,用于垂直方向排列小部件。它继承自QLayout,提供了一种简便的方式来自动管理窗口或对话框中小部件的位置和大小。使用QVBoxLayout,可以将小部件从上到下依次排列,而不需要手动指定每个小部件的具体位置。

简单示例如下:

import sys
from PySide6.QtWidgets import *
class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setWindowTitle("QVBoxLayout之垂直布局")
        self.setMinimumSize(400, 300)
        layout = QVBoxLayout()
        layout.addWidget(QPushButton("1"))
        layout.addWidget(QPushButton("2"))
        layout.addWidget(QPushButton("3"))
        widget = QWidget()
        widget.setLayout(layout)
        self.setCentralWidget(widget)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    app.exec()

效果图如下:

QGridLayout

QGridLayout是Qt中一个非常强大的布局管理器,它提供一种网格式布局,这种布局由行和列组成(类似table),每个小部件占据网格中的一个或多个单元格。QGridLayout提供了灵活的方式来创建复杂的用户界面,使得小部件的布局可以精确控制,同时也能自动适应窗口大小的变化,主要特性有:

  • 行列管理:可以指定小部件应该放在网格的哪一行哪一列,甚至可以跨越多行多列。
  • 自动调整大小:当窗口大小改变时,QGridLayout会自动调整小部件的大小和位置,保持布局的整洁和一致性。
  • 最小宽度和拉伸因子:每列(或行)可以有一个最小宽度和一个拉伸因子,这决定了在可用空间中它们将如何分配额外的空间。
  • 间距和边距:可以设置小部件之间的间距(spacing())和布局边缘的边距(内容边距),以控制布局的外观。

示例代码如下:

import sys
from PySide6.QtWidgets import *
class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setWindowTitle("QGridLayout之网格布局")
        self.setMinimumSize(400, 300)
        layout = QGridLayout()
        # 为窗口部件设置样式表,添加边框
        self.setStyleSheet("QWidget { border: 2px solid black; }")
        layout.addWidget(QLabel('第0行第0列'), 0, 0)
        layout.addWidget(QLabel('第0行第1列'), 0, 1)
        layout.addWidget(QLabel('第1行第0列'), 1, 0)
        layout.addWidget(QLabel('第1行第1列'), 1, 1)
        widget = QWidget()
        widget.setLayout(layout)
        self.setCentralWidget(widget)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    app.exec()

效果图如下:

QStackedLayout

QStackedLayout是Qt中的一个布局管理器,它可以在相同的空间内堆叠多个小部件,但一次只显示一个小部件。这种布局非常适合用于实现向导、选项卡和其他需要在多个页面之间切换的界面。

主要特性:

  • 堆叠小部件:在同一个布局空间内堆叠多个小部件。
  • 单一可见性:一次只有一个小部件可见。
  • 动态切换:可以编程方式动态切换当前可见的小部件

常用方法技巧:indexOf()函数返回小部件在该列表中的索引。可以使用addWidget()函数添加小部件到列表末尾,或者使用insertWidget()函数在给定索引处插入。removeWidget()函数从布局中移除给定索引的小部件。可以使用count()函数获取布局中包含的小部件数量。widget()函数返回给定索引位置的小部件。当前显示在屏幕上的小部件的索引由currentIndex()给出,并且可以使用setCurrentIndex()进行更改。以类似的方式,可以使用currentWidget()函数检索当前显示的小部件,并使用setCurrentWidget()函数进行更改。每当布局中的当前小部件发生变化或从布局中移除小部件时,分别会发出currentChanged()和widgetRemoved()信号。

示例代码如下:

import sys
from PySide6.QtGui import QPalette, QColor
from PySide6.QtWidgets import *
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("QStackedLayout之堆叠布局")
        self.setMinimumSize(400, 300)
        pagelayout = QVBoxLayout()
        button_layout = QHBoxLayout()
        self.stacklayout = QStackedLayout()
        pagelayout.addLayout(button_layout)
        pagelayout.addLayout(self.stacklayout)
        btn = QPushButton("red")
        btn.pressed.connect(self.activate_tab_1)
        button_layout.addWidget(btn)
        self.stacklayout.addWidget(Color("red"))
        btn = QPushButton("green")
        btn.pressed.connect(self.activate_tab_2)
        button_layout.addWidget(btn)
        self.stacklayout.addWidget(Color("green"))
        btn = QPushButton("yellow")
        btn.pressed.connect(self.activate_tab_3)
        button_layout.addWidget(btn)
        self.stacklayout.addWidget(Color("yellow"))
        widget = QWidget()
        widget.setLayout(pagelayout)
        self.setCentralWidget(widget)

    def activate_tab_1(self):
        self.stacklayout.setCurrentIndex(0)

    def activate_tab_2(self):
        self.stacklayout.setCurrentIndex(1)

    def activate_tab_3(self):
        self.stacklayout.setCurrentIndex(2)

class Color(QWidget):
    def __init__(self, color):
        super(Color, self).__init__()
        self.setAutoFillBackground(True)
        palette = self.palette()
        palette.setColor(QPalette.Window, QColor(color))
        self.setPalette(palette)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    app.exec()

效果图如下:


混合布局

使用QHBoxLayout、QVBoxLayout、QGridLayout、QStackedLayout这几种布局组合使用,来控制界面的整体风格视角,制作精美的布局效果

示例代码如下:

import sys
from PySide6.QtWidgets import *

class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setWindowTitle("混合布局")
        self.setMinimumSize(400, 300)
        self.setStyleSheet("QLabel { border: 1px solid blue; }")
        layout1 = QHBoxLayout()
        layout2 = QVBoxLayout()
        layout3 = QVBoxLayout()
        layout1.setContentsMargins(0,0,0,0)
        layout1.setSpacing(20)
        layout2.addWidget(QLabel('hbox1-QVBoxLayout1'))
        layout2.addWidget(QLabel('hbox1-QVBoxLayout2'))
        layout2.addWidget(QLabel('hbox1-QVBoxLayout3'))
        layout1.addLayout(layout2)
        layout1.addWidget(QLabel('hbox2'))
        layout3.addWidget(QLabel('hbox2-QVBoxLayout1'))
        layout3.addWidget(QLabel('hbox2-QVBoxLayout2'))
        layout1.addLayout(layout3)
        widget = QWidget()
        widget.setLayout(layout1)
        self.setCentralWidget(widget)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    app.exec()

效果图如下:


注意:QLayout边框及样式不能通过这种方式来设置样式效果,需要指定Widget的样式

#无效果
self.setStyleSheet("QHBoxLayout { border: 1px solid black; }")
#有效果
self.setStyleSheet("QLabel { border: 1px solid blue; }")

自定义Layout,实现部件自动换行

由于QHBoxLayout、QVBoxLayout、QGridLayout、QStackedLayout布局放置的控件,不增加任何处理,生成的控件会固定住窗口大小,可以通过下面来动态排列控件。

示例代码如下:

import sys
from PySide6.QtCore import QRect, QSize, QPoint, Qt
from PySide6.QtWidgets import *

class FlowLayout(QLayout):
    def __init__(self, parent=None, margin=0, spacing=-1):
        super(FlowLayout, self).__init__(parent)
        if parent is not None:
            self.setContentsMargins(margin, margin, margin, margin)
        self.setSpacing(spacing)
        self.items = []

    def addItem(self, item):
        self.items.append(item)

    def count(self):
        return len(self.items)

    def itemAt(self, index):
        if index >= 0 and index < len(self.items):
            return self.items[index]
        return None

    def takeAt(self, index):
        if index >= 0 and index < len(self.items):
            return self.items.pop(index)
        return None

    def expandingDirections(self):
        return 0

    def hasHeightForWidth(self):
        return True

    def heightForWidth(self, width):
        height = self.doLayout(QRect(0, 0, width, 0), True)
        return height

    def setGeometry(self, rect):
        super(FlowLayout, self).setGeometry(rect)
        self.doLayout(rect, False)

    def sizeHint(self):
        return QSize(self.doLayout(QRect(0, 0, 10000, 0), True), 10000)

    def doLayout(self, rect, testOnly):
        x = rect.x()
        y = rect.y()
        lineHeight = 0
        for item in self.items:
            wid = item.widget()
            spaceX = self.spacing() + wid.style().layoutSpacing(QSizePolicy.PushButton, QSizePolicy.PushButton,Qt.Horizontal)
            spaceY = self.spacing() + wid.style().layoutSpacing(QSizePolicy.PushButton, QSizePolicy.PushButton,Qt.Vertical)
            nextX = x + item.sizeHint().width() + spaceX
            if nextX - spaceX > rect.right() and lineHeight > 0:
                x = rect.x()
                y = y + lineHeight + spaceY
                nextX = x + item.sizeHint().width() + spaceX
                lineHeight = 0
            if not testOnly:
                item.setGeometry(QRect(QPoint(x, y), item.sizeHint()))
            x = nextX
            lineHeight = max(lineHeight, item.sizeHint().height())

        return y + lineHeight - rect.y()
if __name__ == '__main__':
    app = QApplication(sys.argv)
    mainWidget = QWidget()
    mainWidget.setMinimumSize(300, 200)
    layout = FlowLayout(mainWidget)
    for i in range(50):
        layout.addWidget(QPushButton(f'Button {i}'))
    mainWidget.setLayout(layout)
    mainWidget.show()
    sys.exit(app.exec_())

效果如下:

相关推荐

一日一技:用Python程序将十进制转换为二进制

用Python程序将十进制转换为二进制通过将数字连续除以2并以相反顺序打印其余部分,将十进制数转换为二进制。在下面的程序中,我们将学习使用递归函数将十进制数转换为二进制数,代码如下:...

十进制转化成二进制你会吗?#数学思维

六年级奥赛起跑线:抽屉原理揭秘。同学们好,我是你们的奥耀老师。今天一起来学习奥赛起跑线第三讲二进制计数法。例一:把十进制五十三化成二进制数是多少?首先十进制就是满十进一,二进制就是满二进一。二进制每个...

二进制、十进制、八进制和十六进制,它们之间是如何转换的?

在学习进制时总会遇到多种进制转换的时候,学会它们之间的转换方法也是必须的,这里分享一下几种进制之间转换的方法,也分享两个好用的转换工具,使用它们能够大幅度的提升你的办公和学习效率,感兴趣的小伙伴记得点...

c语言-2进制转10进制_c语言 二进制转十进制

#include<stdio.h>intmain(){charch;inta=0;...

二进制、八进制、十进制和十六进制数制转换

一、数制1、什么是数制数制是计数进位的简称。也就是由低位向高位进位计数的方法。2、常用数制计算机中常用的数制有二进制、八进制、十进制和十六进制。...

二进制、十进制、八进制、十六进制间的相互转换函数

二进制、十进制、八进制、十六进制间的相互转换函数1、输入任意一个十进制的整数,将其分别转换为二进制、八进制、十六进制。2、程序代码如下:#include<iostream>usingna...

二进制、八进制、十进制和十六进制等常用数制及其相互转换

从大学开始系统的接触计算机专业,到现在已经过去十几年了,今天整理一下基础的进制转换,希望给还在上高中的表妹一个入门的引导,早日熟悉这个行业。一、二进制、八进制、十进制和十六进制是如何定义的?二进制是B...

二进制如何转换成十进制?_二进制如何转换成十进制例子图解

随着社会的发展,电器维修由继电器时代逐渐被PLC,变频器,触摸屏等工控时代所替代,特别是plc编程,其数据逻辑往往涉及到数制二进制,那么二进制到底是什么呢?它和十进制又有什么区别和联系呢?下面和朋友们...

二进制与十进制的相互转换_二进制和十进制之间转换

很多同学在刚开始接触计算机语言的时候,都会了解计算机的世界里面大多都是二进制来表达现实世界的任何事物的。当然现实世界的事务有很多很多,就拿最简单的数字,我们经常看到的数字大多都是十进制的形式,例如:我...

十进制如何转换为二进制,二进制如何转换为十进制

用十进制除以2,除的断的,商用0表示;除不断的,商用1表示余0时结束假如十进制用X表示,用十进制除以2,即x/2除以2后为整数的(除的断的),商用0表示;除以2除不断的,商用1表示除完后的商0或1...

十进制数如何转换为二进制数_十进制数如何转换为二进制数举例说明

我们经常听到十进制数和二进制数,电脑中也经常使用二进制数来进行计算,但是很多人却不清楚十进制数和二进制数是怎样进行转换的,下面就来看看,十进制数转换为二进制数的方法。正整数转二进制...

二进制转化为十进制,你会做吗?一起来试试吧

今天孩子问把二进制表示的110101改写成十进制数怎么做呀?,“二进制”简单来说就是“满二进一”,只用0和1共两个数字表示,同理我们平常接触到的“十进制”是“满十进一”,只用0-9共十个数字表示。如果...

Mac终于能正常打游戏了!苹果正逐渐淘汰Rosetta转译

Mac玩家苦转译久矣!WWDC2025苹果正式宣判Rosetta死刑,原生游戏时代终于杀到。Metal4光追和AI插帧技术直接掀桌,连Steam都连夜扛着ARM架构投诚了。看到《赛博朋克2077》...

怎么把视频的声音提出来转为音频?音频提取,11款工具实测搞定

想把视频里的声音单独保存为音频文件(MP3/AAC/WAV/FLAC)用于配音、播客、听课或二次剪辑?本文挑出10款常用工具,给出实测可复现的操作步骤、优缺点和场景推荐。1)转换猫mp3转换器(操作门...

6个mp4格式转换器测评:转换速度与质量并存!

MP4视频格式具有兼容性强、视频画质高清、文件体积较小、支持多种编码等特点,适用于网络媒体传播。如果大家想要将非MP4格式的视频转换成MP4的视频格式的话,可以使用MP4格式转换器更换格式。本文分别从...