PyQt中如何让QTableView的编辑器跨两列显示?
问题
我正在开发一个基于PyQt的项目,遇到了QTableView及其项编辑器的问题。我的TableModel包含两列耦合紧密、需同步修改的数据。我已重写QStyledItemDelegate类,实现了基于QComboBox的编辑器,这部分功能正常。但我需要让编辑器跨两列显示,目前找到的示例仅能在用户点击的单个单元格打开编辑器,且通过重写updateEditorGeometry方法基于option参数调整几何。请问能否在updateEditorGeometry方法中获取邻列宽度,计算两列总宽度来调整QComboBox编辑器的几何?
当前简化版QStyledItemDelegate子类代码如下:
class ComboBoxDelegate(QStyledItemDelegate): def __init__(self, parent=None): super(SpinBoxDelegate, self).__init__(parent) def createEditor(self, parent, option, index): editor = QComboBox(parent) return editor def setEditorData(self, editor, index): pass def setModelData(self, editor, model, index): pass def updateEditorGeometry(self, editor, option, index): row = index.row() column = index.column() if column == 1: neighbourIndex = index.model().index(row, 0, QModelIndex()) editor.setGeometry(option.rect)
解决方案
完全可以通过updateEditorGeometry实现跨列编辑器,核心是从QTableView中获取目标列的宽度(Model不存储视图的列宽信息),再调整编辑器的几何区域。
具体实现步骤:
- 修正代码错误:
__init__方法里的super(SpinBoxDelegate, self)需改为super(ComboBoxDelegate, self),否则会引发继承类不匹配的错误。 - 在
updateEditorGeometry中,通过option.widget获取当前QTableView实例,调用columnWidth()方法获取指定列的宽度。 - 根据当前点击的列,计算编辑器的起始坐标和总宽度:
- 若点击第0列:编辑器从第0列起始位置开始,宽度为两列宽度之和
- 若点击第1列:编辑器向左偏移第0列的宽度,宽度同样为两列之和
- 用调整后的区域重新设置编辑器几何。
修改后的完整代码:
from PyQt5.QtWidgets import QStyledItemDelegate, QComboBox, QTableView, QRect from PyQt5.QtCore import Qt class ComboBoxDelegate(QStyledItemDelegate): def __init__(self, parent=None): super(ComboBoxDelegate, self).__init__(parent) def createEditor(self, parent, option, index): editor = QComboBox(parent) # 可在此添加下拉选项 # editor.addItems(["选项A", "选项B", "选项C"]) return editor def setEditorData(self, editor, index): # 从模型加载数据到编辑器 current_value = index.model().data(index, Qt.DisplayRole) if current_value in [editor.itemText(i) for i in range(editor.count())]: editor.setCurrentText(current_value) def setModelData(self, editor, model, index): # 将编辑器数据同步到模型,同时更新关联列 selected_value = editor.currentText() model.setData(index, selected_value, Qt.EditRole) # 同步修改邻列数据 neighbor_col = 1 if index.column() == 0 else 0 neighbor_index = model.index(index.row(), neighbor_col) model.setData(neighbor_index, f"{selected_value}_同步值", Qt.EditRole) def updateEditorGeometry(self, editor, option, index): table_view = option.widget if not isinstance(table_view, QTableView): editor.setGeometry(option.rect) return col = index.column() # 获取两列宽度 col0_width = table_view.columnWidth(0) col1_width = table_view.columnWidth(1) total_width = col0_width + col1_width # 计算编辑器的位置与大小 rect = option.rect if col == 0: new_rect = QRect(rect.x(), rect.y(), total_width, rect.height()) elif col == 1: new_rect = QRect(rect.x() - col0_width, rect.y(), total_width, rect.height()) else: new_rect = rect editor.setGeometry(new_rect)
额外说明:
- 编辑器作为QTableView的子控件,调整x坐标不会超出视图范围,只要计算逻辑正确就能实现跨列显示效果。
setModelData方法中可直接同步修改两列数据,满足耦合数据同步更新的需求。- 若后续需要支持更多列的跨列显示,可扩展列宽计算逻辑。
内容的提问来源于stack exchange,提问作者BVZ
相关产品推荐
相关产品推荐

