You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

关键改动说明

  1. 视觉交互禁用:

    • 在StyleDelegate中提前清除选中、悬停、焦点状态,确保绘制时无交互反馈
    • 通过setSelectionMode和setFocusPolicy彻底移除表格的选中框与焦点框
    • 全局应用Delegate,简化代码逻辑
  2. 极小列宽设置:

    • 调用horizontalHeader().setMinimumSectionWidth(0)取消表头最小宽度限制
    • 直接使用setColumnWidth设置2-5px范围内的宽度
  3. 极小行高设置:

    • 调用verticalHeader().setMinimumSectionHeight(0)取消表头最小行高限制
    • 通过setRowHeight设置符合预期的极小行高

内容的提问来源于stack exchange,提问作者Kankan2000

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 05:45:58