最近为了写软著,一直在用PyQt5进行开发,但因为本身对PyQt5并不熟悉,所以在写代码的过程中遇到了很多问题,只能在网上疯狂百度找办法,这一篇博客简单总结一下PyQt5中QTableWidget的显示、添加和删除操作的方法。
1. QTableWidget的显示
首先给出我的界面如下,其中红色框就是显示的表格。
显示表格的代码如下,具体细节已经在代码的注释中给出。
def show_events(self, event_table, total_events, cause_tag):
"""
将事件列表显示在tableWidget中
:param event_table: tableWidget控件
:param total_events: 所有事件的列表
:param cause_tag: 所有的标签值列表
:return: None
"""
# 先给出表格中需要显示的行列数。注意这个是必须要提前设置的,否则无法显示
event_table.setColumnCount(2)
event_table.setRowCount(len(total_events))
# 设置表格的列标题,并设置列的模式为"Stretch",在这种模式下列直接自适应显示,无法对列的宽度和高度进行设置
header_list = ['event', 'cause'] # set header labels
event_table.setHorizontalHeaderLabels(header_list)
event_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
# event_table.setColumnWidth(0, 685)
# event_table.setColumnWidth(1, 100)
# 表格中的每个cell都是一个Item,所以显示时需要分别显示每个cell的内容,每个cell的坐标都是(行号,列号),行号和列号都是从0开始
for index, event in enumerate(total_events):
# 在每一行中显示每个样本的每个元素
for column_index in range(7):
self.main_ui.tuple_events_table.setItem(cur_row - 1, column_index, QTableWidgetItem(''))
# event_table.setItem(index, 1, QTableWidgetItem(event_node.getAttribute('cause')))
# 下拉框,默认值为'N',因为大部分值都为'N'
combox_list = ['N', 'Y']
combox = QtWidgets.QComboBox()
combox.addItems(combox_list)
if cause_tag[index] == 'N':
combox.setCurrentIndex(0)
else:
combox.setCurrentIndex(1)
# 这个函数可以用来定义所有控件的
combox.setStyleSheet('QComboBox{margin:3px;font-family:Times New Roman;font-size:18;border-radius:8px}')
event_table.setCellWidget(index, 1, combox)
2. QTableWidget绑定右键菜单
首先需要在表格中绑定右键菜单,同时定义右键菜单的点击事件:
# 设置events_table的右键菜单
self.tag_ui.events_table.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
# 在tableWidget中点击右键的触发事件
self.tag_ui.events_table.customContextMenuRequested[QtCore.QPoint].connect(self.context_menu_of_events_table)
在右键菜单的绑定事件中,我们需要定义右键菜单中显示的操作,同时定义显示的操作再被点击后的具体操作过程,代码如下:
def context_menu_of_events_table(self, pos):
"""
用于在tableWidget中点击右键的触发事件,显示右键菜单
:return:
"""
pop_menu = QMenu()
add_new_event = pop_menu.addAction('添加新事件')
del_selected_event = pop_menu.addAction('删除选中事件')
# 获取右键菜单中当前被点击的是哪一项
action = pop_menu.exec_(self.tag_ui.events_table.mapToGlobal(pos))
实现后的界面如下:
3. QTableWidget中添加和删除事件
在定义了QTableWidget的右键菜单的基础上,实现表格中的添加和删除事件的代码如下,具体细节在代码中给出。
def context_menu_of_events_table(self, pos):
"""
用于在tableWidget中点击右键的触发事件,显示右键菜单
:return:
"""
pop_menu = QMenu()
add_new_event = pop_menu.addAction('添加新事件')
del_selected_event = pop_menu.addAction('删除选中事件')
action = pop_menu.exec_(self.tag_ui.events_table.mapToGlobal(pos))
if action == add_new_event: # 如果选中的是添加新的事件
"""
如果是添加新行,首先必须先将表格的总行数加1,才能进行后续操作,将表格的行数加1之后,再在新加的行内每一列中添加Item
"""
cur_total_row = self.tag_ui.events_table.rowCount()
cur_row = cur_total_row + 1
self.tag_ui.events_table.setRowCount(cur_row) # 将当前的总行数加1
self.tag_ui.events_table.setItem(cur_row-1, 0, QTableWidgetItem("请添加新的事件"))
# event_table.setItem(index, 1, QTableWidgetItem(event_node.getAttribute('cause')))
# 下拉框,默认值为'N',因为大部分值都为'N'
combox_list = ['N', 'Y']
combox = QtWidgets.QComboBox()
combox.addItems(combox_list)
combox.setCurrentIndex(0)
# 这个函数可以用来定义所有控件的
combox.setStyleSheet('QComboBox{margin:3px;font-family:Times New Roman;font-size:14;border-radius:8px}')
self.tag_ui.events_table.setCellWidget(cur_row-1, 1, combox)
elif action == del_selected_event:
"""
如果我们选择用.selectedItems()函数来得到当前选中的多行,一定要注意,这个函数返回的是所有选中的item,即返回的item的个数为:选中的行数 * 每一行的item数(我这个代码中有8列,但每行只返回7个item,我也不知道为什么,这一点需要注意一下)。
每个item都可以通过.indexFromItem(items).row()得到其所在的行号,再通过.removeRow(row_number)删除对应的行。
所以在删除时并不是所有的item都需要用,因为很显然要删除每一行都只需要一个该行的item即可,如果有多个肯定会报错,所以我才做了如下操作,在固定间隔取一个item,保证每一行中都只有一个item保留下来,这样就能保证每个被选中的行都只被删除一次。
还有一个需要注意的问题,如果选择多行的话,比如选择的行号为1,2,3,7,9,如果我们从前面开始删除,比如先删除第1行,则剩下的行的行的删除会出现问题,因为第1行删除后,原来的第2行会变成新的第1行,原来的第3行会变成新的第2行,以此类推,这很显然会导致剩余行的删除出现问题。我这里的解决办法是先将要删除的行进行降序排序,从后往前删除则可以保证删除的行不会发生错误。
"""
selected_items = self.main_ui.tuple_events_table.selectedItems()
if len(selected_items) == 0: # 说明没有选中任何行
return
selected_items = [selected_items[i] for i in range(len(selected_items)-1, -1, -7)]
# 将选定行的行号降序排序,只有从索引大的行开始删除,才不会出现错误
for items in selected_items:
self.main_ui.tuple_events_table.removeRow(self.main_ui.tuple_events_table.indexFromItem(items).row())