【问题标题】:PyQt: How Can I set row heights of QTreeViewPyQt:如何设置 QTreeView 的行高
【发布时间】:2015-11-20 15:38:29
【问题描述】:

在 PyQt 中,我正在寻找一种方法来设置 QTreeView 中的行高(类似于 QTableView.setRowHeight(row, row_height),但 QTreeView 没有此功能)。 QAbstractItemModel 用于设置树模型。我阅读了一些建议here 使用和子类化QAbstractItemDelegate.sizeHint(option, index),但我不知道如何在我的树模型中正确调用它们。

任何最小的代码或建议将不胜感激。谢谢。

【问题讨论】:

    标签: qt pyqt pyside pyqt5 qtreeview


    【解决方案1】:

    在 Qt 5.9.2 中,我无法同时获得 QTreeView 自动调整列大小和自定义行高。使用 SizeHintRole 对高度有效,但似乎破坏了自动宽度。我的解决方案是将行设置为具有统一的高度,然后在 Python 3.7 中执行以下操作:

    self._tree = QTreeView()
    self._tree.setAlternatingRowColors(True)
    self._tree.setUniformRowHeights(True)
    
    ...
    
    fi = QFontInfo(self.font())
    
    self._tree.setStyleSheet(
        f'''
        QTreeView {{
            alternate-background-color: #E6FFFF;
        }}
        QTreeView::Item{{
            height:{fi.pixelSize() * 2}px;
        }}
        ''')
    

    我推测以这种方式设置颜色和高度可以稍微提高性能。

    【讨论】:

      【解决方案2】:

      使用样式表很简单:

      self.setStyleSheet("QTreeView::item { padding: 10px }")
      

      【讨论】:

        【解决方案3】:

        对于 PySide 绑定,这里是 AbstractItemModel 上的自定义委托的 Python 代码。

        from PySide import QtCore, QtGui
        
        tree = QTreeView()
        tree.model = QtGui.QAbstractItemModel()
        tree.setModel(tree.model)
        
        size = QtCore.QSize(20, 20)
        index = tree.model.index(row, col)   # row, col are your own
        tree.model.setData(index, size, QtCore.Qt.SizeHintRole)
        
        delegate = MyDelegate()
        tree.setItemDelegate(delegate)
        

        这只是将代码从 @RazrFalcon 翻译成 Python,是另一个用户请求的。

        【讨论】:

          【解决方案4】:

          QTreeView 根据为每个项目返回的数据和大小提示计算出每行的高度。我认为您可能只需要为所有项目或至少第一行(如果您有setUniformRowHeights(True))返回尺寸提示。顺便说一句,这可以显着提高性能,因此您应该尽可能设置它。

          因此您只需要实现您的AbstractItemModel.data() 方法即可在SizeHintRole 中返回大小提示。像这样的:

          def data(self, index, role = QtCore.Qt.DisplayRole):
              #  Check the index, possibly return None
              if role == QtCore.Qt.DisplayRole:
                  # Return the data
              elif role == QtCore.Qt.SizeHintRole:
                  return QtCore.QSize(item_width,item_height)
              # Other roles - maybe return None if you don't use them.
          

          编辑:大例子

          您说您仍然遇到问题,所以这里是一个完整的工作示例,基于标准 QT itemviews 示例。尝试改变 data 方法中返回的 QSize 以查看视图如何变化:

          import sys
          from PySide import QtCore,QtGui
          
          class TreeItem(object):
              def __init__(self, data, parent=None):
                  self.parentItem = parent
                  self.data = data
                  self.childItems = []
          
              def appendChild(self, item):
                  self.childItems.append(item)
          
              def row(self):
                  if self.parentItem:
                      return self.parentItem.childItems.index(self)
                  return 0
          
          
          class TreeModel(QtCore.QAbstractItemModel):
              def __init__(self, parent=None):
                  super(TreeModel, self).__init__(parent)
                  self.rootItem = TreeItem(None)
                  for i,c in enumerate("abcdefg"):
                      child = TreeItem([i,c],self.rootItem)
                      self.rootItem.appendChild(child)
                  parent = self.rootItem.childItems[1]
                  child = TreeItem(["down","down"],parent)
                  parent.appendChild(child)
          
              def columnCount(self, parent):
                  return 2
          
              def data(self, index, role):
                  if not index.isValid():
                      return None
                  if role == QtCore.Qt.DisplayRole:
                      item = index.internalPointer()
                      return item.data[index.column()]
                  elif role == QtCore.Qt.SizeHintRole:
                      print "giving size hint"
                      return QtCore.QSize(40,40)
          
                  return None
          
          
              def flags(self, index):
                  if not index.isValid():
                      return QtCore.Qt.NoItemFlags
                  return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
          
              def headerData(self, section, orientation, role):
                  if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
                      return ["A","B"][section]
                  return None
          
              def index(self, row, column, parent):
                  if not self.hasIndex(row, column, parent):
                      return QtCore.QModelIndex()
          
                  if not parent.isValid():
                      parentItem = self.rootItem
                  else:
                      parentItem = parent.internalPointer()
          
                  childItem = parentItem.childItems[row]
                  if childItem:
                      return self.createIndex(row, column, childItem)
                  else:
                      return QtCore.QModelIndex()
          
              def parent(self, index):
                  if not index.isValid():
                      return QtCore.QModelIndex()
                  parentItem = index.internalPointer().parentItem
                  if parentItem == self.rootItem:
                      return QtCore.QModelIndex()
                  return self.createIndex(parentItem.row(), 0, parentItem)
          
              def rowCount(self, parent):
                  if parent.column() > 0:
                      return 0
                  if not parent.isValid():
                      parentItem = self.rootItem
                  else:
                      parentItem = parent.internalPointer()
                  return len(parentItem.childItems)
          
          
          
          if __name__ == '__main__':
          
              app = QtGui.QApplication(sys.argv)
              model = TreeModel()
          
              view = QtGui.QTreeView()
              view.setModel(model)
              view.setWindowTitle("Simple Tree Model")
              view.show()
              sys.exit(app.exec_())
          

          【讨论】:

          • 谢谢。我实现了这个,但在我的情况下它还不起作用(条件'elif role == QtCore.Qt.SizeHintRole'永远不会满足),可能是因为我必须设置 setData 以便调用 sizeHint(如@RazrFalcon 所述) .一旦它工作,我将转发代码。再次感谢
          • 我刚刚对其进行了测试,它在我的示例中运行良好。调用 setData 不起作用:这只适用于 QStandardItemModels 而不是 QAbstractItemModel。你能提供一个我可以测试的精简版本的代码吗?视图应在首次访问模型时请求 SizeHintRole。
          • 我添加了一个完整的示例,我已经测试过并且工作正常。如果您仍然遇到问题,那么您的 AbstractItemModel 有其他问题。
          • 非常感谢,您的代码就像一个魅力!我在其他博客上没有找到这么简单的解决方案。我弄清楚了我的(愚蠢的)错误:我在复制粘贴的代码中尝试了您的解决方案,其中如果角色!= QtCore.Qt.DisplayRole 则返回无。无论如何,再次感谢!
          【解决方案5】:

          不了解 Python,但 C++ 代码应该是这样的:

          model->setData(model->index(/*your index*/), QSize(20, 20), Qt::SizeHintRole);
          

          您需要为树中的所有项目设置它。

          如果你想使用 QItemDelegate - 你不需要调用这个函数,你只需将你的委托设置为视图,就像这样(C++ 代码,但主要思想是一样的):

          treeView->setItemDelegate(new MyDelegate(this));
          

          视图会在需要时使用它。

          【讨论】:

          • 我使用 Python 的 PySide 绑定,所以我会将您的代码转换为 Python。 || tree = QTreeView() tree.model = QtGui.QAbstractItemModel() tree.setModel(tree.model) tree.model.setData(tree.model.index(someIndex), QtCore.QSize(20, 20), QtCore.Qt。大小提示角色) ||还有... || delegate = MyDelegate() tree.setItemDelegate(delegate)
          • @AlexanderHuszagh 将有助于将其转换为带有格式的单独答案。
          • 当然@neuronet,它在 5 后上升。
          猜你喜欢
          • 1970-01-01
          • 2011-11-19
          • 2017-04-23
          • 2021-04-23
          • 2014-06-12
          • 2012-01-11
          • 2011-05-23
          • 2023-04-03
          • 1970-01-01
          相关资源
          最近更新 更多