如何更改QTreeView中特定分支的颜色?

1 投票
2 回答
1731 浏览
提问于 2025-04-16 23:49

我有一个QTreeView(树形视图),我已经找到了通过在我的主类中使用setStyleSheet来设置它的样式的方法:

self.view.setStyleSheet("""
    QTreeView::item {
        margin: 2px;
    }
""")

这样做会给整个QTreeView设置样式。但是我想让树中的某些项目变成粗体。当我创建分支时(使用[父组件].appendRow("项目名称")),有没有办法给特定的项目“打标签”或者单独处理,以便它们可以以相同的方式被样式化?我觉得答案可能和“AccessibleName”或“ObjectName”属性有关,但我找不到相关的文档。

更新:这是我目前的进展:

#!/usr/bin/python
# -*- coding: utf-8 -*-

from __future__ import division
from __future__ import print_function
from future_builtins import *

import os, sys
from PySide.QtCore import *
from PySide.QtGui import *

path_to_media = '/Volumes/show/vfx/webisodes/%d1%/seq/%d2%/%d3%/renders/2d/comp/'

class FileTree(QTreeView):
    """Main file tree element"""
    def __init__(self):
        QTreeView.__init__(self)
    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Space or event.key() == Qt.Key_Return:
            index = self.selectedIndexes()[0]
            crawler = index.model().itemFromIndex(index)
            if crawler.uri:
                print("launching", crawler.uri)
                p = os.popen(('open -a "RV.app" "'+ crawler.uri) +'"', "r")
        QTreeView.keyPressEvent(self, event)

class Branch(QStandardItem):
    """Branch element"""
    def __init__(self, label, uri = None, tag = None):
        QStandardItem.__init__(self, label)
        self.uri = uri

class AppForm(QMainWindow):
    def __init__(self, parent = None):
        super(AppForm, self).__init__(parent)
        self.model = QStandardItemModel()
        self.view = FileTree()
        self.view.setStyleSheet("""
            QTreeView::item {
                margin: 2px;
            }
        """)
        self.view.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.view.setModel(self.model)
        self.setCentralWidget(self.view)
        self.Grow()
        # self.view.setSortingEnabled(True)

    def Grow(self):
        """Populates FileTree (using BuildBranch())"""
        global path_to_media
        self.path = {}
        self.path['source'] = path_to_media
        self.path['parts'] = []
        self.path['depth'] = 0
        self.path['crawl'] = {}
        for i in self.path['source'].split('%'):
            if i[0] == "d" and i[1].isdigit():
                self.path['depth'] += 1
            else:
                self.path['parts'].append(i)
        self.BuildBranch(self.path['parts'], self.path['depth'], parentWidget = self.model.invisibleRootItem())

    def BuildBranch(self, parts, depth, uri = '', count = 0, parent = '', parentWidget = ''):
        """Recursively crawls folder structure and adds appropriate branches"""
        if not uri: uri = parts[0]
        else: uri += parent + parts[count]
        try:
            if os.listdir(uri):
                for i in os.listdir(uri):
                    if i[0] != '.':
                        if count != depth:
                            if os.path.isdir(uri):
                                thisWidget = Branch(i)
                                parentWidget.appendRow(thisWidget)
                                self.BuildBranch(parts, depth, uri, count + 1, i, parentWidget = thisWidget)
                            else:
                                thisWidget = Branch(i)
                                parentWidget.appendRow(thisWidget)
                        elif count == depth:
                            thisWidget = Branch(i, uri + i, 'media')
                            parentWidget.appendRow(thisWidget)
            else:
                print("nothing here; nuking " + parent)
                # Need to add code to nuke unused branch
        except OSError:
            print("Folder structure error... nuking the branch")
            # Need to add code to nuke unused branch

def main():
    app = QApplication(sys.argv)
    form = AppForm()
    form.resize(800, 600)
    form.setWindowTitle('Qt Dailies')
    form.show()
    app.exec_()

if __name__ == "__main__":
    main()

更新 2:好的,我修改了我的Branch类,这样如果传入'bold',它就会让分支变成粗体(理论上是这样)...

class Branch(QStandardItem):
    def __init__(self, label, uri = None, tag = None):
        QStandardItem.__init__(self, label)
        self.uri = uri
        if tag == 'bold':
            self.setData(self.createBoldFont(), Qt.FontRole)
    def createBoldFont(self):
        if self.font: return self.font
        self.font = QFont()
        self.font.setWeight(QFont.Bold)
        return self.font

...但是虽然代码在运行,但似乎没有任何变化。我还有什么没明白的呢?

2 个回答

0

在你模型的 data() 方法里,你可以添加代码,根据项目的内容来设置字体。比如说,如果你想把某一行的所有内容都加粗,

def data(self, index, role):

    if role == QtCore.Qt.FontRole:
       if index.row() == 1:
           boldFont = QtGui.QFont()
           boldFont.setBold(True)
           return boldFont

你只需要一种方法来根据索引获取你分支的名称。这取决于你树形模型的实现方式。

Qt的模型/视图 教程里有个不错的例子,虽然是用C++写的。可以看看第2.2节(用角色扩展只读示例)。

1

Qt的模型-视图架构可以处理描述不同角色的数据。简单来说,这些角色可以是编辑数据、显示数据等等。这里我们关注的是字体角色(也就是 Qt::FontRole),因为字体有一个权重的分类,其中粗体就是一个选项。

在你构建树形结构时,首先需要确定哪些项目应该使用粗体。我假设你有一个方法可以判断这些项目是否需要粗体:

def should_be_bolded(self, item):
    return 1 # your condition checks

接下来,只需设置字体的权重,并使用它的 setData 方法来设置项目的字体角色:

def BuildBranch(...):
    thisWidget = Branch(i)
    if self.should_be_bolded(thisWidget):
        thisWidget.setData(self.createBoldFont(), Qt.FontRole)

def createFont(self):
    if self.font: return self.font
    self.font = QFont()
    self.font.setWeight(QFont.Bold)
    return self.font

等等……你已经有了一个 QStandardItem 的子类,所以可以直接使用它:

class Branch(QStandardItem):
    """Branch element"""
    def __init__(self, label, uri = None, tag = None):
        QStandardItem.__init__(self, label)
        self.uri = uri
        if self.should_be_bolded():
            self.bold_myself()

你需要修正 should_be_boldedbold_myself 这两个方法,进行相应的清理,但希望你能明白这个意思。

Stephen 指出,你也可以从 QAbstractItemModel 的某个子类(比如你正在使用的 QStandardItemModel)进行继承,并返回一个特定的 Qt.FontRole。他的做法让这些知识在模型中变得隐含。你需要决定这些知识最适合放在哪里,可以放在项目中、树形结构创建算法中、模型中,甚至是视图模型中。

撰写回答