在QTreeView(Qt / PySide / PyQt)中实现wordwrap的委托?

时间:2016-01-05 23:20:07

标签: qt pyqt pyqt4 pyside

我有一个带有自定义委托的树视图,我试图添加自动换行功能。自动换行工作正常,但sizeHint()似乎不起作用,因此当文本换行时,相关行不会展开以包含它。

我认为我在sizeHint()中通过返回document.size().height()来处理它。

def sizeHint(self, option, index):
    text = index.model().data(index)
    document = QtGui.QTextDocument()
    document.setHtml(text) 
    document.setTextWidth(option.rect.width())  
    return QtCore.QSize(document.idealWidth(), document.size().height())    

但是,当我打印出document.size().height()时,每个项目都是相同的。

另外,即使我手动设置高度(比如75)只是为了检查事情看起来是否合理,这棵树看起来就像金枪鱼被火箭筒击中(也就是说,这是一团糟):

WTF

如您所见,每行中的文本未在树中正确对齐。

类似帖子

之前出现过类似的问题,但我的问题没有解决方案(人们通常会说要重新实现sizeHint(),这就是我正在尝试的方式):

QTreeWidget set height of each row depending on content

QTreeView custom row height of individual rows

http://www.qtcentre.org/threads/1289-QT4-QTreeView-and-rows-with-multiple-lines

SSCCE

import sys
from PySide import QtGui, QtCore

class SimpleTree(QtGui.QTreeView):
    def __init__(self, parent = None):    
        QtGui.QTreeView.__init__(self, parent)
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
        self.setGeometry(500,200, 400, 300)  
        self.setUniformRowHeights(False) #optimize: but for word wrap, we don't want this!
        print "uniform heights in tree?", self.uniformRowHeights()
        self.model = QtGui.QStandardItemModel()
        self.model.setHorizontalHeaderLabels(['Task', 'Description'])
        self.setModel(self.model)
        self.rootItem = self.model.invisibleRootItem()
        item0 = [QtGui.QStandardItem('Sneeze'), QtGui.QStandardItem('You have been blocked up')]
        item00 = [QtGui.QStandardItem('Tickle nose, this is a very long entry. Row should resize.'), QtGui.QStandardItem('Key first step')]
        item1 = [QtGui.QStandardItem('<b>Get a job</b>'), QtGui.QStandardItem('Do not blow it')]
        self.rootItem.appendRow(item0)
        item0[0].appendRow(item00) 
        self.rootItem.appendRow(item1)
        self.setColumnWidth(0,150)
        self.expandAll()
        self.setWordWrap(True)
        self.setItemDelegate(ItemWordWrap(self))

class ItemWordWrap(QtGui.QStyledItemDelegate):
    def __init__(self, parent=None):
        QtGui.QStyledItemDelegate.__init__(self, parent)
        self.parent = parent
    def paint(self, painter, option, index):
        text = index.model().data(index) 
        document = QtGui.QTextDocument() # #print "dir(document)", dir(document)
        document.setHtml(text)       
        document.setTextWidth(option.rect.width())  #keeps text from spilling over into adjacent rect
        painter.save() 
        painter.translate(option.rect.x(), option.rect.y()) 
        document.drawContents(painter)  #draw the document with the painter
        painter.restore()
    def sizeHint(self, option, index):
        #Size should depend on number of lines wrapped
        text = index.model().data(index)
        document = QtGui.QTextDocument()
        document.setHtml(text) 
        document.setTextWidth(option.rect.width())  
        return QtCore.QSize(document.idealWidth() + 10,  document.size().height())       

def main():
    app = QtGui.QApplication(sys.argv)
    myTree = SimpleTree()
    myTree.show()
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()

1 个答案:

答案 0 :(得分:3)

问题似乎源于option.rect.width()传入QStyledItemDelegate.sizeHint()的值为-1。这显然是假的!

我通过在paint()方法中存储模型中的宽度并从sizeHint()访问它来解决这个问题。

因此,在paint()方法中添加以下行:

index.model().setData(index, option.rect.width(), QtCore.Qt.UserRole+1)

并在您的sizeHint()方法中,将document.setTextWidth(option.rect.width())替换为:

width = index.model().data(index, QtCore.Qt.UserRole+1)
if not width:
    width = 20
document.setTextWidth(width)