PyQt5实现表格禁用视觉交互、设置窄列及极小行高
解决QTableWidget的三个视觉与布局需求(PyQt5实现)
针对你提出的三个需求,以下是具体的实现方案及修改后的完整代码:
1. 禁用所有高亮及视觉交互(保留点击取值功能)
原代码中StyleDelegate的状态修改时机错误,需在调用父类paint方法之前清除交互状态,同时配合表格属性设置,彻底移除选中、悬停、焦点等视觉反馈,但保留点击事件响应。
2. 设置指定列为2-5px宽度
默认表头存在最小宽度限制,需先取消该限制,才能设置极小列宽。
3. 设置指定行为更小行高
与列宽同理,垂直表头默认有最小行高限制,取消后即可设置符合预期的极小行高。
修改后的完整代码
import sys from PyQt5.QtWidgets import ( QWidget, QTableWidget, QHBoxLayout, QApplication, QTableWidgetItem, QStyledItemDelegate, QSizePolicy, QStyle ) from PyQt5.QtCore import Qt class StyleDelegate(QStyledItemDelegate): def paint(self, painter, option, index): # 先清除所有交互相关状态,再执行父类绘制逻辑 option.state &= ~(QStyle.State_Selected | QStyle.State_MouseOver | QStyle.State_HasFocus) super().paint(painter, option, index) class Table(QWidget): def __init__(self): super().__init__() self.initUI() # 设置指定列的窄宽度(示例设为3px,可在2-5之间调整) narrow_columns = [6, 8, 10, 12, 14] for col in narrow_columns: self.tableWidget.setColumnWidth(col, 3) def initUI(self): self.setWindowTitle("QTableWidget - 单元格合并示例") self.resize(660, 300) conLayout = QHBoxLayout() self.tableWidget = QTableWidget() self.tableWidget.setColumnCount(20) conLayout.addWidget(self.tableWidget) # 隐藏表头 self.tableWidget.horizontalHeader().setVisible(False) self.tableWidget.verticalHeader().setVisible(False) # 取消表头的最小宽高限制,允许设置极小尺寸 self.tableWidget.horizontalHeader().setMinimumSectionWidth(0) self.tableWidget.verticalHeader().setMinimumSectionHeight(0) # 禁用选中与焦点的视觉反馈,保留点击事件 self.tableWidget.setSelectionMode(QTableWidget.NoSelection) self.tableWidget.setFocusPolicy(Qt.NoFocus) # 单元格合并设置 self.tableWidget.setSpan(0, 0, 1, 20) self.tableWidget.setSpan(3, 0, 1, 20) data = [('NAME', 'VALUE', 'LPT', 'NLPT', 'SEQ', 'SEQ2', "V1", "V2", "V3", "V4", "V5", "V6", "V7"), ('NAME1', 'VALUE1', 'LPT1', 'NLPT1', 'SEQ1', 'SEQ21', "V11", "V21", "V31", "V41", "V51", "V61", "V71")] data_offset = 0 required_rows = len(data) * 4 total_rows = required_rows self.tableWidget.setRowCount(total_rows) for i in range(0, required_rows, 4): # 设置极小行高(示例设为2px,可按需调整) self.tableWidget.setRowHeight(i, 2) self.tableWidget.setRowHeight(i + 3, 2) # 重复单元格合并规则 self.tableWidget.setSpan(i + 3, 0, 1, 20) self.tableWidget.setSpan(i + 0, 0, 1, 20) self.tableWidget.setSpan(i + 1, 2, 1, 2) self.tableWidget.setSpan(i + 1, 4, 1, 2) self.tableWidget.setSpan(i + 1, 7, 2, 1) self.tableWidget.setSpan(i + 1, 9, 2, 1) self.tableWidget.setSpan(i + 1, 11, 2, 1) self.tableWidget.setSpan(i + 1, 13, 2, 1) self.tableWidget.setSpan(i + 1, 15, 2, 1) self.tableWidget.setSpan(i + 1, 17, 2, 1) self.tableWidget.setSpan(i + 1, 19, 2, 1) # 填充数据 self.tableWidget.setItem(i + 1, 2, QTableWidgetItem(data[data_offset][0])) self.tableWidget.setItem(i + 2, 0, QTableWidgetItem(str(data[data_offset][1]))) try: value = str(data[data_offset][2]) except IndexError: value = None self.tableWidget.setItem(i + 2, 4, QTableWidgetItem(value)) try: value = str(data[data_offset][3]) except IndexError: value = None self.tableWidget.setItem(i + 2, 5, QTableWidgetItem(value)) try: value = str(data[data_offset][3]) except IndexError: value = None self.tableWidget.setItem(i + 1, 11, QTableWidgetItem(value)) try: value = str(data[data_offset][3]) except IndexError: value = None self.tableWidget.setItem(i + 1, 9, QTableWidgetItem(value)) try: value = str(data[data_offset][3]) except IndexError: value = None self.tableWidget.setItem(i + 1, 7, QTableWidgetItem(value)) try: value = str(data[data_offset][3]) except IndexError: value = None self.tableWidget.setItem(i + 1, 13, QTableWidgetItem(value)) try: value = str(data[data_offset][3]) except IndexError: value = None self.tableWidget.setItem(i + 1, 15, QTableWidgetItem(value)) try: value = str(data[data_offset][3]) except IndexError: value = None self.tableWidget.setItem(i + 1, 17, QTableWidgetItem(value)) data_offset += 1 # 表格其他属性设置 self.tableWidget.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn) self.tableWidget.setShowGrid(True) self.tableWidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) # 全局应用自定义Delegate,无需逐行设置 delegate = StyleDelegate() self.tableWidget.setItemDelegate(delegate) self.setLayout(conLayout) if __name__ == '__main__': app = QApplication(sys.argv) example = Table() example.show() sys.exit(app.exec_())
关键改动说明
视觉交互禁用:
- 在
StyleDelegate中提前清除选中、悬停、焦点状态,确保绘制时无交互反馈 - 通过
setSelectionMode和setFocusPolicy彻底移除表格的选中框与焦点框 - 全局应用Delegate,简化代码逻辑
- 在
极小列宽设置:
- 调用
horizontalHeader().setMinimumSectionWidth(0)取消表头最小宽度限制 - 直接使用
setColumnWidth设置2-5px范围内的宽度
- 调用
极小行高设置:
- 调用
verticalHeader().setMinimumSectionHeight(0)取消表头最小行高限制 - 通过
setRowHeight设置符合预期的极小行高
- 调用
内容的提问来源于stack exchange,提问作者Kankan2000
相关产品推荐
相关产品推荐

