20. 容器类控件

一、容器控件

  容器类控件不能输入输出数据,通常作为常用控件的载体,将常用控件 “放置” 到其内部。容器控件对放到其内部的控件进行管理,并成为控件的父控件。

  我们可以在终端中使用 pip 安装 PySide6 模块。默认是从国外的主站上下载,因此,我们可能会遇到网络不好的情况导致下载失败。我们可以在 pip 指令后通过 -i 指定国内镜像源下载

pip install pyside6 -i https://mirrors.aliyun.com/pypi/simple

  国内常用的 pip 下载源列表:

二、分组框控件

  QGroupBox 控件,又称为 分组框控件,它主要为其它控件提供分组,并且按照控件的分组来细分窗口的功能。 QGroupBox 通常带有一个边框和一个标题栏,标题栏上可以有勾选项,标题栏可以放到左边、中间或右边。布局时, QGroupBox 可用作一组控件的容器,内部使用布局控件进行布局。

  用 QGroupBox 创建对象的方法如下:

QGroupBox(parent:QWidget=None)
QGroupBox(title:str, parent:QWidget=None)

  其中,parent窗口 或者 容器 控件;title 是控件上 显示的文字,它是从 QWidget 类继承而来的。

  QGroupBox 类的常用方法如下:

# 实例方法
setTitle(title:str) -> None                                                     # 设置标题
title() -> str                                                                  # 获取标题

setFlat(flat:bool) -> None                                                      # 设置是否处于扁平状态
isFlat() -> bool                                                                # 获取是否处于扁平状态

setCheckable(checkable:bool) -> None                                            # 设置是否有勾选框
isCheckable() -> bool                                                           # 获取是否有勾选框
isChecked() -> bool                                                             # 获取勾选项是否处于勾选状态

setAlignment(alignment:Qt.AlignmentFlag) -> None                                # 设置对齐方式
alignment() -> Qt.AlignmentFlag                                                 # 获取对齐方式

# 槽函数
setChecked(checked:bool) -> None                                                # 设置勾选项是否处于勾选状态

  用 setAlignment(alignment:Qt.Alignment) 方法可以 设置标题栏的对齐位置,其中参数 alignmentQt.Alignment 类型的枚举值,可以取值如下:

Qt.Alignment.AlignLeft                                                          # 把标题栏放到左边
Qt.Alignment.AlignRight                                                         # 把标题栏放到右边
Qt.Alignment.AlignHCenter                                                       # 把标题栏放到中间
Qt.Alignment.AlignCenter                                                        # 把标题栏放到中间

  创建分组框控件后,如果要往分组框中添加其他控件,可以在创建控件对象时将其 parent 参数设置成 QGroupBox 的实例对象,或者用控件的 setParent(widget:QWidget)方法 设置控件所在的容器。也可以先创建布局,将控件放到布局中,然后用分组框的 setLayout(layout:QLayout) 方法 将布局添加到分组框中

  我们新建一个 ui.py 文件,用来存放 UI 相关的代码。

from PySide6.QtWidgets import QWidget
from PySide6.QtWidgets import QGroupBox, QPushButton
from PySide6.QtWidgets import QHBoxLayout
from PySide6.QtCore import Qt

class MyUi:
    def setupUi(self, window:QWidget):
        window.resize(800, 600)                                                 # 1.设置窗口对象大小
  
        groupBox = QGroupBox(window)                                            # 2.创建分组控件
        groupBox.setGeometry(10, 10, 300, 100)                                  # 3.设置分组框控件的位置和大小

        groupBox.setTitle("分组标题")                                             # 4.设置分组标题
        groupBox.setAlignment(Qt.AlignmentFlag.AlignCenter)                     # 5.设置标签文本对齐方式

        layout = QHBoxLayout(groupBox)                                          # 6.创建布局控件

        button_1 = QPushButton("按钮1")                                          # 7.创建控件,并添加到布局中
        layout.addWidget(button_1)

        button_2 = QPushButton("按钮2")
        layout.addWidget(button_2)

  我们新建一个 widget.py 文件,用来存放业务逻辑相关的代码。

import sys

from PySide6.QtWidgets import QApplication, QWidget

from ui import MyUi

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()                                                      # 1.调用父类Qwidget类的__init__()方法
      
        self.__ui = MyUi()
        self.__ui.setupUi(self)                                                 # 2.初始化页面

if __name__ == "__main__":
    app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例
    window = MyWidget()                                                         # 2.创建一个窗口
    window.show()                                                               # 3.显示窗口
    sys.exit(app.exec())                                                        # 4.进入程序的主循环,并通过exit函数确保主循环安全结束

三、框架控件

  框架控件 QFrame 作为容器,可以在其内部放置各种可视控件。但是 QFrame 没有属于自己特有的信号和槽函数,一般不接受用户的输入,它只能提供一个外形,可以设置外形的样式、线宽等。QFrame 作为父类,被其他一些控件所继承,这些控件如 QAbstractScrollAreaQLabelQLCDNumberQSplitterQStackedWidgetQToolBox 等。

  框架控件 QFrame 是从 QWidget 类继承而来的。用 QFrame 创建实例对象的常用方法如下所示:

QFrame(parent:QWidget=None, f:Qt.WindowFlags=Default(Qt.WindowFlags))

  其中 parent窗口 或者 容器 类控件,f 用于 设置控件的窗口类型

  框架控件 QFrame 的常用方法如下:

setFrameShadow(shadow:QFrame.Shadow) -> None                                    # 设置QFrame窗口的阴影形状
frameShadow() -> QFrame.Shadow                                                  # 获取QFrame窗口的阴影形状

setFrameShape(shape:QFrame.Shape) -> None                                       # 设置QFrame窗口的边框形状
frameShape() -> QFrame.Shape                                                    # 获取QFrame窗口的边框形状

setFrameStyle(style:int) -> None                                                # 设置QFrame窗口的边框样式
frameStyle() -> int                                                             # 获取QFrame窗口的边框样式

setLineWidth(width:int) -> None                                                 # 设置QFrame窗口的边框宽度
lineWidth() -> int                                                              # 获取QFrame窗口的边框宽度

setMidLineWidth(width:int) -> None                                              # 设置QFrame窗口的中间边框宽度
midLineWidth() -> int                                                           # 获取QFrame窗口的中间边框宽度

frameWidth() -> int                                                             # 获取QFrame窗口的边框宽度
setFrameRect(rect:QRect) -> None                                                # 设置QFrame窗口的边框矩形
frameRect() -> QRect                                                            # 获取QFrame窗口的边框矩形

drawFrame(painter:QPainter) -> None                                             # 绘制QFrame窗口边框线

setLayout(layout:QLayout) -> None                                               # 设置QFrame窗口的布局

setGeometry(rect:QRect) -> None                                                 # 设置QFrame窗口的位置和大小
setGeometry(x:int, y:int, width:int, height:int) -> None                        # 设置QFrame窗口的位置和大小

resize(size:QSize) -> None                                                      # 设置QFrame窗口的大小
resize(width:int, height:int) -> None                                           # 设置QFrame窗口的大小

  框架主要由边框线构成,边框线由外线、内线和中间线构成外线和内线的宽度 可以通过 setLineWidth(width:int) 方法设置,中间线宽度 可以通过 setMidLineWidth(width:int) 方法设置,外线和内线的宽度 通过 lineWidth() 方法获取,中间线的宽度 通过 midLineWidth() 方法获取,外线、内线和中间线总体宽度 通过 frameWidth() 方法获取。

  通过给边框的内线、外线设置不同的颜色,可以让外框有凸起和凹陷的立体感觉。用 setFrameShadow(shadow:QFrame.Shadow) 方法 =设置边框线的立体感觉,参数 shadowQFrame.Shadow 类型的枚举值,可以取值如下:

QFrame.Shadow.Plain                                                             # 平面
QFrame.Shadow.Raised                                                            # 凸起
QFrame.Shadow.Sunken                                                            # 凹陷

  外框线的形状 通过 setFrameShape(shape:QFrame.Shape) 方法设置,其中参数 shapeQFrame.Shape 类型的枚举值,可取值如下所示:

QFrame.Shape.NoFrame                                                            # 无边框,默认值
QFrame.Shape.Box                                                                # 矩形框,边框线内部不填充
QFrame.Shape.Panel                                                              # 面板,边框线内部填充
QFrame.Shape.WinPanel                                                           # Windows2000风格的面板,边框线的宽度是2像素
QFrame.Shape.HLine                                                              # 边框线只在中间有一条水平线,用作分隔线
QFrame.Shape.VLine                                                              # 边框线只在中间有一条垂直线,用作分隔线
QFrame.Shape.StyledPanel                                                        # 依据当前GUI类型,画一个矩形面板

  QFrameframeStyle 属性由 frameShadow 属性和 frameShape 属性决定,因此设置 frameShadowframeShape 的值,就不需要再设置 frameStyle 的值了。将以上参数进行组合可以得到不同感觉的边框线。

  修改 ui.py 文件的内容。

from PySide6.QtWidgets import QWidget
from PySide6.QtWidgets import QFrame, QPushButton
from PySide6.QtWidgets import QHBoxLayout

class MyUi:
    def setupUi(self, window:QWidget):
        window.resize(800, 600)                                                 # 1.设置窗口对象大小
  
        frame = QFrame(window)                                                  # 2.创建框架控件对象
        frame.setGeometry(10, 10, 300, 100)                                     # 3.设置框架控件的位置和大小

        frame.setLineWidth(10)                                                  # 4.设置框架控件的线宽
        frame.setFrameShape(QFrame.Shape.Box)                                   # 5.设置框架控件的形状
        frame.setFrameShadow(QFrame.Shadow.Raised)                              # 6.设置框架控件的立体感觉

        layout = QHBoxLayout(frame)                                             # 7.创建布局控件
  
        button_1 = QPushButton("按钮1")                                          # 8.创建按钮控件,并添加布局中
        layout.addWidget(button_1)

        button_2 = QPushButton("按钮2")
        layout.addWidget(button_2)

四、滚动区控件

  滚动区控件 QScrollArea 作为其他控件的容器,当其内部的控件超过滚动区的尺寸时,滚动区自动提供水平或竖直滚动条,通过拖动滚动条的位置,用户可以看到内部所有控件的内容。

  用 QScrollArea 类创建实例对象的方法如下所示:

QScrollArea(parent:QWidget=None)

  其中 parent窗口 或者 容器 类控件,它是从抽象类 QAbstractScrollArea 继承而来的。

  QScrollArea 类的常用方法如下:

setWidget(widget:QWidget) -> None                                               # 将某个控件设置成可滚动显示的控件
widget() -> QWidget                                                             # 获取可滚动显示的控件

setWidgetResizable(resizable:bool) -> None                                      # 设置内部控件是否可调节尺寸,尽量不显示滚动条
widgetResizable() -> bool                                                       # 获取内部控件是否可以调节尺寸

setAlignment(alignment::Qt.Alignment) -> None                                   # 设置内部控件在滚动区的控件对齐方式
alignment() -> Qt.Alignment                                                     # 获取内部控件在滚动区的控件对齐方式

# 自动移动滚动条的位置,确保(x, y)像素点是可见的。可见时,点到边框的距离时间为xmargin和ymargin,默认值是50
ensureVisible(x:int, y:int, margin_x:int=50, margin_y:int=50) -> None   

# 自动移动滚动条的位置,确保控件childWidget是可见的
ensureWidgetVisible(childWidget:QWidget, margin_x:int=50, margin_y:int=50)  

setHorizontalScrollBarPolicy(policy:Qt.ScrollBarPolicy) -> None                 # 设置水平滚动条的显示策略
setVerticalScrollBarPolicy(policy:Qt.ScrollBarPolicy) -> None                   # 设置垂直滚动条的显示策略

  我们需要用 setWidget(widget:QWidget) 方法将某个控件添加到滚动区控件中,以便设置该控件成可滚动显示的控件。

  用 setHorizontalScrollBarPolicy(policy:Qt.ScrollBarPolicy) 方法和 setVerticalScrollBarPolicy(policy:Qt.ScrollBarPolicy) 方法设置竖直滚动条和水平滚动条出现的策略,其中参数 policyQt.ScrollBarPolicy 类型的枚举值,可以取值如下:

Qt.ScrollBarPolicy.ScrollBarAsNeeded                                            # 根据情况自动决定何时出现滚动条
Qt.ScrollBarPolicy.ScrollBarAlwaysOff                                           # 从不出现滚动条
Qt.ScrollBarPolicy.ScrollBarAlwaysOn                                            # 一直出现滚动条

  ensureVisible(x:int ,y:int, margin_x:int=50,margin_y:int=50) 方法和 ensureWidgetVisible(childWidget:QWidget, margin_x:int=50,margin_y:int=50) 方法可以 确保某个点或某个控件是可见的,如果无法使其可见,将会使距其最近的有效点可见。当点或控件可见时,点或控件距离边界的位置是 margin_x 和 margin_y。

  修改 ui.py 文件中的内容。

from PySide6.QtWidgets import QWidget
from PySide6.QtWidgets import QScrollArea, QLabel
from PySide6.QtWidgets import QVBoxLayout
from PySide6.QtGui import QPixmap, Qt

class MyUi:
    def setupUi(self, window:QWidget):
        window.resize(800, 600)                                                 # 1.设置窗口对象大小
  
        scrollArea = QScrollArea(window)                                        # 2.创建滚动区域控件

        label = QLabel(scrollArea)                                              # 3.创建标签控件

        pixmap = QPixmap("assets/images/1.jpg")
        label.setPixmap(pixmap)                                                 # 4.设置标签的图片

        scrollArea.setWidget(label)                                             # 5.将标签控件添加到滚动区域中

        scrollArea.setAlignment(Qt.AlignmentFlag.AlignCenter)                   # 6.设置滚动区域的对齐方式
  
        scrollArea.ensureVisible(300, 300)                                      # 7.设置可见点,即滚动到指定位置
  
        scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)   # 8.设置水平显示策略
        scrollArea.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAsNeeded)     # 9.设置垂直显示策略

        layout = QVBoxLayout(window)                                            # 10.创建垂直布局
        layout.addWidget(scrollArea)                                            # 11.添加滚动区域到布局中

五、选项卡控件

  QTabWidget 控件,又称为选项卡控件,它可以将窗口设置为多页,每页卡片就是一个窗口(QWidget),以便使窗口的功能划分为多个部分,而每个部分都可以包含多个子控件。当无法显示全部卡片时,可单击右上角显示滚动按钮。

  用 QTabWidget 类创建实例对象的方法如下所示

QTabWidget(parent:QWidget=None)

  其中 parent窗口 或者 容器 类控件。

  该类的常用方法如下:

# 实例方法
addTab(widget:QWidget, label:str) -> int                                        # 在末尾添加新卡片
addTab(widget:QWidget, icon:QIcon, label:str) -> int                            # 在末尾添加新卡片

insertTab(index:int, widget:QWidget, label:str) -> int                          # 在指定位置插入新卡片
insertTab(index:int, widget:QWidget, icon:QIcon, label:str) -> int              # 在指定位置插入新卡片

widget(index:int) -> QWidget                                                    # 获取指定位置的卡片

clear() -> None                                                                 # 清空卡片
count() -> int                                                                  # 获取卡片数量
indexOf(widget:QWidget) -> int                                                  # 获取窗口对应的卡片索引号
removeTab(index:int) -> None                                                    # 删除指定位置的卡片

setCornerWidget(w:QWidget, corner:Qt.Corner=Qt.TopRightCorner) -> None          # 在角上设置控件
cornerWidget(corner:Qt.Corner=Qt.TopRightCorner) -> QWidget                     # 获取角位置处的控件

currentIndex() -> int                                                           # 获取当前卡片索引号
currentWidget() -> QWidget                                                      # 获取当前卡片

setDocumentMode(set:bool) -> None                                               # 设置卡片是否为文档模式
documentMode() -> bool                                                          # 获取卡片是否为文档模式

setElideMode(mode:Qt.TextElideMode) -> None                                     # 设置卡片标题是否为省略模式

setMovable(movable:bool) -> None                                                # 设置卡片是否可移动
isMovable() -> bool                                                             # 获取卡片是否可移动

setTabBarAutoHide(enabled:bool) -> None                                         # 设置卡片是否自动隐藏标签栏
tabBarAutoHide() -> bool                                                        # 获取卡片是否自动隐藏标签栏

setTabEnabled(index:int, enabled:bool) -> None                                  # 设置是否将索引为index的卡片激活
isTabEnabled(index:int) -> bool                                                 # 获取索引为index的卡片是否激活

setTabIcon(index:int, icon:QIcon) -> None                                       # 设置索引为index的卡片图标
tabIcon(index:int) -> QIcon                                                     # 获取索引为index的卡片图标

setIconSize(size:QSize) -> None                                                 # 设置图标大小   
iconSize() -> QSize                                                             # 获取图标大小

setTabPosition(position:QTabWidget.TabPosition) -> None                         # 设置标题栏的位置 
setTabShape(s:QTabWidget.TabShape) -> None                                      # 设置标题栏的形状

setTabText(index:int, text:str) -> None                                         # 设置索引为index的卡片标题
tabText(index:int) -> str                                                       # 获取索引为index的卡片标题

setTabToolTip(index:int, tip:str) -> None                                       # 设置索引为index的卡片提示
tabToolTip(index:int) -> str                                                    # 获取索引为index的卡片提示

setTabsClosable(closeable:bool) -> None                                         # 设置卡片是否可关闭
tabsClosable() -> bool                                                          # 获取卡片是否可关闭

setUsesScrollButtons(useButtons:bool) -> None                                   # 设置是否使用滚动按钮
usesScrollButtons() -> bool                                                     # 获取是否使用滚动按钮

# 槽函数
setCurrentIndex(index:int) -> None                                              # 根据索引设置为当前卡片
setCurrentWidget(widget:QWidget) -> None                                        # 将窗口控件widget设置为当前卡片

  QTabWidge 控件最常用的信号及其说明如下:

currentChanged(index:int)                                                       # 标签栏上的选项卡改变时发射信号
tabBarClicked(index:int)                                                        # 标签栏被点击时发射信号
tabBarDoubleClicked(index:int)                                                  # 标签栏被双击时发射信号
tabCloseRequested(index:int)                                                    # 标签栏被关闭时发射信号

  切换卡的每页卡片都是一个窗口(QWidget)或者从 QWidget 继承的可视化子类,因此添加卡片时,需要实例化的 QWidget

  QTabWidget 添加卡片的方法是 addTab(widget:QWidget, label:str)addTab(widget:QWidget, icon:QIcon, label:str),其中, QWidget 是继承自 QWidget 的实例,label卡片标题的名称,可以在名称中添加 &字母设置快捷键QIcon卡片的图标,卡片的索引从 0 开始

  在某个位置插入卡片用 insertTab(index:int, widget:QWidget, label:str)insertTab(index:int, widget:QWidget, icon:QIcon, label:str) 方法。删除所有卡片用 clear() 方法;删除索引号index 的卡片用 removeTab(index:int) 方法;卡片标题可以用 setTabText(index:int, label:str) 方法设置,其中参数 index卡片的索引

  卡片标题栏可以放到上、下、左、右位置,卡片标题的位置用 setTabPosition(position:QTabWidget.TabPosition) 方法设置,其中参数 positionQTabWidget.TabPosition 类型的枚举值,可以取值如下:

QTabWidget.TabPosition.North                                                    # 上
QTabWidget.TabPosition.South                                                    # 下
QTabWidget.TabPosition.West                                                     # 左
QTabWidget.TabPosition.East                                                     # 右

  卡片标题栏的形状用 setTabShape(shape:QTabWidget.TabShape) 方法定义,其中参数 shapeQTabWidget.TabShape 类型的枚举值,可以取值如下:

QTabWidget.TabShape.Rounded                                                     # 圆角
QTabWidget.TabShape.Triangular                                                  # 三角形

  如果显示标题栏文字的空间不足,可以用省略号来表示。用 setElideMode(mode:Qt.TextElideMode) 方法 设置卡片标题栏文字在显示空间不足时的省略号显示方式,其中参数 modeQt.TextElideMode 类型的枚举值,可以取值如下:

Qt.TextElideMode.ElideNone                                                      # 没有省略号
Qt.TextElideMode.ElideLeft                                                      # 省略号在左边
Qt.TextElideMode.ElideMiddle                                                    # 省略号在中间
Qt.TextElideMode.ElideRight                                                     # 省略号在右边

  每页卡片显示时,默认为有框架并呈立体形状显示在父窗口上。用 setDocumentMode(mode:bool) 方法 设置卡片是否有框架,如果没有框架,则卡片上内容与父窗口看起来是一个整体。

  用 setCornerWidget(widget:QWidget, corent:Qt.Corner) 方法可以 QTabWidget 的右上角、右下角、左上角和左下角处放置控件,例如放置标签、单击按钮等,其中参数 corentQt.Corner 类型的枚举值,可以取值如下:

Qt.Corner.TopRightCorner
Qt.Corner.BottomRightCorner
Qt.Corner.TopLeftCorner
Qt.Corner.BottomLeftCorner

  用 setTabBarAutoHide(hide:bool) 方法可以 设置当只有 1 张卡片时,卡片标题是否自动隐藏

  修改 ui.py 文件的内容。

from PySide6.QtWidgets import QWidget
from PySide6.QtWidgets import QTabWidget, QLabel
from PySide6.QtWidgets import QVBoxLayout
from PySide6.QtGui import QIcon

class MyUi:
    def setupUi(self, window:QWidget):
        window.resize(800, 600)                                                 # 1.设置窗口对象大小
  
        layout = QVBoxLayout(window)                                            # 2.创建垂直布局

        self.tabWidget = QTabWidget(window)                                     # 3.创建选项卡控件对象
        layout.addWidget(self.tabWidget)                                        # 4.添加滚动区域到布局中

        tab_1 = QWidget()                                                       # 5.创建选项卡对象,并添加到选项卡控件对象中
        self.tabWidget.addTab(tab_1, QIcon("assets/images/1.ico"), "选项卡1")

        tab_2 = QWidget()                                                       # 6.创建选项卡对象,并插入选项卡
        self.tabWidget.insertTab(1, tab_2, QIcon("assets/images/1.ico"), "选项卡2")

        tab_3 = QWidget()
        self.tabWidget.addTab(tab_3, "选项卡-3")
  
        self.tabWidget.setTabText(2, "选项卡3")                                  # 7.设置指定选项卡标题文本
        self.tabWidget.setTabIcon(2, QIcon("1.ico"))                            # 8.设置指定索引选项卡图标

        self.tabWidget.setTabsClosable(True)                                    # 9.设置是否可以独立关闭选项卡
        self.tabWidget.setMovable(True)                                         # 10.设置是否可以拖动选项卡
        self.tabWidget.setTabShape(QTabWidget.TabShape.Triangular)              # 11.设置选项卡的形状

        # tabWidget.setCurrentIndex(1)
        self.tabWidget.setCurrentWidget(tab_2)                                  # 12.设置默认选中的选项卡

        self.label = QLabel(window)                                             # 13.创建标签控件,并添加到布局中
        layout.addWidget(self.label)

        label = self.tabWidget.tabText(self.tabWidget.currentIndex())           # 14.获取当前选项卡的标题,并设置标签文本
        self.label.setText(f"你选中了【{label}】选项卡")

  修改 widget.py 文件的内容。

import sys

from PySide6.QtWidgets import QApplication, QWidget

from ui import MyUi

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()                                                      # 1.调用父类Qwidget类的__init__()方法
      
        self.__ui = MyUi()
        self.__ui.setupUi(self)                                                 # 2.初始化页面
  
        self.__ui.tabWidget.currentChanged.connect(self.tabWidget_current_changed)              # 3.关联选项卡控件切换tab页时触发信号
        self.__ui.tabWidget.tabBarClicked.connect(self.taWidget_tabBar_clicked)                 # 4,关联选项卡控件点击tab页时触发信号
        self.__ui.tabWidget.tabCloseRequested.connect(self.tabWidget_tab_close_requested)       # 5.关联选项卡控件关闭tab页时触发信号

    def tabWidget_current_changed(self, index):
        self.__ui.label.setText(f"选项卡被切换了,切换后的选项卡索引为:{index}")

    def taWidget_tabBar_clicked(self, index):
        self.__ui.label.setText(f"当前选项卡的标题被单击了,索引为:{index}")

    def tabWidget_tab_close_requested(self, index):
        self.__ui.label.setText(f"索引为【{index}】的选项卡被关闭了")

if __name__ == "__main__":
    app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例
    window = MyWidget()                                                         # 2.创建一个窗口
    window.show()                                                               # 3.显示窗口
    sys.exit(app.exec())                                                        # 4.进入程序的主循环,并通过exit函数确保主循环安全结束

QTabWidge 在显示选项卡时,如果默认大小显示不下,会自动生成先前和先后的箭头,用户可以通过单击箭头,查看未显示的选项卡;

当删除某个选项卡时,选项卡会自动切换到前一个,因此也会弹出相应的信息提示。

六、栈控件

  控件栈控件 QStackedWidgetQTabWidget 在功能上有些相似。控件栈也是包含多个窗口的控件,但是与 QTabWidget 不同的是,控件栈不是通过卡片管理窗口控件,而是根据需要从多个控件中选择某个窗口作为当前窗口,当前窗口是要显示的窗口,而不是当前的窗口不显示。

  QStackedWidget 类是从 QFrame 继承而来的。用 QStackedWidget 类创建实例对象的方法如下所示:

QStackedWidget(parent:QWidget=None)

  其中 parent窗口 或者 容器 类控件。

  QStackedWidget 类的常用方法如下:

# 实例方法
addWidget(widget:QWidget) -> int                                                # 在末尾添加窗口,并返回索引值
insertWidget(index:int, widget:QWidget) -> int                                  # 在指定索引位置添加窗口
widget(index:int) -> QWidget                                                    # 获取指定索引值的窗口

removeWidget(widget:QWidget) -> None                                            # 删除窗口

currentIndex() -> int                                                           # 获取当前索引值
currentWidget() -> QWidget                                                      # 获取当前窗口

indexOf(widget:QWidget) -> int                                                  # 获取指定窗口的索引值

count() -> int                                                                  # 获取窗口数量

# 槽函数
setCurrentIndex(index:int) -> None                                              # 将索引值为index的窗口设置为当前窗口
setCurrentWidget(widget:QWidget) -> None                                        # 将指定的窗口设置当前窗口

  QStackedWidget 控件最常用的信号及其说明如下:

currentChanged(index:int)                                                       # 窗口改变时发射信号
widgetRemoved(index:int)                                                        # 窗口被移除时发射信号

  修改 ui.py 文件的内容。

from PySide6.QtWidgets import QWidget
from PySide6.QtWidgets import QStackedWidget, QPushButton, QLabel
from PySide6.QtWidgets import QGridLayout

class MyUi:
    def setupUi(self, window:QWidget):
        window.resize(800, 600)                                                 # 1.设置窗口对象大小
  
        layout = QGridLayout(window)                                            # 2.创建垂直布局

        self.stackedWidget = QStackedWidget(window)                             # 3.创建栈控件并添加到布局中
        layout.addWidget(self.stackedWidget, 0, 0, 1, 4)

        self.new_button = QPushButton("新建窗口")                                # 4.创建按钮控件并添加到布局中
        layout.addWidget(self.new_button, 1, 0)

        self.previous_button = QPushButton("上一个")
        layout.addWidget(self.previous_button, 1, 1)

        self.next_button = QPushButton("下一个")
        layout.addWidget(self.next_button, 1, 2)

        self.delete_button = QPushButton("删除窗口")
        layout.addWidget(self.delete_button, 1, 3)

        self.label = QLabel(window)                                             # 5.创建标签控件,并添加到布局中
        layout.addWidget(self.label, 2, 0, 1, 4)

  修改 wiget.py 文件的内容。

import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtWidgets import QTextEdit
from PySide6.QtWidgets import QVBoxLayout

from ui import MyUi

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()                                                      # 1.调用父类Qwidget类的__init__()方法
      
        self.__ui = MyUi()
        self.__ui.setupUi(self)                                                 # 2.初始化页面

        self.__ui.new_button.clicked.connect(self.new_window)                   # 3.关联新建按钮点击时触发信号
        self.__ui.previous_button.clicked.connect(self.privious_window)         # 4.关联上一页按钮点击时触发信号
        self.__ui.next_button.clicked.connect(self.next_window)                 # 5.关联下一页按钮点击时触发信号
        self.__ui.delete_button.clicked.connect(self.delete_window)             # 6.关联删除按钮点击时触发信号

        self.__ui.stackedWidget.currentChanged.connect(self.stackedWidget_current_changed)  # 8.关联栈控件当前页改变时触发信号
        self.__ui.stackedWidget.widgetRemoved.connect(self.stackedWidget_widget_removed)    # 9.关联栈控件移除窗口时触发信号

    def new_window(self):
        widget = QWidget()                                                      # 1.创建窗口控件

        textEdit = QTextEdit(widget)                                            # 2.创建文本编辑框

        layout = QVBoxLayout(widget)                                            # 3.创建垂直布局
        layout.addWidget(textEdit)                                              # 4.添加文本编辑框到布局中

        self.__ui.stackedWidget.addWidget(widget)                               # 5.添加窗口到栈控件中
        self.__ui.stackedWidget.setCurrentWidget(widget)                        # 6.设置当前窗口为栈控件中的第一个窗口

    def privious_window(self):
        count = self.__ui.stackedWidget.count()                                 # 1.获取栈控件的子窗口数量
        if count:                                                               # 2.判断栈控件是否为空
            current_index = self.__ui.stackedWidget.currentIndex()              # 3.获取当前栈控件的索引
            current_index = 0 if current_index == 0 else current_index - 1
            self.__ui.stackedWidget.setCurrentIndex(current_index)              # 4.设置当前栈控件的索引

    def next_window(self):
        count = self.__ui.stackedWidget.count()                                 # 1.获取栈控件的子窗口数量
        if count:                                                               # 2.判断栈控件是否为空
            current_index = self.__ui.stackedWidget.currentIndex()              # 3.获取当前栈控件的索引
            current_index = count if current_index == count else current_index + 1
            self.__ui.stackedWidget.setCurrentIndex(current_index)              # 4.设置当前栈控件的索引

    def delete_window(self):
        count = self.__ui.stackedWidget.count()                                 # 1.获取栈控件的子窗口数量
        if count:
            current_index = self.__ui.stackedWidget.currentIndex()              # 2.获取当前栈控件的索引
            widget = self.__ui.stackedWidget.widget(current_index)              # 3.获取当前栈控件的子窗口
            self.__ui.stackedWidget.removeWidget(widget)                        # 4.删除当前栈控件的子窗口

    def stackedWidget_current_changed(self):
        text = f"你当前选中的是第【{self.__ui.stackedWidget.currentIndex() + 1}】个窗口"
        self.__ui.label.setText(text)                                           # 1.设置标签文本

    def stackedWidget_widget_removed(self, index):
        count = self.__ui.stackedWidget.count()                                 # 1.获取栈控件的子窗口数量
        text = f"你删除了第【{index + 1}】个窗口" if count else "你删除了所有窗口"
        self.__ui.label.setText(text)

if __name__ == "__main__":
    app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例
    window = MyWidget()                                                         # 2.创建一个窗口
    window.show()                                                               # 3.显示窗口
    sys.exit(app.exec())                                                        # 4.进入程序的主循环,并通过exit函数确保主循环安全结束

七、工具盒控件

  工具箱控件 QToolBox 与切换卡控件 QTabWidget 有些类似,也是由多页构成,每页有标题名称。与切换卡不同的是,工具箱的标题是从上到下依次排列,每页的标题呈按钮状态,单击每页的标题,每页的窗口会显示在标题按钮下面;而切换卡的标题是按顺序展开,切换卡的标题面积比卡片窗口的面积小。

  QToolBox 是从 QFrame 类继承而来的。用 QToolBox 类创建实例对象的方法如下所示:

QToolBox(parent:QWidget=None, f:Qt.WindowFlags=Default(Qt.WindowFlags))

  其中 parent窗口 或者 容器 类控件,参数 Qt.WindowFlags 枚举值用于 设置窗口类型

  QToolBox 类的常用方法如下:

# 实例方法
addItem(widget:QWidget, text:str) -> int                                        # 在末尾添加项
addItem(widget:QWidget, icon:QIcon, text:str) -> int                            # 在末尾添加项

insertItem(index:int, widget:QWidget, text:str) -> int                          # 在指定位置插入项
insertItem(index:int, widget:QWidget, icon:QIcon, text:str) -> int              # 在指定位置插入项

widget(index:int) -> QWidget                                                    # 获取指定位置的项
removeItem(index:int) -> None                                                   # 删除指定位置的项

currentIndex() -> int                                                           # 获取当前选中的的项的索引
currentWidget() -> QWidget                                                      # 获取当前选中的项

count() -> int                                                                  # 获取项的数量

indexOf(widget:QWidget) -> int                                                  # 获取指定项的索引

setItemEnabled(index:int, enabled:bool) -> None                                 # 设置指定位置的项是否被激活
isItemEnabled(index:int) -> bool                                                # 获取指定位置的项是否被激活

setItemIcon(index:int, icon:QIcon) -> None                                      # 设置指定位置的项的图标
itemIcon(index:int) -> QIcon                                                    # 获取指定位置的项的图标

setItemText(index:int, text:str) -> None                                        # 设置指定位置的项的文本
itemText(index:int) -> str                                                      # 获取指定位置的项的文本

setItemToolTip(index:int, toolTip:str) -> None                                  # 设置指定位置的项的提示文本
itemToolTip(index:int) -> str                                                   # 获取指定位置的项的提示文本

# 槽方法
setCurrentIndex(index:int) -> None                                              # 根据索引设置当前选中的项
setCurrentWidget(widget:QWidget) -> None                                        # 根据指定窗口设置当前选中的项

  QToolBox 控件常用信号及其说明如下:

currentChanged(index)                                                           # 当前项改变时发射信号

  修改 ui.py 文件的内容。

from PySide6.QtWidgets import QWidget
from PySide6.QtWidgets import QToolBox, QPushButton, QLabel
from PySide6.QtWidgets import QGridLayout

class MyUi:
    def setupUi(self, window:QWidget):
        window.resize(800, 600)                                                 # 1.设置窗口对象大小
  
        layout = QGridLayout(window)                                            # 2.创建垂直布局

        self.toolBox = QToolBox(window)                                         # 3.创建工具箱控件并添加到布局中
        layout.addWidget(self.toolBox, 0, 0, 1, 4)

        self.new_button = QPushButton("新建项")                                  # 4.创建按钮控件对象,并添加到布局中
        layout.addWidget(self.new_button, 1, 0)

        self.previous_button = QPushButton("上一项")
        layout.addWidget(self.previous_button, 1, 1)

        self.next_button = QPushButton("下一项")
        layout.addWidget(self.next_button, 1, 2)

        self.delete_button = QPushButton("删除项")
        layout.addWidget(self.delete_button, 1, 3)

        self.label = QLabel(window)                                             # 5.创建标签控件,并添加到布局中
        layout.addWidget(self.label, 2, 0, 1, 4)

  修改 widget.py 文件的内容。

import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtWidgets import QTextEdit
from PySide6.QtWidgets import QVBoxLayout
from PySide6.QtGui import QIcon

from ui import MyUi

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()                                                      # 1.调用父类Qwidget类的__init__()方法
      
        self.__ui = MyUi()
        self.__ui.setupUi(self)                                                 # 2.初始化页面

        self.__ui.new_button.clicked.connect(self.new_window)                   # 3.关联新建按钮点击时触发信号
        self.__ui.previous_button.clicked.connect(self.privious_window)         # 4.关联上一页按钮点击时触发信号
        self.__ui.next_button.clicked.connect(self.next_window)                 # 5.关联下一页按钮点击时触发信号
        self.__ui.delete_button.clicked.connect(self.delete_window)             # 6.关联删除按钮点击时触发信号

        self.__ui.toolBox.currentChanged.connect(self.toolBox_current_changed)  # 12.关联工具箱控件切换时触发信号

    def new_window(self):
        count = self.__ui.toolBox.count()                                       # 1.获取toolBox控件的子窗口数量

        widget = QWidget()                                                      # 2.创建窗口控件
        textEdit = QTextEdit(widget)                                            # 3.创建文本编辑框

        layout = QVBoxLayout(widget)                                            # 4.创建垂直布局
        layout.addWidget(textEdit)                                              # 5.添加文本编辑框到布局中

        self.__ui.toolBox.addItem(widget, QIcon("assets/images/1.ico"), f"窗口{count + 1}")     # 6.添加窗口到工具箱控件中
        self.__ui.toolBox.setCurrentWidget(widget)                              # 7.设置当前窗口为工具箱控件中的第一个窗口

    def privious_window(self):
        count = self.__ui.toolBox.count()                                       # 1.获取工具箱控件的子窗口数量
        if count:                                                               # 2.判断工具箱控件是否为空
            current_index = self.__ui.toolBox.currentIndex()                    # 3.获取当前工具箱控件的索引
            current_index = 0 if current_index == 0 else current_index - 1
            self.__ui.toolBox.setCurrentIndex(current_index)                    # 4.设置当前工具箱控件的索引

    def next_window(self):
        count = self.__ui.toolBox.count()                                       # 1.获取工具箱控件的子窗口数量
        if count:                                                               # 2.判断工具箱控件是否为空
            current_index = self.__ui.toolBox.currentIndex()                    # 3.获取当前工具箱控件的索引
            current_index = count if current_index == count else current_index + 1
            self.__ui.toolBox.setCurrentIndex(current_index)                    # 4.设置当前工具箱控件的索引

    def delete_window(self):
        count = self.__ui.toolBox.count()                                       # 1.获取工具箱控件的子窗口数量
        if count:
            current_index = self.__ui.toolBox.currentIndex()                    # 2.获取当工具箱控件的索引
            self.__ui.toolBox.removeItem(current_index)                         # 3.删除当工具箱控件的子窗口

    def toolBox_current_changed(self):
        index = self.__ui.toolBox.currentIndex()                                # 1.获取工具箱控件的当前索引
        label = self.__ui.toolBox.itemText(index)                               # 2.获取工具箱控制指定索引的文本
        text = f"你当前选中的是【{label}】项"
        self.__ui.label.setText(text)                                           # 1.设置标签文本

if __name__ == "__main__":
    app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例
    window = MyWidget()                                                         # 2.创建一个窗口
    window.show()                                                               # 3.显示窗口
    sys.exit(app.exec())                                                        # 4.进入程序的主循环,并通过exit函数确保主循环安全结束
posted @ 2025-01-08 22:05  星光映梦  阅读(146)  评论(0)    收藏  举报