实现QTableView行高随编辑器高度增加自动扩展
QTableView行高随QTextEdit编辑器实时调整问题解决
我来帮你拆解并解决这几个问题:
核心问题:行高无法随编辑器换行实时更新
你遇到的contentsChange信号中获取的文档高度滞后的问题,本质是QTextDocument的内容修改信号触发时,文档的布局计算还没完成。此时self.size()返回的是布局更新前的旧值,只有当事件循环处理完布局任务后,高度才会更新——这也是为什么1秒定时器能拿到正确高度的原因。
解决方法很简单,用QTimer.singleShot(0)延迟触发行高调整,让Qt先完成文档布局计算:
def contents_change(self, position, chars_removed, chars_added): # 用0延迟让文档布局完成后再调整行高 QtCore.QTimer.singleShot(0, lambda: parent.parent().resizeRowToContents(index.row()))
这样就能在换行发生后立即获取到正确的文档高度,同步调整行高。
另外,记得在编辑器销毁时清空self.editor引用,避免无效对象访问:
def createEditor(self, parent, option, index): class Editor(QtWidgets.QTextEdit): def resizeEvent(self, event): super().resizeEvent(event) self.editor = Editor(parent) # 添加销毁信号处理 self.editor.destroyed.connect(lambda: setattr(self, 'editor', None)) self.editor.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) # ... 其余代码不变
疑问1:编辑器输入时字符轻微跳动
这个问题大概率是编辑器的渲染设置和单元格绘制时的设置不一致导致的。你需要确保paint方法、sizeHint方法和编辑器的QTextDocument使用完全相同的配置:
- 统一文档边距:在
paint、sizeHint和编辑器的文档中都设置setDocumentMargin(0) - 统一字体:确保编辑器的字体和
option.font一致,比如在createEditor里添加:self.editor.setFont(option.font) - 移除编辑器不必要的
resizeEvent打印和自定义Document的drawContents打印,避免额外的性能开销导致的渲染波动。
疑问2:sizeHint方法被频繁调用(4次)
这是Qt视图的正常行为——当单元格内容变化、行高调整、视图重绘时,Qt会多次请求sizeHint来确保布局正确。如果觉得调用次数过多,可以通过缓存优化:
class SegmentsTableViewDelegate(QtWidgets.QStyledItemDelegate): def __init__(self, *args): super().__init__(*args) self.editor = None self._size_hint_cache = {} # 缓存sizeHint结果 def sizeHint(self, option, index): # 生成缓存键,用index的行/列+内容哈希 cache_key = (index.row(), index.column(), hash(option.text)) if cache_key in self._size_hint_cache: return self._size_hint_cache[cache_key] self.initStyleOption(option, index) doc = QtGui.QTextDocument() doc.setTextWidth(option.rect.width()) doc.setDefaultFont(option.font) doc.setDocumentMargin(0) doc.setHtml(option.text) doc_height_int = int(doc.size().height()) result = QtCore.QSize(int(doc.idealWidth()), doc_height_int) # 更新缓存 self._size_hint_cache[cache_key] = result return result def createEditor(self, parent, option, index): # 编辑器创建时清空对应行的缓存 cache_key = (index.row(), index.column(), hash(option.text)) if cache_key in self._size_hint_cache: del self._size_hint_cache[cache_key] # ... 其余代码不变
这样可以避免重复计算相同内容的sizeHint,减少调用次数。
额外优化:行高调整的效率
你当前的resizeRowsToContents方法会遍历所有行,其实可以只调整当前编辑的行,避免不必要的计算:
def resizeRowsToContents(self): # 只调整当前选中的行(如果有编辑的话) if self.currentIndex().isValid(): row = self.currentIndex().row() hint = self.sizeHintForRow(row) self.verticalHeader().resizeSection(row, hint)
内容的提问来源于stack exchange,提问作者mike rodent
相关产品推荐
相关产品推荐

