目录
1、QListWidget
2、QTreeWidget
3、QTableWidget
1、QListWidget
QListWidget是一个QListView的便捷类,提供一个列表视图,大数据量的情况下QListView确实更加灵活,效率更高。但是在少量数据的时候,因为易用性,QListWidget也是一个不错的选择。
QListWidget的每个数据项都是一个QListWidgetItem。
更多用法见:QListWidget详细说明
下面是一个QListWidget的简单用法:
self.list_widget = QListWidget()
self.list_widget.addItem("数据1")
self.list_widget.addItem("数据2")
self.list_widget.addItem("数据3")
self.list_widget.addItem("数据4")
self.main_layout.addWidget(self.list_widget)
再结合前面的知识实现一个简易的目录浏览器:
import os
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLineEdit, QPushButton, \
QListWidgetItem, QListWidget, QHBoxLayout
class ButtonWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle('测试button')
self.resize(400, 300)
self.layout_main = QVBoxLayout()
self.layout_header = QHBoxLayout()
self.le_folder_addr = QLineEdit()
self.btn_view = QPushButton("浏览")
# 信号与槽
self.btn_view.clicked.connect(self.view_folder)
self.layout_header.addWidget(self.le_folder_addr, stretch=1)
self.layout_header.addWidget(self.btn_view)
self.layout_main.addLayout(self.layout_header)
self.list_widget = QListWidget()
self.layout_main.addWidget(self.list_widget)
self.setLayout(self.layout_main)
def view_folder(self):
for entry in os.scandir(self.le_folder_addr.text()):
if entry.is_dir():
self.list_widget.addItem(QListWidgetItem(QIcon('icons/folder.png'), entry.name))
else:
self.list_widget.addItem(QListWidgetItem(QIcon('icons/file.png'), entry.name))
QTreeWidget是QTreeView的便捷类,提供一个树形视图。QTreeWidget的每个结点都是一个QTreeWidgetItem。直接挂靠在QTreeWidget下的结点是top结点,top结点没有父结点,其他结点在代码上和QTreeWidget已经没有关系了,只需要指定父结点即可,我们可以从QTreeWidgetItem详细说明里面看到QTreeWidgetItem的构造函数大多要指定一个parent。
QTreeWidget使用addTopLevelItem()来添加top结点。
QTreeWidget有columns的概念,我们可以用windows文件夹的详细信息浏览方式为例来理解:
QTreeWidget在第一列展示树形视图,我们可以添加2、3、4 ... 列来展示结点的更多属性。
QTreeWidget还可以设置header信息,更多用法参见:QTreeWidget详细说明
还是上面的简易文件夹浏览器,我们希望能够进一步浏览子目录,并且要体现层级关系,可以用QTreeWidget来改写上面的代码:
class ButtonWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle('测试button')
self.resize(400, 300)
self.layout_main = QVBoxLayout()
self.layout_header = QHBoxLayout()
self.le_folder_addr = QLineEdit()
self.btn_view = QPushButton("浏览")
self.btn_view.clicked.connect(self.view_folder)
self.layout_header.addWidget(self.le_folder_addr, stretch=1)
self.layout_header.addWidget(self.btn_view)
self.layout_main.addLayout(self.layout_header)
# 改用QTreeWidget来展示,树形才能展示目录的层级关系
self.tree_widget = QTreeWidget()
# 设置标题为 名称
self.tree_widget.setHeaderLabel("名称")
self.layout_main.addWidget(self.tree_widget)
self.setLayout(self.layout_main)
def view_folder(self):
for entry in os.scandir(self.le_folder_addr.text()):
if entry.is_dir():
temp = QTreeWidgetItem([entry.name])
temp.setIcon(0, QIcon('icons/folder.png'))
# 添加top结点
self.tree_widget.addTopLevelItem(temp)
# 子目录下的结点以此top结点为root形成一颗结点树
self.digui_view(os.path.join(self.le_folder_addr.text(), entry.name), temp)
else:
temp = QTreeWidgetItem([entry.name])
temp.setIcon(0, QIcon('icons/file.png'))
self.tree_widget.addTopLevelItem(temp)
def digui_view(self, name, parent):
for entry in os.scandir(name):
if entry.is_dir():
# 非top结点只需指定父结点即可
temp = QTreeWidgetItem(parent, [entry.name])
temp.setIcon(0, QIcon('icons/folder.png'))
self.digui_view(os.path.join(name, entry.name), temp)
else:
temp = QTreeWidgetItem(parent, [entry.name])
temp.setIcon(0, QIcon('icons/file.png'))
这样一来效果就好多了,现在我们想展示每个文件的修改日期,再进一步修改代码:
def get_f_time(timestamp):
return datetime.datetime.fromtimestamp(timestamp).strftime("%Y/%m/%d %H:%M")
class ButtonWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle('测试button')
self.resize(400, 300)
self.layout_main = QVBoxLayout()
self.layout_header = QHBoxLayout()
self.le_folder_addr = QLineEdit()
self.btn_view = QPushButton("浏览")
self.btn_view.clicked.connect(self.view_folder)
self.layout_header.addWidget(self.le_folder_addr, stretch=1)
self.layout_header.addWidget(self.btn_view)
self.layout_main.addLayout(self.layout_header)
self.tree_widget = QTreeWidget()
# 设置两列
self.tree_widget.setColumnCount(2)
# 两列的标题
self.tree_widget.setHeaderLabels(["名称", "修改日期"])
self.layout_main.addWidget(self.tree_widget)
self.setLayout(self.layout_main)
def view_folder(self):
for entry in os.scandir(self.le_folder_addr.text()):
if entry.is_dir():
# 这就是为什么QTreeWidgetItem的构造函数都是传入字符串列表
temp = QTreeWidgetItem([entry.name, get_f_time(entry.stat().st_mtime)])
temp.setIcon(0, QIcon('icons/folder.png'))
self.tree_widget.addTopLevelItem(temp)
self.digui_view(os.path.join(self.le_folder_addr.text(), entry.name), temp)
else:
temp = QTreeWidgetItem([entry.name, get_f_time(entry.stat().st_mtime)])
temp.setIcon(0, QIcon('icons/file.png'))
self.tree_widget.addTopLevelItem(temp)
def digui_view(self, name, parent):
for entry in os.scandir(name):
if entry.is_dir():
temp = QTreeWidgetItem(parent, [entry.name, get_f_time(entry.stat().st_mtime)])
temp.setIcon(0, QIcon('icons/folder.png'))
self.digui_view(os.path.join(name, entry.name), temp)
else:
temp = QTreeWidgetItem(parent, [entry.name, get_f_time(entry.stat().st_mtime)])
temp.setIcon(0, QIcon('icons/file.png'))
QTableWidget是QTableView的便捷类,提供一个表格视图。表格有行列之说,QTableWidget的行列数可以在实例化的时候指定,也可以通过setRowCount()和setColumnCount()来指定,QTableWidget的每个单元格都是一个QTableWidgetItem,通过setItem()来设置单元格。更多用法见:QTableWidget详细说明。
class ButtonWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle('测试button')
self.resize(400, 300)
self.layout_main = QVBoxLayout()
# 新建一个QTableWidget并指定5行3列
self.table_widget = QTableWidget(5, 3)
# 水平方向上的标题自然就是列标题
self.table_widget.setHorizontalHeaderLabels(["数学", "语文", "英语"])
# 行标题
self.table_widget.setVerticalHeaderLabels(["张三", "李四", "王五", "赵六", "吴起"])
# 设置item,需要同时指定行列索引,没有捷径,只能一个个单元格的设置
self.table_widget.setItem(0, 0, QTableWidgetItem("78"))
self.table_widget.setItem(1, 0, QTableWidgetItem("89"))
self.table_widget.setItem(2, 0, QTableWidgetItem("56"))
self.table_widget.setItem(3, 0, QTableWidgetItem("77"))
self.table_widget.setItem(4, 0, QTableWidgetItem("99"))
self.layout_main.addWidget(self.table_widget)
self.setLayout(self.layout_main)