欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

PyQt5 QTableWidget的显示、添加和删除多行

程序员文章站 2022-04-22 12:08:09
...

最近为了写软著,一直在用PyQt5进行开发,但因为本身对PyQt5并不熟悉,所以在写代码的过程中遇到了很多问题,只能在网上疯狂百度找办法,这一篇博客简单总结一下PyQt5中QTableWidget的显示、添加和删除操作的方法。

1. QTableWidget的显示

首先给出我的界面如下,其中红色框就是显示的表格。

PyQt5 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))


实现后的界面如下:

PyQt5 QTableWidget的显示、添加和删除多行

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())