Skip to main content

基于项的控件

QListWidgetItem类

【实例1-1】 创建一个窗口,该窗口包含一个列表控件。要求在列表控件中显示项,设置背景色

image-20250414212651864

代码如下:

import sys
from PySide6.QtGui import QFont
from PySide6.QtWidgets import (
QApplication,
QWidget,
QVBoxLayout,
QListWidget,
QPushButton,
QHBoxLayout,
QInputDialog,
QLineEdit,
QMessageBox,
)


class Window(QWidget):
def __init__(self):
super().__init__()
self.setGeometry(200, 200, 560, 260)
self.setWindowTitle("QListWidget")

# 创建垂直布局并设置为当前控件的布局方式
vbox = QVBoxLayout()
self.setLayout(vbox)

# 创建列表控件
self.listwidget = QListWidget()
self.listwidget.setFont(QFont("黑体", 14))
self.listwidget.setStyleSheet("background-color:yellowgreen")
# 添加到布局控件中
vbox.addWidget(self.listwidget)

# 插入项
self.listwidget.insertItem(0, "python")
self.listwidget.insertItem(1, "go")
self.listwidget.insertItem(2, "c++")


if __name__ == "__main__":
app = QApplication(sys.argv)
win = Window()
win.show()
sys.exit(app.exec())

【实例1-2】 创建一个窗口,该窗口包含一个列表控件、4个按钮控件。这4个按钮分别实现添加项、编辑项、删除项、排序的作用。

image-20250414213634547

代码如下:

import sys
from PySide6.QtGui import QFont
from PySide6.QtWidgets import (
QApplication,
QWidget,
QVBoxLayout,
QListWidget,
QPushButton,
QHBoxLayout,
QInputDialog,
QLineEdit,
QMessageBox,
)

class Window(QWidget):
def __init__(self):
super().__init__()
self.setGeometry(200, 200, 560, 260)
self.setWindowTitle("QListWidget QListWidgetItem")

vbox = QVBoxLayout()
self.setLayout(vbox)
# 创建4个按钮
btn_add = QPushButton("添加")
btn_edit = QPushButton("编辑")
btn_remove = QPushButton("删除")
btn_sort = QPushButton("排序")

hbox = QHBoxLayout()
hbox.addWidget(btn_add)
hbox.addWidget(btn_edit)
hbox.addWidget(btn_remove)
hbox.addWidget(btn_sort)
vbox.addLayout(hbox)
# 使用信号/槽
btn_add.clicked.connect(self.add_item)
btn_edit.clicked.connect(self.edit_item)
btn_remove.clicked.connect(self.remove_item)
btn_sort.clicked.connect(self.sort_item)
hbox.addWidget(btn_add)
hbox.addWidget(btn_edit)
hbox.addWidget(btn_remove)
hbox.addWidget(btn_sort)

# 创建列表控件
self.listwidget = QListWidget()
self.listwidget.setFont(QFont("黑体", 14))
vbox.addWidget(self.listwidget)

def add_item(self):
row = self.listwidget.currentRow()
title = "添加项"
data, ok = QInputDialog.getText(self, title, title) # 弹出对话框
if ok and data is not None:
self.listwidget.insertItem(row, data)

def edit_item(self):
item = self.listwidget.currentItem()
if item is not None:
title = "编辑项"
data, ok = QInputDialog.getText(
self, title, title, QLineEdit.EchoMode.Normal, item.text()
)
if ok and data is not None:
item.setText(data)

def remove_item(self):
row = self.listwidget.currentRow()
item = self.listwidget.item(row)
if item == None:
return
title1 = "删除项"
title2 = "确定要删除?"
reply = QMessageBox.question(
self, title1, title2, QMessageBox.Yes | QMessageBox.No
)
if reply == QMessageBox.Yes:
self.listwidget.takeItem(row)

def sort_item(self):
self.listwidget.sortItems()


if __name__ == "__main__":
app = QApplication(sys.argv)
win = Window()
win.show()
sys.exit(app.exec())

【实例1-3】 创建一个窗口,该窗口包含一个列表控件。在列表控件中右击会弹出上下文菜单,菜单命令包含添加、编辑、删除、全选、反选、全不选。

listwidget

代码如下:

"""
创建一个窗口,该窗口包含一个列表控件。在列表控件中右击会弹出上下文菜单,菜单命令包含添加、编辑、删除、全选、反选、全不选
"""

import sys
from PySide6.QtGui import QFont
from PySide6.QtWidgets import (
QApplication,
QWidget,
QVBoxLayout,
QListWidget,
QPushButton,
QHBoxLayout,
QInputDialog,
QLineEdit,
QMessageBox,
QMenu,
)
from PySide6.QtCore import Qt


class Window(QWidget):
def __init__(self):
super().__init__()
self.setGeometry(200, 200, 560, 260)
self.setWindowTitle("QListWidget QListWidgetItem")

vbox = QVBoxLayout()
self.setLayout(vbox)

# 创建列表控件
self.listwidget = QListWidget()
self.listwidget.setFont(QFont("黑体", 14))
vbox.addWidget(self.listwidget)

def contextMenuEvent(self, event):
"""在PyQt中,contextMenuEvent用于处理右键菜单事件,当用户右击部件时会触发。"""
contextMenu = QMenu(self)
contextMenu.addAction("添加").triggered.connect(self.add_item)
contextMenu.addAction("编辑").triggered.connect(self.edit_item)
contextMenu.addAction("删除").triggered.connect(self.remove_item)
contextMenu.addSeparator() # 添加分割线
contextMenu.addAction("全选").triggered.connect(self.select_all)
contextMenu.addAction("反选").triggered.connect(self.inverse_select)
contextMenu.addAction("全不选").triggered.connect(self.select_none)
contextMenu.exec(event.globalPos())

def add_item(self):
"""插入新项"""
row = self.listwidget.currentRow() # 获取当前选中项的index
print(row)
title = "添加项"
data, ok = QInputDialog.getText(self, title, title)
if ok and data is not None:
self.listwidget.insertItem(row, data)

def edit_item(self):
"""编辑项"""
item = self.listwidget.currentItem()
if item is not None:
title = "编辑项"
data, ok = QInputDialog.getText(
self, title, title, QLineEdit.EchoMode.Normal, item.text()
)
if ok and data is not None:
item.setText(data)

def remove_item(self):
"""删除项"""
row = self.listwidget.currentRow()
item = self.listwidget.item(row)
if item == None:
return
title1 = "删除项"
title2 = "确定要删除?"
reply = QMessageBox.question(
self, title1, title2, QMessageBox.Yes | QMessageBox.No
)
if reply == QMessageBox.Yes:
self.listwidget.takeItem(row)

def select_all(self):
"""选择所有项"""
count = self.listwidget.count()
for i in range(count):
item = self.listwidget.item(i)
item.setCheckState(Qt.Checked)

def inverse_select(self):
"""反选"""
count = self.listwidget.count()
for i in range(count):
item = self.listwidget.item(i)
if item.checkState() == Qt.Unchecked:
item.setCheckState(Qt.Checked)
else:
item.setCheckState(Qt.Unchecked)

def select_none(self):
"""全不选"""
count = self.listwidget.count()
for i in range(count):
item = self.listwidget.item(i)
item.setCheckState(Qt.Unchecked)


if __name__ == "__main__":
app = QApplication(sys.argv)
win = Window()
win.show()
sys.exit(app.exec())

表格控件QTableWidget

【实例1-4】 创建一个窗口,该窗口包含一个表格控件。设置表格控件的表头,并添加两行数据。

image-20250415233948151

代码如下:

"""
创建一个窗口,该窗口包含一个列表控件。在列表控件中右击会弹出上下文菜单,菜单命令包含添加、编辑、删除、全选、反选、全不选
"""

import sys
from PySide6.QtGui import QFont
from PySide6.QtWidgets import (
QApplication,
QWidget,
QVBoxLayout,
QListWidget,
QPushButton,
QHBoxLayout,
QInputDialog,
QLineEdit,
QMessageBox,
QMenu,
QTabWidget,
QTableWidget,
QTableWidgetItem,
)
from PySide6.QtCore import Qt


class Window(QWidget):
def __init__(self):
super().__init__()
self.setGeometry(200, 200, 560, 260)
self.setWindowTitle("QListWidget QListWidgetItem")

vbox = QVBoxLayout()
self.setLayout(vbox)

# 创建表格控件
tableWidget = QTableWidget()
tableWidget.setRowCount(3) # 设置行数
tableWidget.setColumnCount(5) # 设置列数
tableWidget.setFont(QFont("等线", 12))
vbox.addWidget(tableWidget)

# 设置表头
header = ["学号", "姓名", "语文成绩", "数学成绩", "总分"]
for i, h in enumerate(header):
tableWidget.setItem(0, int(i), QTableWidgetItem(h))

# 插入第一行数据
row1 = ["001", "孙悟空", "90", "90", "180"]
for i, h in enumerate(row1):
tableWidget.setItem(1, int(i), QTableWidgetItem(h))

# 插入第二行数据
row2 = ["002", "猪八戒", "90", "90", "180"]
for i, h in enumerate(row2):
tableWidget.setItem(2, int(i), QTableWidgetItem(h))


if __name__ == "__main__":
app = QApplication(sys.argv)
win = Window()
win.show()
sys.exit(app.exec())

QTableWidgetItem类

使用QTableWidgetItem类创建表格控件的表格项。

【实例1-5】 创建一个窗口,该窗口包含一个表格控件、5个按钮控件。这5个按钮分别实现添加列、删除列、添加行、删除行、全选含有文本的表格项的功能。

1

代码如下:

"""
创建一个窗口,该窗口包含一个表格控件、5个按钮控件。这5个按钮分别实现添加列、删除列、添加行、删除行、全选含有文本的表格项的功能
"""

import sys
from PySide6.QtGui import QFont
from PySide6.QtWidgets import (
QApplication,
QWidget,
QVBoxLayout,
QListWidget,
QPushButton,
QHBoxLayout,
QInputDialog,
QLineEdit,
QMessageBox,
QMenu,
QTabWidget,
QTableWidget,
QTableWidgetItem,
)
from PySide6.QtGui import QFont, Qt


class Window(QWidget):
def __init__(self):
super().__init__()
self.setGeometry(200, 200, 560, 260)
self.setWindowTitle("QListWidget QListWidgetItem")

vbox = QVBoxLayout()
self.setLayout(vbox)

# 创建4个按钮
btnAddColumn = QPushButton("添加列")
btnRemoveColumn = QPushButton("删除列")
btnAddRow = QPushButton("添加行")
btnRemoveRow = QPushButton("删除行")
btnSelectAll = QPushButton("全选")
hbox = QHBoxLayout()
hbox.addWidget(btnAddColumn)
hbox.addWidget(btnRemoveColumn)
hbox.addWidget(btnAddRow)
hbox.addWidget(btnRemoveRow)
hbox.addWidget(btnSelectAll)
vbox.addLayout(hbox)

# 使用信号/槽
btnAddColumn.clicked.connect(self.add_column)
btnRemoveColumn.clicked.connect(self.remove_column)
btnAddRow.clicked.connect(self.add_row)
btnRemoveRow.clicked.connect(self.remove_row)
btnSelectAll.clicked.connect(self.slect_all)

# 创建表格控件
self.tableWidget = QTableWidget()
self.tableWidget.setRowCount(3) # 设置行数
self.tableWidget.setColumnCount(5) # 设置列数
self.tableWidget.setFont(QFont("等线", 12))
vbox.addWidget(self.tableWidget)

# 设置表头
header = ["学号", "姓名", "语文成绩", "数学成绩", "总分"]
for i, h in enumerate(header):
self.tableWidget.setItem(0, int(i), QTableWidgetItem(h))

# 插入第一行数据
row1 = ["001", "孙悟空", "90", "90", "180"]
for i, h in enumerate(row1):
self.tableWidget.setItem(1, int(i), QTableWidgetItem(h))

# 插入第二行数据
row2 = ["002", "猪八戒", "90", "90", "180"]
for i, h in enumerate(row2):
self.tableWidget.setItem(2, int(i), QTableWidgetItem(h))

def add_column(self):
"""添加列"""
count = self.tableWidget.columnCount()
if count == 0:
self.tableWidget.insertColumn(0)
else:
self.tableWidget.insertColumn(count)

def remove_column(self):
num = self.tableWidget.currentColumn()
if num == None:
return

title1 = "删除项"
title2 = "确定要删除这一列?"
reply = QMessageBox.question(
self, title1, title2, QMessageBox.Yes | QMessageBox.No
)
if reply == QMessageBox.Yes:
self.tableWidget.removeColumn(num)

def add_row(self):
"""添加行"""
count = self.tableWidget.rowCount()
if count == 0:
self.tableWidget.insertRow(0)
else:
self.tableWidget.insertRow(count)

def remove_row(self):
"""删除项"""
row = self.tableWidget.currentRow()
if row == None:
return
title1 = "删除行"
title2 = "确定要删除?"
reply = QMessageBox.question(
self, title1, title2, QMessageBox.Yes | QMessageBox.No
)
if reply == QMessageBox.Yes:
self.tableWidget.removeRow(row)

def slect_all(self):
"""选择所有项"""
rowNum = self.tableWidget.rowCount()
colNum = self.tableWidget.columnCount()
for i in range(rowNum):
for j in range(colNum):
item = self.tableWidget.item(i, j)
if item is not None:
item.setCheckState(Qt.Checked)


if __name__ == "__main__":
app = QApplication(sys.argv)
win = Window()
win.show()
sys.exit(app.exec())


使用表格控件处理CSV文件

在PySide6中,可以使用表格控件(QTableWidget)处理CSV文件,不过这需要应用Python内置模块CSV。

【实例1-6】 创建一个窗口,该窗口包含一个表格控件、两个按压按钮。这两个按钮分别实现打开CSV文件、保存CSV文件的功能。

image-20250418203830099

代码如下:

"""
创建一个窗口,该窗口包含一个表格控件、两个按压按钮。这两个按钮分别实现打开CSV文件、保存CSV文件的功能。
"""

import sys, os, csv
from PySide6.QtGui import QFont
from PySide6.QtWidgets import (
QApplication,
QWidget,
QVBoxLayout,
QListWidget,
QPushButton,
QHBoxLayout,
QInputDialog,
QLineEdit,
QMessageBox,
QMenu,
QTabWidget,
QTableWidget,
QTableWidgetItem,
QFileDialog,
)
from PySide6.QtGui import QFont, Qt


class Window(QWidget):
def __init__(self):
super().__init__()
self.setGeometry(200, 200, 560, 260)
self.setWindowTitle("处理CSV文件")

vbox = QVBoxLayout()
self.setLayout(vbox)

# 创建2个按钮
btnOpen = QPushButton("打开CSV文件")
btnClose = QPushButton("保存CSV文件")
hbox = QHBoxLayout()
hbox.addWidget(btnOpen)
hbox.addWidget(btnClose)
vbox.addLayout(hbox)

# 使用信号/槽
btnOpen.clicked.connect(self.open_csv)
btnClose.clicked.connect(self.save_csv)

# 创建表格控件
self.tableWidget = QTableWidget()
self.tableWidget.setFont(QFont("等线", 12))
vbox.addWidget(self.tableWidget)

def open_csv(self):
"""打开csv文件"""
src_file, file = QFileDialog.getOpenFileName(
self, "打开文件", "D:\\", "CSV文件(*.csv)"
)
if os.path.exists(src_file) == False:
return
self.tableWidget.clear() # 清空表格中的内容
# 根据文件类型设置编码方式为gbk货utf-8
with open(src_file, mode="r") as f:
reader = csv.reader(f)
data = list()
# 将reader的数据添加到二维列表data中
for row in reader:
temp = list()
for j in row:
temp.append(str(j))
data.append(temp)
# 根据二维列表的行数、列数创建表格控件
rowNum = len(data) - 1
colummNum = len(data[0])
self.tableWidget.setRowCount(rowNum)
self.tableWidget.setColumnCount(colummNum)
self.tableWidget.setHorizontalHeaderLabels(data[0]) # 设置首行
for i in range(rowNum):
for j in range(colummNum):
cell = QTableWidgetItem()
cell.setText(data[i + 1][j])
self.tableWidget.setItem(i, j, cell)

def save_csv(self):
"""保存CSV文件"""
data_list = list()
fileName, file = QFileDialog.getSaveFileName(
self, "保存文件", "D:\\", "CSV文件(*.csv)"
)
if fileName == "":
return
temp1 = list()
rowNum = self.tableWidget.columnCount()
colummNum = self.tableWidget.rowCount() - 1
# 将表头数据添加到data_list列表中
for j in range(colummNum):
temp1.append(self.tableWidget.horizontalHeaderItem(j).text())
data_list.append(temp1)
print(data_list)
# 将表格数据添加到data_list列表中
for i in range(rowNum):
temp2 = list()
for j in range(colummNum):
item = self.tableWidget.item(i, j)
temp2.append(item.text())
data_list.append(temp2)
# 向CSV中写入数据
with open(fileName, mode="w", encoding="utf-8-sig", newline="") as f:
writer = csv.writer(f)
writer.writerows(data_list) # 写入多行数据


if __name__ == "__main__":
app = QApplication(sys.argv)
win = Window()
win.show()
sys.exit(app.exec())

树结构控件QTreeWidget及其项QTreeWidgetItem

使用QTreeWidgetItem类表示树结构控件的项,使用QTreeWidgetItem类可以定义项中的文字和图标。

QTreeWidget类是QTreeView类的子类。

【实例1-7】 创建一个窗口,该窗口包含一个树结构控件、一个标签控件。向树结构控件中添加两列数据,如果选中包含两列数据的项,则标签显示对应的信息。

image-20250418210541248

代码如下:

"""
创建一个窗口,该窗口包含一个树结构控件、一个标签控件。向树结构控件中添加两列数据,如果选中包含两列数据的项,则标签显示对应的信息
"""

import sys, os, csv
from PySide6.QtGui import QFont
from PySide6.QtWidgets import (
QApplication,
QWidget,
QVBoxLayout,
QListWidget,
QPushButton,
QHBoxLayout,
QInputDialog,
QLineEdit,
QMessageBox,
QMenu,
QTabWidget,
QTableWidget,
QTableWidgetItem,
QFileDialog,
QLabel,
QTreeWidget,
QTreeWidgetItem,
)
from PySide6.QtGui import QFont, Qt


class Window(QWidget):
def __init__(self):
super().__init__()
self.setGeometry(200, 200, 560, 360)
self.setWindowTitle("处理CSV文件")

vbox = QVBoxLayout()
self.setLayout(vbox)

# 创建数结构控件
self.treeWidget = QTreeWidget()
self.treeWidget.setFont(QFont("黑体", 12))
self.label = QLabel("提示:")
self.label.setFont(QFont("楷体", 14))
vbox.addWidget(self.treeWidget)
vbox.addWidget(self.label)

# 树结构中添加表头数据
self.treeWidget.setColumnCount(2)
header = QTreeWidgetItem()
header.setText(0, "地区范围")
header.setText(1, "人口范围(万人)")
header.setTextAlignment(0, Qt.AlignLeft)
header.setTextAlignment(1, Qt.AlignLeft)
self.treeWidget.setHeaderItem(header)

# 添加顶层项
self.topItem1 = QTreeWidgetItem(self.treeWidget)
self.topItem1.setText(0, "东北")
child_1 = QTreeWidgetItem(self.topItem1, ["黑龙江", "31119"])
child_2 = QTreeWidgetItem(self.topItem1, ["吉林", "12334"])
child_3 = QTreeWidgetItem(self.topItem1, ["辽宁", "234324"])
child_4 = QTreeWidgetItem(child_3, ["沈阳", "12312"])
child_5 = QTreeWidgetItem(child_3, ["大连", "123412"])

# 添加顶层项
self.topItem2 = QTreeWidgetItem(self.treeWidget)
self.topItem2.setText(0, "华南")
child_1 = QTreeWidgetItem(self.topItem2, ["广东", "31119"])
child_2 = QTreeWidgetItem(self.topItem2, ["深圳", "12334"])
child_3 = QTreeWidgetItem(self.topItem2, ["广西", "234324"])
child_4 = QTreeWidgetItem(child_1, ["南沙", "12312"])
child_5 = QTreeWidgetItem(child_1, ["番禺", "123412"])

# 展开所有项目
self.treeWidget.expandAll()

# 点击项槽函数
self.treeWidget.itemClicked.connect(self.clicked_treeWidgt)

def clicked_treeWidgt(self, item, column):
if item.text(1) != "":
string = f"地区范围:{item.text(0)}, 人口数量(万人):{item.text(1)}"
self.label.setText(string)


if __name__ == "__main__":
app = QApplication(sys.argv)
win = Window()
win.show()
sys.exit(app.exec())