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

如何禁用PySide6中QTableWidget垂直表头的指定行?

解决QTableWidget垂直表头特定行禁用问题

Qt没有直接提供disableRow这类方法,但可以通过两种实用方式实现需求——既保留行内容可见,又阻止表头行的重复点击:

方法一:用集合记录禁用行 + 视觉反馈

这种方式实现简单,适合快速落地:

  • 用集合存储已禁用的表头行索引,点击时先判断是否在集合内,是则直接返回
  • 处理完选择逻辑后,将该行加入禁用集合
  • 可选:修改表头样式,给用户明确的视觉提示(比如变灰)
class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.board.verticalHeader().sectionClicked.connect(self.pick_choice)
        # 存储已禁用的垂直表头行索引
        self.disabled_header_rows = set()
        # 初始化表头样式基础模板
        self.header_style_base = """
            QHeaderView::section:vertical {
                padding: 4px;
                border: 1px solid #ddd;
            }
        """
        self.board.verticalHeader().setStyleSheet(self.header_style_base)

    def pick_choice(self, row: int):
        # 先判断该行是否已禁用
        if row in self.disabled_header_rows:
            return
        
        # 原有业务逻辑
        if self.board.item(row, self.current_player).text():
            # 直接禁用该行
            self.disabled_header_rows.add(row)
            self._update_disabled_header_style()
            return
        
        # 此处添加正常选择后的业务逻辑
        # ...
        
        # 处理完成后禁用该行
        self.disabled_header_rows.add(row)
        self._update_disabled_header_style()

    def _update_disabled_header_style(self):
        # 拼接禁用行的样式规则,避免覆盖基础样式
        disabled_rules = ""
        for row in self.disabled_header_rows:
            disabled_rules += f"""
                QHeaderView::section:vertical:nth-child({row+1}) {{
                    background-color: #eee;
                    color: #888;
                }}
            """
        self.board.verticalHeader().setStyleSheet(self.header_style_base + disabled_rules)

方法二:自定义垂直表头(更优雅的模块化实现)

如果需要更灵活的交互控制,可自定义QHeaderView,重写鼠标事件和绘制逻辑:

from PySide6.QtWidgets import QHeaderView, QTableWidget
from PySide6.QtGui import QPainter
from PySide6.QtCore import Qt

class DisabledVerticalHeader(QHeaderView):
    def __init__(self, parent=None):
        super().__init__(QHeaderView.Orientation.Vertical, parent)
        self.disabled_sections = set()

    def disable_section(self, row):
        self.disabled_sections.add(row)
        self.updateSection(row)  # 触发重绘

    def is_section_disabled(self, row):
        return row in self.disabled_sections

    def mousePressEvent(self, event):
        # 获取点击的行索引,已禁用则不处理
        row = self.logicalIndexAt(event.pos())
        if row != -1 and self.is_section_disabled(row):
            return
        super().mousePressEvent(event)

    def paintSection(self, painter, rect, logicalIndex):
        # 自定义禁用状态的表头绘制
        if self.is_section_disabled(logicalIndex):
            painter.save()
            painter.fillRect(rect, "#eee")
            painter.setPen("#888")
            painter.drawText(rect, Qt.AlignCenter, self.model().headerData(logicalIndex, self.orientation()))
            painter.restore()
        else:
            super().paintSection(painter, rect, logicalIndex)

# 在主窗口中使用自定义表头
class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        # 替换默认垂直表头
        custom_header = DisabledVerticalHeader(self.board)
        self.board.setVerticalHeader(custom_header)
        custom_header.sectionClicked.connect(self.pick_choice)
        self.custom_header = custom_header

    def pick_choice(self, row: int):
        if self.board.item(row, self.current_player).text():
            self.custom_header.disable_section(row)
            return
        
        # 正常选择业务逻辑
        # ...
        
        # 处理完成后禁用该行
        self.custom_header.disable_section(row)

两种方式对比:

  • 方法一:代码量少、上手快,适合小型项目;但动态添加禁用行时需注意样式表的拼接逻辑
  • 方法二:模块化程度高,样式和交互控制更灵活,适合复杂场景

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 02:28:19