27. 基于项的控件

一、基于项的控件

  PySide6 有专门的显示数据的控件和存储数据的模型,可以显示和存储不同形式的数据。显示数据的控件分为两类,一类是基于 (item)的控件,另一类是基于 模型(model)的控件,基于项的控件是基于模型的控件的简便类。基于项的控件把读取到的数据存储到项中,基于模型的控件把数据存储到模型中,或通过模型提供读取数据的接口,然后通过控件把数据模型中的数据或关联的数据显示出来。

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

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

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

  基于项的控件有 列表控件 QListWidget表格控件 QTableWidget树结构控件 QTreeWidget,它们是从基于模型的控件继承而来的,基于模型的控件有 QListViewQTableViewQTreeView,这些控件之间的继承关系如下所示。

基于项和模型控件的继承关系

  QAbstractItemView 类的常用方法:

# 实例方法
setModel(model:QAbstractItemModel) -> None                                      # 设置数据模型
setSelectionModel(selectionModel:QItemSelectionModel) -> None                   # 设置选择模型
setAlternatingRowColors(enable:bool) -> None                                    # 设置交替色

# 槽方法
clearSelection() -> None                                                        # 清空选择

二、列表控件及其项

  列表控件 QListWidget 由一列多行构成,每行称为一个项(item),每个项是一个 QListWidgetItem 对象。可以继承 QListWidgetItem 创建用户自定义的项,也可以先创建 QWidget 实例,在其上添加一些控件,然后把 QWidget 放到 QListWidgetItem 的位置,形成复杂的列表控件。

  列表控件 QListWidget 是从 QListView 类继承而来的,用 QListWidget 类创建列表控件的方法如下所示:

QListWidget(parent:QWidget=None)

  其中 parentQListWidget 列表控件所在的父窗口或控件。

  用 QListWidgetItem 创建列表项的方法如下所示:

QListWidgetItem(listview:QListWidget=None, type:int=QListWidgetItem.Type)
QListWidgetItem(text:str, listview:QListWidget=None, type:int=QListWidgetItem.Type)
QListWidgetItem(icon:Union[QIcon, QPixmap], text:str, listview:QListWidget=None, type:int=QListWidgetItem.Type)

  其中 type 可取 QListWidgetItem.Type(值为 0)或 QListWidgetItem.UserType(值为 1000),前者是默认值,后者是用户自定义类型的最小值。可以用 QListWidgetItem 类创建子类,定义新的类型。

  列表控件 QListWidget 的常用方法如下:

# 实例方法
addItem(item:QListWidgetItem) -> None                                           # 在列表控件中添加项
addItem(label:str) -> None                                                      # 用文本创建并添加项
addItems(labels:Sequence[str]) -> None                                          # 用文本列表创建添加多个项

insertItem(row:int, item:QListWidgetItem) -> None                               # 在列表控件中插入项
insertItem(row:int, label:str) -> None                                          # 用文本创建项并插入项
insertItems(row:int, labels:Sequence[str]) -> None                              # 用文本列表创建项并插入多个项

setCurrentItem(item:QListWidgetItem) -> None                                    # 设置当前项
currentItem() -> QListWidgetItem                                                # 返回当前项

setCurrentRow(row:int) -> None                                                  # 指定第row行为当前行
currentRow() -> int                                                             # 返回当前行

selectedItems() -> List[QListWidgetItem]                                        # 返回选择项的列表

row(item:QListWidgetItem) -> int                                                # 返回当前项的行号
item(row:int) -> QListWidgetItem                                                # 返回指定行的项
itemAt(p:QPoint) -> QListWidgetItem                                             # 返回指定位置的项
itemAt(x:int, y:int) -> QListWidgetItem                                         # 返回指定位置的项

itemFromIndex(index:QModelIndex) -> QListWidgetItem                             # 返回指定索引的项
visualItemRect(item:QListWidgetItem) -> QRect                                   # 返回指定项的矩形

setItemWidget(item:QListWidgetItem, widget:QWidget) -> None                     # 把某控件显示在指定项的位置处
itemWidget(item:QListWidgetItem) -> QWidget                                     # 返回指定项位置处的控件
removeItemWidget(item:QListWidgetItem) -> None                                  # 删除指定项位置处的控件

openPersistentEditor(item:QListWidgetItem) -> None                              # 打开指定项的编辑框,用于编辑文本
isPersistentEditorOpen(item:QListWidgetItem) -> bool                            # 返回指定项的编辑框是否打开
closePersistentEditor(item:QListWidgetItem) -> None                             # 关闭指定项的编辑框

count() -> int                                                                  # 返回项的数量
takeItem(row:int) -> QListWidgetItem                                            # 从列表控件中删除并返回项
findItems(text:str, flags:Qt.MatchFlags) -> List[QListWidgetItem]               # 返回匹配项的列表

setSortingEnabled(enable:bool) -> None                                          # 设置列表控件是否可以排序
isSortingEnabled() -> bool                                                      # 返回列表控件是否可以排序
sortItems(order:Qt.AscendingOrder) -> None                                      # 按照排序方式进行项的排序

supportedDropActions() ->  Qt.DropActions                                       # 返回列表控件支持的拖动和粘贴操作

mimeData(items:Sequence[QListWidgetItem]) -> QMimeData                          # 获取多个项的mime数据QMimeData
mimeTypes() -> List[str]                                                        # 返回mime数据的类型列表

# 槽方法  
clear() -> None                                                                 # 清空列表控件
scrollToItem(item:QListWidgetItem, hint=QAbstractItemView.ScrollHint.EnsureVisible) -> None     # 滚动到指定项,使其可见

  列表控件 QListWidget 的常用信号如下:

currentItemChanged(current:QListWidgetItem, previous:QListWidgetItem)           # 当前项发生改变时发射信号
currentRowChanged(currentRow:int)                                               # 当前行发生改变时发射信号
currentTextChanged(currentText:str)                                             # 当前项的文本发生改变时发射信号
itemActivated(item:QListWidgetItem)                                             # 单击或双击项,使其变成活跃项时发射信号
itemChanged(item:QListWidgetItem)                                               # 项的数据发生改变时发射信号
itemClicked(item:QListWidgetItem)                                               # 单击项时发射信号
itemDoubleClicked(item:QListWidgetItem)                                         # 双击项时发射信号
itemEntered(item:QListWidgetItem)                                               # 光标进入某个项时发射信号
itemPressed(item:QListWidgetItem)                                               # 当鼠标在某个项按下时发射信号
itemSelectionChanged()                                                          # 项的选择状态发生改变时发射信号

  用 setSortingEnabled(bool) 方法 设置是否可以进行排序;用 sortItems(order:Qt.AscendingOrder) 方法 设置排序方法,其中参数 orderQt.AscendingOrder 类型的枚举值,可以取值如下:

Qt.AscendingOrder.AscendingOrder                                                # 升序
Qt.AscendingOrder.DescendingOrder                                               # 降序

  用 findItems(text:str,flags:Qt.MatchFlags) 方法可以 查找满足匹配规则的项 List[QListWidgetItem],其中参数 flagsQt.MatchFlags 类型的枚举值,可以取值如下:

Qt.MatchFlags.MatchExactly
Qt.MatchFlags.MatchFixedString
Qt.MatchFlags.MatchContains
Qt.MatchFlags.MatchStartsWith
Qt.MatchFlags.MatchEndsWith
Qt.MatchFlags.MatchCaseSensitive
Qt.MatchFlags.MatchRegularExpression
Qt.MatchFlags.MatchWildcard
Qt.MatchFlags.MatchWrap
Qt.MatchFlags.MatchRecursive

  用 supportedDropActions() 方法 获取支持的拖放动作 Qt.DropActionQt.DropAction 可以取值如下:

Qt.DropAction.CopyAction                                                        # 复制
Qt.DropAction.MoveAction                                                        # 移动
Qt.DropAction.LinkAction                                                        # 链接
Qt.DropAction.IgnoreAction                                                      # 什么都不做
Qt.DropAction.TargetMoveAction                                                  # 目标对象接管

  列表项 QListWidgetItem 的常用方法如下:

setText(text:str) -> None                                                       # 设置文字
text() -> str                                                                   # 获取文字
setTextAlignment(alignment:Qt.Alignment) -> None                                # 设置文字对齐方式

setIcon(icon:QIcon) -> None                                                     # 设置图标
icon() -> QIcon                                                                 # 获取图标

setToolTip(toolTip:str) -> None                                                 # 设置提示文字
setStatusTip(statusTip:str) -> None                                             # 设置状态提示文字,需激活mouseTracking属性
setWhatsThis(whatsThis:str) -> None                                             # 设置按Shift+F1键的显示文字

setFont(font:QFont) -> None                                                     # 设置字体

setForeground(brush:QColor) -> None                                             # 设置前景色
setBackground(brush:QColor) -> None                                             # 设置背景色

setCheckState(state:Qt.CheckState) -> None                                      # 设置勾选状态
checkState() -> Qt.CheckState                                                   # 获取勾选状态

setFlags(flags:Qt.ItemFlag) -> None                                             # 设置标识

setHidden(hide:bool) -> None                                                    # 设置是否隐藏
isHidden() -> bool                                                              # 获取是否隐藏

setSelected(select:bool) -> None                                                # 设置是否选中
isSelected() -> bool                                                            # 获取是否选中

clone() -> QListWidgetItem                                                      # 克隆一个项
listWidget() -> QListWidget                                                     # 获取列表视图

write(out:QDataStream) -> None                                                  # 将项写入数据流
read(in:QDataStream) -> None                                                    # 从数据流中读取项
setData(role:int, value:Any) -> None                                            # 设置某角色的数据
data(role:int) -> Any                                                           # 获取某角色的数据

  用 setForeground(color:QColor) 方法和 setBackground(color:QColor) 方法可以 设置前景色和背景色,其中参数 QColor 可以取 QBrushQt.BrushStyleQt.GlobalColorQGradientQImageQPixmap

  用 setCheckState(state:Qt.CheckState) 方法 设置项是否处于勾选状态,其中参数 stateQt.CheckState 类型的枚举值,可以取值如下:

Qt.CheckState.Unchecked                                                         # 未勾选
Qt.CheckState.PartiallyChecked                                                  # 部分勾选,如果有子项
Qt.CheckState.Checked                                                           # 勾选

  用 setFlags(flag:Qt.ItemFlags) 方法 设置项的标识,其中参数 flagQt.ItemFlags 类型的枚举值,可以取的值如下所示:

Qt.ItemFlag.NoItemFlags                                                         # 没有标识符
Qt.ItemFlag.ItemIsSelectable                                                    # 项可选
Qt.ItemFlag.ItemIsEditable                                                      # 项可编辑
Qt.ItemFlag.ItemIsDragEnabled                                                   # 项可以拖拽
Qt.ItemFlag.ItemIsDropEnabled                                                   # 项可以拖放
Qt.ItemFlag.ItemIsUserCheckable                                                 # 项可以勾选
Qt.ItemFlag.ItemIsEnabled                                                       # 项被激活
Qt.ItemFlag.ItemIsAutoTristate                                                  # 如有子项,则有第三种状态
Qt.ItemFlag.ItemNeverHasChildren                                                # 项没有子项
Qt.ItemFlag.ItemIsUserTristate                                                  # 可在三种状态之际爱你循环切换

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

from PySide6.QtWidgets import QWidget
from PySide6.QtWidgets import QLabel, QListWidget
from PySide6.QtWidgets import QVBoxLayout

class MyUi:
    def setupUi(self, window:QWidget):
        window.resize(800, 600)                                                 # 1.设置窗口对象大小

        layout = QVBoxLayout(window)                                            # 2.创建一个垂直布局
  
        self.listWidget = QListWidget()                                         # 3.创建列表控件对象,并添加到布局中
        layout.addWidget(self.listWidget)

        self.listWidget.addItem("木之本樱")                                      # 4.向列表控件中添加值
        self.listWidget.addItems(["御坂美琴", "夏娜", "赤瞳", "黑瞳"])

        self.listWidget.insertItem(3, "涂山苏苏")                                # 5.向指定索引处插入值
        self.listWidget.insertItems(3, ["白钰袖", "风铃儿"])

        item = self.listWidget.item(1)                                          # 6.获取指定项

        item.setToolTip("超电磁炮")                                              # 7.设置指定项的提示信息
  
        self.listWidget.setCurrentItem(item)                                    # 8.设置当前项
        self.listWidget.setSelectionMode(QListWidget.SelectionMode.ExtendedSelection)       # 9.设置选择模式
        self.listWidget.setSelectionBehavior(QListWidget.SelectionBehavior.SelectItems)     # 10.设置选择项的方式
        self.listWidget.setViewMode(QListWidget.ViewMode.IconMode)              # 11.设置显示模式
        self.listWidget.setWordWrap(True)                                       # 12.设置是否自动换行

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

  修改 widget.py 文件的内容。

import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtWidgets import QListWidgetItem

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.listWidget.currentItemChanged.connect(self.listWidget_current_item_changed)   # 3.当前项改变了触发信号
        self.__ui.listWidget.itemClicked.connect(self.listWidget_item_clicked)                  # 4.当前项被点击触发信号
        self.__ui.listWidget.itemActivated.connect(self.listWidget_item_activated)              # 5.当前项被激活触发信号
        self.__ui.listWidget.itemEntered.connect(self.listWidget_item_entered)                  # 6.当前项进入时触发信号
        self.__ui.listWidget.itemPressed.connect(self.listWidget_item_pressed)                  # 7.当前项按下时触发信号

    def listWidget_current_item_changed(self, current:QListWidgetItem, previous:QListWidgetItem):
        self.__ui.label.setText(f"当前项被改变了,从【{previous.text()}】变成了【{current.text()}】")

    def listWidget_item_clicked(self, item:QListWidgetItem):
        self.__ui.label.setText(f"【{item.text()}】项被单击了")

    def listWidget_item_activated(self, item:QListWidgetItem):
        self.__ui.label.setText(f"【{item.text()}】项被激活了")

    def listWidget_item_entered(self, item:QListWidgetItem):
        self.__ui.label.setText(f"鼠标移入【{item.text()}】项")

    def listWidget_item_pressed(self, item:QListWidgetItem):
        self.__ui.label.setText(f"【{item.text()}】项被按下了")
  
if __name__ == "__main__":
    app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例
    window = MyWidget()                                                         # 2.创建一个窗口
    window.show()                                                               # 3.显示窗口
    sys.exit(app.exec())                                                        # 4.进入程序的主循环并通过exit()函数确保主循环安全结束

三、表格控件及其项

  表格控件 QTableWidget 是从 QTableView 类继承而来的,由多行多列构成,并且含有行表头和列表头,表格控件的每个单元格称为一个项(item),每个项是一个 QTableWidgetItem 对象,可以设置每个项的文本、图标、颜色、前景色和背景色等属性。

  用 QTableWidget 类创建表格控件的方法如下所示:

QTableWidget(parent:QWidget=None)
QTableWidget(rows:int, columns:int, parent:QWidget=None)

  其中 parent 是表格控件 QTableWidget 所在的父窗口或控件, rowscolumns 分别 指定表格对象的行和列的数量

  用 QTableWidgetItem 创建表格项的方法如下所示:

QTableWidgetItem(type=QTableWidgetItem.Type)
QTableWidgetItem(text:str, type=QTableWidgetItem.Type)
QTableWidgetItem(icon:QIcon, text:str, type=QTableWidgetItem.Type)

  其中 type 可取 QTableWidgetItem.Type(值为 0)或 QTableWidgetItem.UserType(值为 1000),前者是默认值,后者是用户自定义类型的最小值。可以用 QTableWidgetItem 类创建子类,定义新表格项。

  QTableWidget 类常用方法如下:

# 实例方法
setRowCount(rows:int) -> None                                                   # 设置行数
rowCount() -> int                                                               # 获取行数

setColumnCount(columns:int) -> None                                             # 设置列数
columnCount() -> int                                                            # 获取列数

setItem(row:int, column:int, item:QTableWidgetItem) -> None                     # 在指定行和列处设置表格项
takeItem(row:int, column:int) -> QTableWidgetItem                               # 移除并返回指定表格项

setCurrentCell(row:int, column:int) -> None                                     # 设置当前单元格
setCurrentItem(item:QTableWidgetItem) -> None                                   # 设置当前的表格项
currentItem() -> QTableWidgetItem                                               # 返回当前的表格项
currentRow() -> int                                                             # 返回当前行号
currentColumn() -> int                                                          # 返回当前列号

row(item:QTableWidgetItem) -> int                                               # 返回指定表格项的行号
column(item:QTableWidgetItem) -> int                                            # 返回指定表格项的列号

setHorizontalHeaderItem(column:int, item:QTableWidgetItem) -> None              # 设置水平表头
setHorizontalHeaderLabels(labels:Sequence[str]) -> None                         # 用字符串序列设置水平表头
horizontalHeaderItem(column:int) -> QTableWidgetItem                            # 获取水平表头的表格项
takeHorizontalHeaderItem(column:int) -> QTableWidgetItem                        # 移除并返回水平表头的表格项

setVerticalHeaderItem(row:int, item:QTableWidgetItem) -> None                   # 设置垂直表头
setVerticalHeaderLabels(labels:Sequence[str]) -> None                           # 用字符串序列设置垂直表头
verticalHeaderItem(row:int) -> QTableWidgetItem                                 # 获取垂直表头的表格项
takeVerticalHeaderItem(row:int) -> QTableWidgetItem                             # 移除并返回垂直表头的表格项

editItem(item:QTableWidgetItem) -> None                                         # 编辑表格项

findItems(text:str, flags:Qt.MatchFlg) -> List[QTableWidgetItem]                # 获取满足条件的表格项列表
item(row:int, column:int) -> QTableWidgetItem                                   # 获取指定行和列处的表格项
itemAt(p:QPoint) -> QTableWidgetItem                                            # 获取指定位置处的表格项
itemAt(x:int, y:int) -> QTableWidgetItem                                        # 获取指定位置处的表格项

openPersistentEditor(item:QTableWidgetItem) -> None                             # 打开指定项的编辑框,用于编辑文本
isPersistentEditorOpen(item:QTableWidgetItem) -> bool                           # 返回指定项的编辑框是否打开
closePersistentEditor(item:QTableWidgetItem) -> None                            # 关闭指定项的编辑框

selectedItems() -> List[QTableWidgetItem]                                       # 返回选择项的列表

setCellWidget(row:int, column:int, widget:QWidget) -> None                      # 设置单元格的控件
cellWidget(row:int, column:int) -> QWidget                                      # 获取单元格的控件
removeCellWidget(row:int, column:int) -> None                                   # 移除单元格的控件

setSortingEnabled(enable:bool) -> None                                          # 设置表格控件是否可以排序
isSortingEnabled() -> bool                                                      # 返回表格控件是否可以排序
sortItems(order:Qt.SortOrder=Qt.AscendingOrder) -> None                         # 按照排序方式进行项的排序

supportedDropActions() -> Qt.DropAction                                         # 返回支持的拖动和粘贴操作

# 槽函数  
insertRow(row:int) -> None                                                      # 在指定位置插入行
removeRow(row:int) -> None                                                      # 移除指定行
insertColumn(column:int) -> None                                                # 在指定位置插入列
removeColumn(column:int) -> None                                                # 移除指定列
clear() -> None                                                                 # 清空表格项和表头的内容
clearContents() -> None                                                         # 清空表格项的内容
scrollToItem(item:QTableWidgetItem, hint=QAbstractItemView.ScrollHint.EnsureVisible) -> None    # 滚动到指定项,使其可见

  QTableWidget 类常用信号如下:

cellActivated(row:int, column:int)                                              # 单元格活跃时发射信号
cellChanged(row:int, column:int)                                                # 单元格数据变化时发射信号
cellClicked(row:int, column:int)                                                # 单击单元格时发射信号
cellDoubleClicked(row:int, column:int)                                          # 双击单元格时发射信号
cellEntered(row:int, column:int)                                                # 光标进入单元格时发射信号
cellPressed(row:int, column:int)                                                # 光标在单元格按下按键时发射信号

currentCellChanged(currentRow:int, currentColumn:int, previousRow:int, previousColumn:int)  # 当前单元格改变时发射信号
currentItemChanged(current:QTableWidgetItem, previous:QTableWidgetItem)         # 当前表格项改变时发射信号

itemActivated(item:QTableWidgetItem)                                            # 表格项活跃时发射信号
itemChanged(item:QTableWidgetItem)                                              # 表格项数据变化时发射信号
itemClicked(item:QTableWidgetItem)                                              # 单击表格时发射信号      
itemDoubleClicked(item:QTableWidgetItem)                                        # 双击表格时发射信号
itemEntered(item:QTableWidgetItem)                                              # 光标进入表格时发射信号
itemPressed(item:QTableWidgetItem)                                              # 光标在表格按下按键时发射信号
itemSelectionChanged()                                                          # 选择的表格项发射改变时发射信号

  QTableWidgetItem 类常用方法如下:

setText(text:str) -> None                                                       # 设置文字
text() -> str                                                                   # 获取文字
setTextAlignment(alignment:Qt.Alignment) -> None                                # 设置文字对齐方式

setIcon(icon:QIcon) -> None                                                     # 设置图标
icon() -> QIcon                                                                 # 获取图标

setToolTip(toolTip:str) -> None                                                 # 设置提示文字
setStatusTip(statusTip:str) -> None                                             # 设置状态提示文字,需激活mouseTracking属性
setWhatsThis(whatsThis:str) -> None                                             # 设置按Shift+F1键的显示文字

setFont(font:QFont) -> None                                                     # 设置字体

setForeground(brush:QColor) -> None                                             # 设置前景色
setBackground(brush:QColor) -> None                                             # 设置背景色

setCheckState(state:Qt.CheckState) -> None                                      # 设置勾选状态
checkState() -> Qt.CheckState                                                   # 获取勾选状态

setFlags(flags:Qt.ItemFlag) -> None                                             # 设置标识
setSelected(select:bool) -> None                                                # 设置是否选中
isSelected() -> bool                                                            # 获取是否选中

clone() -> QTableWidgetItem                                                     # 克隆一个项

tableWidget() -> QTableWidget                                                   # 获取表格视图

write(out:QDataStream) -> None                                                  # 将项写入数据流
read(in:QDataStream) -> None                                                    # 从数据流中读取项
setData(role:int, value:Any) -> None                                            # 设置某角色的数据
data(role:int) -> Any                                                           # 获取某角色的数据

  修改 ui.py 文件的内容。

from PySide6.QtWidgets import QWidget
from PySide6.QtWidgets import QLabel, QTableWidget, QTableWidgetItem
from PySide6.QtWidgets import QVBoxLayout

class MyUi:
    def setupUi(self, window:QWidget):
        window.resize(800, 600)                                                 # 1.设置窗口对象大小

        layout = QVBoxLayout(window)                                            # 2.创建一个垂直布局
  
        self.tableWidget = QTableWidget()                                       # 3.创建一个表格控件,并添加到布局中
        layout.addWidget(self.tableWidget)

        self.tableWidget.setAlternatingRowColors(True)                          # 4.设置表格颜色交错显示

        self.tableWidget.setRowCount(15)                                        # 5.设置表格的行数
        self.tableWidget.setColumnCount(10)                                     # 6.设置表格的列数

        self.tableWidget.setHorizontalHeaderLabels(["部门", "姓名", "性别", "年龄"])    # 7.设置表格的水平表头

        self.tableWidget.setVerticalHeaderLabels(["1", "2", "3"])               # 8.设置表格的垂直表头
  

        department_list = ["魔法部", "超能力部"]
        person_list = [
            {"department": department_list[0], "name": "木之本樱", "gender": "女", "age": 10},
            {"department": department_list[0], "name": "夏娜", "gender": "女", "age": 15},
            {"department": department_list[1], "name": "御坂美琴", "gender": "女", "age": 14},
        ]

        for i in range(0, len(person_list)):
            j = 0
            for key, value in person_list[i].items():
                item = QTableWidgetItem(str(value))                             # 9.创建表格项
                self.tableWidget.setItem(i, j, item)                            # 10.设置单元格的内容
                j += 1

        # 11.合并单元格
        self.tableWidget.setSpan(0, 0, 2, 1)

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

  修改 widget.py 文件的内容。

import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtWidgets import QTableWidgetItem

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.tableWidget.itemClicked.connect(self.tableWidget_item_clicked)                        # 3.单击表格项时激活信号
        self.__ui.tableWidget.itemDoubleClicked.connect(self.tableWidget_item_double_clicked)           # 4.双击表格项时激活信号
        self.__ui.tableWidget.itemChanged.connect(self.tableWidget_item_changed)                        # 5.表格项数据改变时激活信号
        self.__ui.tableWidget.itemSelectionChanged.connect(self.tableWidget_item_selection_changed)     # 6.选择的表格项改变时激活信号

        self.__ui.tableWidget.currentCellChanged.connect(self.tableWidget_current_cell_changed)         # 7.当前表格项改变时激活信号

    def tableWidget_item_clicked(self, item:QTableWidgetItem):
        self.__ui.label.setText(f"【{item.text()}】表格项被单击了")

    def tableWidget_item_double_clicked(self, item:QTableWidgetItem):
        self.__ui.label.setText(f"【{item.text()}】表格项被双击了")

    def tableWidget_item_changed(self, item:QTableWidgetItem):
        self.__ui.label.setText(f"【{item.text()}】表格项内容被更改了")

    def tableWidget_item_selection_changed(self):
        self.__ui.label.setText("你选中的表格项更改了")

    def tableWidget_current_cell_changed(self, current_row:int, current_column:int, previous_row:int, previsou_column:int):
        previous_item = self.__ui.tableWidget.item(previous_row, previsou_column)
        current_item = self.__ui.tableWidget.item(current_row, current_column)
        if previous_item:
            previous_item_text = previous_item.text()
        else:
            previous_item_text = None
        current_item_text = current_item.text()
        self.__ui.label.setText(f"你选中的单元格从【{previous_item_text}】变成了【{current_item_text}】")
  
if __name__ == "__main__":
    app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例
    window = MyWidget()                                                         # 2.创建一个窗口
    window.show()                                                               # 3.显示窗口
    sys.exit(app.exec())                                                        # 4.进入程序的主循环并通过exit()函数确保主循环安全结束

四、树控件及其项

  树结构控件 QTreeWidget 继承自 QTreeView 类,它是 QTreeView 的便利类。树结构控件由 1 列或多列构成,没有行的概念。

  树结构控件有 1 个或多个顶层项,顶层项下面有任意多个子项,子项下面还可以有子项,顶层项没有父项。顶层项和子项都是 QTreeWidgetItem,每个 QTreeWidgetItem 可以定义在每列显示的文字和图标,一般应在第 1 列中定义文字或图标,其它列中是否设置文字和图标,需要用户视情况而定。可以把每个项理解成树结构控件的一行,只不过行之间有层级关系,可以折叠和展开。

  用 QTreeWidget 类创建树结构控件的方法如下。

QTreeWidget(parent:QWidget=None)

  其中 parentQTreeWidget 树结构控件所在的父窗口或控件。

  用 QTreeWidgetItem 类创建树结构项的方法如下。

QTreeWidgetItem(type=QTreeWidgetItem.Type)
QTreeWidgetItem(strings:Sequence[str], type=QTreeWidgetItem.Type)
QTreeWidgetItem(treeview:QTreeWidget, type=QTreeWidgetItem.Type)
QTreeWidgetItem(treeview:QTreeWidget, strings:Sequence[str], type=QTreeWidgetItem.Type)
QTreeWidgetItem(parent:QTreeWidgetItem, type=QTreeWidgetItem.Type)
QTreeWidgetItem(parent:QTreeWidgetItem, strings:Sequence[str], type=QTreeWidgetItem.Type)
QTreeWidgetItem(parent:QTreeWidgetItem, after:QTreeWidgetItem, type=QTreeWidgetItem.Type)

  其中 Sequence[str]字符串序列,是各列上的文字。第 1 个参数是 QTreeWidget 时表示 项追加到树结构控件中,这时,新创建的项是顶层项。第 1 个参数是 QTreeWidgetItem 表示 父项,这时,新创建的项作为子项追加到父项下面;第 2 个参数是 QTreeWidgetItem 时表示 新创建的项插入到该项的后面type 可以取 QTreeWidgetItem.Type(值是 0)或 QTreeWidgetItem.UserType(值是 1000,自定义类型的最小值)。

  QTreeWidget 类常用方法如下:

# 实例方法
setColumnCount(columns:int) -> None                                             # 设置列数
columnCount() -> int                                                            # 获取列数

currentColumn() -> int                                                          # 返回当前列

setColumnWidth(column:int, width:int) -> None                                   # 设置列宽  

setColumnHidden(column:int, hide:bool) -> None                                  # 设置列是否隐藏

addTopLevelItem(item:QTreeWidgetItem) -> None                                   # 添加顶层项
addTopLevelItems(items:Sequence[QTreeWidgetItem]) -> None                       # 添加多个顶层项  

insertTopLevelItem(index:int, item:QTreeWidgetItem) -> None                     # 插入顶层项
insertTopLevelItems(index:int, items:Sequence[QTreeWidgetItem]) -> None         # 插入多个顶层项

takeTopLevelItem(index:int) -> QTreeWidgetItem                                  # 移除并获取顶层项

topLevelItem(index:int) -> QTreeWidgetItem                                      # 返回索引是index的顶层项
topLevelItemCount() -> int                                                      # 返回顶层项的数量
indexOfTopLevelItem(item:QTreeWidgetItem) -> int                                # 返回顶层项的索引

setCurrentItem(item:QTreeWidgetItem) -> None                                    # 把指定的项设置为当前项
setCurrentItem(item:QTreeWidgetItem, column:int) -> None                        # 设置当前项和当前列
currentItem() -> QTreeWidgetItem                                                # 获取当前项

editItem(item:QTreeWidgetItem, column:int=0) -> None                            # 编辑表格项
openPersistentEditor(item:QTreeWidgetItem, column:int) -> None                  # 打开指定项的编辑框,用于编辑文本
isPersistentEditorOpen(item:QTreeWidgetItem, column:int) -> bool                # 返回指定项的编辑框是否打开
closePersistentEditor(item:QTreeWidgetItem, column:int) -> None                 # 关闭指定项的编辑框

findItems(text:str, flags:Qt.MatchFlg, column:int=0) -> List[QTreeWidgetItem]   # 获取满足条件项的列表

setHeaderItem(item:QTreeWidgetItem) -> None                                     # 设置表头
setHeaderLabel(label:str) -> None                                               # 设置表头的第一列文字

itemAt(p:QPoint) -> QTableWidgetItem                                            # 获取指定位置处的表格项
itemAt(x:int, y:int) -> QTableWidgetItem                                        # 获取指定位置处的表格项

invisibleRootItem() -> QTreeWidgetItem                                          # 获取根项
itemAbove(item:QTreeWidgetItem) -> QTreeWidgetItem                              # 返回指定项之前的项
itemBelow(item:QTreeWidgetItem) -> QTreeWidgetItem                              # 返回指定项之后的项

selectedItems() -> List[QTreeWidgetItem]                                        # 返回选择项的列表

setItemWidget(item:QTreeWidgetItem, column:int, widget:QWidget) -> None         # 在指定项的指定列设置控件
itemWidget(item:QTreeWidgetItem, column:int) -> QWidget                         # 获取项上的控件
removeItemWidget(item:QTreeWidgetItem, column:int) -> None                      # 移除项上的控件

# 槽函数  
scrollToItem(item:QTreeWidgetItem, hint=QAbstractItemView.ScrollHint.EnsureVisible) -> None     # 滚动到指定项,使其可见
collapseItem(item:QTreeWidgetItem) -> None                                      # 折叠项
collapseAll() -> None                                                           # 折叠所有项
expandItem(item:QTreeWidgetItem) -> None                                        # 展开项
expandAll() -> None                                                             # 展开所有项
clear() -> None                                                                 # 清空所有项

  QTreeWidget 类常用信号如下:

currentItemChanged(current:QTreeWidgetItem, previous:QTreeWidgetItem)           # 当前项改变时发射信号
itemActivated(item:QTreeWidgetItem, column:int)                                 # 项活跃时发射信号
itemChanged(item:QTreeWidgetItem, column:int)                                   # 项数据变化时发射信号
itemClicked(item:QTreeWidgetItem, column:int)                                   # 单击项时发射信号  
itemDoubleClicked(item:QTreeWidgetItem, column:int)                             # 双击项时发射信号
itemEntered(item:QTreeWidgetItem, column:int)                                   # 光标进入项时发射信号
itemPressed(item:QTreeWidgetItem, column:int)                                   # 在项上按下按键时发射信号
itemExpanded(item:QTreeWidgetItem)                                              # 展开项时发射信号
itemCollapsed(item:QTreeWidgetItem)                                             # 折叠项时发射信号
itemSelectionChanged()                                                          # 选择的项发射改变时发射信号

  QTreeWidgetItem 类常用方法如下:

addChild(child:QTreeWidgetItem) -> None                                         # 添加子项
addChildren(children:Sequence[QTreeWidgetItem]) -> None                         # 添加多个子项

insertChild(index:int, child:QTreeWidgetItem) -> None                           # 插入子项
insertChildren(index:int, children:Sequence[QTreeWidgetItem]) -> None           # 插入多个子项

child(index:int) -> QTreeWidgetItem                                             # 获取子项
childCount() -> int                                                             # 获取子项数量

takeChild(index:int) -> QTreeWidgetItem                                         # 移除并返回子项
takeChildren() -> List[QTreeWidgetItem]                                         # 移除并返回所有子项
removeChild(child:QTreeWidgetItem) -> None                                      # 移除子项

parent() -> QTreeWidgetItem                                                     # 获取父项
treeWidget() -> QTreeWidget                                                     # 获取树视图
  
setText(column:int, text:str) -> None                                           # 设置文字
text(column:int) -> str                                                         # 获取文字

setTextAlignment(column:int, alignment:Qt.Alignment) -> None                    # 设置文字对齐方式

setIcon(column:int, icon:QIcon) -> None                                         # 设置图标
icon(column:int) -> QIcon                                                       # 获取图标

setToolTip(column:int, toolTip:str) -> None                                     # 设置提示文字
setStatusTip(column:int, statusTip:str) -> None                                 # 设置状态提示文字,需激活mouseTracking属性
setWhatsThis(column:int, whatsThis:str) -> None                                 # 设置按Shift+F1键的显示文字

setFont(column:int, font:QFont) -> None                                         # 设置字体
font(column:int) -> QFont                                                       # 获取字体

setForeground(column:int, brush:QColor) -> None                                 # 设置前景色
setBackground(column:int, brush:QColor) -> None                                 # 设置背景色

setCheckState(column:int, state:Qt.CheckState) -> None                          # 设置勾选状态
checkState(column:int) -> Qt.CheckState                                         # 获取勾选状态

setFlags(flags:Qt.ItemFlag) -> None                                             # 设置标识

setSelected(select:bool) -> None                                                # 设置是否选中
isSelected() -> bool                                                            # 获取是否选中

setHidden(hide:bool) -> None                                                    # 设置是否隐藏

setDisabled(disabled:bool) -> None                                              # 设置是否禁用
isDisabled() -> bool                                                            # 获取是否禁用

setExpanded(expand:bool) -> None                                                # 设置是否展开
isExpanded() -> bool                                                            # 获取是否展开

setFirstColumnSpanned(span:bool) -> None                                        # 设置是否只显示第一列的内容
setChildIndicatorPolicy(policy:QTreeWidgetItem.ChildIndicatorPolicy) -> None    # 设置展开/折叠标识的显示策略
childIndicatorPolicy() -> QTreeWidgetItem.ChildIndicatorPolicy                  # 获取展开策略
  
columnCount() -> int                                                            # 获取列数
indexOfChild(child:QTreeWidgetItem) -> int                                      # 获取子项的索引
sortChildren(column:int, order:Qt.SortOrder) -> None                            # 对子项进行排序

setData(column:int, role:int, value:Any) -> None                                # 设置某角色的数据
data(column:int, role:int) -> Any                                               # 获取某角色的数据

  修改 ui.py 文件的内容。

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

class MyUi:
    def setupUi(self, window:QWidget):
        window.resize(800, 600)                                                 # 1.设置窗口对象大小

        layout = QVBoxLayout(window)                                            # 2.创建一个垂直布局
  
        self.treeWidget = QTreeWidget()                                         # 3.创建树控件,并添加到布局中
        layout.addWidget(self.treeWidget)

        self.treeWidget.setSortingEnabled(True)                                 # 4.设置单击头部时是否可以排序
        self.treeWidget.setAlternatingRowColors(True)                           # 5.设置每间隔一行颜色是否一致

        self.treeWidget.setSelectionBehavior(QTreeWidget.SelectionBehavior.SelectItems)     # 6.设置选中方式
        self.treeWidget.setSelectionMode(QTreeWidget.SelectionMode.ExtendedSelection)       # 7.设置选中模式

        self.treeWidget.setColumnCount(10)                                       # 8.设置树结构中的列数

        self.treeWidget.setHeaderLabels(["部门", "姓名", "性别", "年龄"])           # 9.设置列标题名

        department_list = ["魔法部", "超能力部"]
        person_list = [
            {"name": "木之本樱", "gender": "女", "age": 10, "department": department_list[0]},
            {"name": "御坂美琴", "gender": "女", "age": 14, "department": department_list[1]},
            {"name": "夏娜", "gender": "女", "age": 15, "department": department_list[0]},
        ]

        for department in department_list:
            # 一级节点
            department_item = QTreeWidgetItem(self.treeWidget)                  # 10.创建一级节点  
            department_item.setText(0, department)                              # 11.设置一级节点的文本
            self.treeWidget.addTopLevelItem(department_item)                    # 12.添加顶级节点

            for person in person_list:
                # 二级节点
                if person["department"] == department:
                    person_item = QTreeWidgetItem(department_item)              # 13.创建二级节点
                    person_item.setText(0, "")                                  # 14.设置节点的文本
                    person_item.setIcon(0, QPixmap("1.ico"))                    # 15.设置节点的图标
                    person_item.setCheckState(0, Qt.CheckState.Unchecked)       # 16.设置节点的选中状态

                    i = 1
                    for key, value in person.items():
                        if not key == "department":
                            person_item.setText(i, str(value))
                            if value == "木之本樱":
                                person_item.setCheckState(0, Qt.CheckState.Checked) # 17.设置选中状态
                            i += 1

        self.treeWidget.expandAll()                                             # 18.展开所有节点

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

  修改 widget.py 文件的内容。

import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtWidgets import QTreeWidgetItem

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.treeWidget.itemClicked.connect(self.treeWidget_item_clicked)                      # 3.单击树节点时激活信号
        self.__ui.treeWidget.itemDoubleClicked.connect(self.treeWidget_item_double_clicked)         # 4.双击树节点时激活信号
        self.__ui.treeWidget.itemExpanded.connect(self.treeWidget_item_expanded)                    # 5.展开树节点时激活信号
        self.__ui.treeWidget.itemCollapsed.connect(self.treeWidget_item_collapsed)                  # 6.折叠树节点时激活信号

    def treeWidget_item_double_clicked(self, item:QTreeWidgetItem, column:int):
        self.__ui.label.setText(f"你双击了【{item.text(column)}】")

    def treeWidget_item_clicked(self, item:QTreeWidgetItem, column:int):
        self.__ui.label.setText(f"你单击了【{item.text(column)}】")

    def treeWidget_item_expanded(self, item:QTreeWidgetItem):
        self.__ui.label.setText(f"你展开了【{item.text(0)}】项")

    def treeWidget_item_collapsed(self, item:QTreeWidgetItem):
        self.__ui.label.setText(f"你收缩了【{item.text(0)}】项")
  
if __name__ == "__main__":
    app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例
    window = MyWidget()                                                         # 2.创建一个窗口
    window.show()                                                               # 3.显示窗口
    sys.exit(app.exec())                                                        # 4.进入程序的主循环并通过exit()函数确保主循环安全结束
posted @ 2025-01-15 20:09  星光映梦  阅读(131)  评论(0)    收藏  举报