向 QTreeView/QFileSystemModel 中的项目添加附加信息
Add additional information to items in a QTreeView/QFileSystemModel
我想根据存储在数据库中的许多属性以及项目是文件夹还是文件,以不同方式呈现 QTreeView 中的每个项目。但是,我不明白 QTreeView 或 QFileSystemModel 如何与委托进行通信。每当必须绘制一个项目时,包括在初始化期间,我希望为委托提供它需要的所有参数,然后在委托中使用一系列 if
语句来设置特定项目的绘制方式。我只找到了 .setItemDelegate
方法,不知道实际调用委托的时间或方式,也不知道它如何循环遍历模型中的所有项目。下面是一个基于在线资料的例子。有两个问题:
我将无法正常工作的代码放在注释中。一旦我了解了委托如何从 QTreeView 接收信息(或调用 class),我相信我可以完成剩下的工作。
我无法让 QTreeView 的这个子class显示文件夹和文件图标。
代码:
import sys
from PySide.QtCore import *
from PySide.QtGui import *
class fileSystemDelegate(QItemDelegate):
def __init__(self, parent=None):
QItemDelegate.__init__(self, parent) #shouldn't this insure the icons are drawn?
def paint(self, painter, option, index):
painter.save()
# set background
painter.setPen(QPen(Qt.NoPen))
if option.state & QStyle.State_Selected: #DURING DRAW LOOP: idx = self.currentIndex(); if self.fileSystemModel.isDir(idx): PAINT RED
painter.setBrush(QBrush(Qt.red))
else:
painter.setBrush(QBrush(Qt.white)) #ELSE PAINT WHITE
painter.drawRect(option.rect)
# draw item
painter.setPen(QPen(Qt.black))
text = index.data(Qt.DisplayRole)
painter.drawText(option.rect, Qt.AlignLeft, text) #there is no painter.drawIcon?
painter.restore()
class fileSystemBrowser(QTreeView):
def __init__(self, parent=None):
super().__init__(parent)
delegate = fileSystemDelegate()
self.setItemDelegate(delegate) # how to provide delegate with additional info about the item to be drawn ?
self.fileSystemModel = QFileSystemModel()
self.fileSystemModel.setRootPath(QDir.currentPath())
self.setModel(self.fileSystemModel)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = fileSystemBrowser()
window.show()
sys.exit(app.exec_())
编辑 1:
我以字典的形式添加了一个示例 "database",并将方法更改为依赖数据方法而不是委托。我希望这段代码在树中显示信息时执行字典查找,因此当用户在 Microsoft Windows 计算机上输入 C:\Program Files\Internet Explorer\
时打印到终端。但是,它只显示目录而不向终端打印任何内容。我想知道:
如何让数据方法中的 if
语句在绘制时触发显示中的每个项目?
如何在显示默认图标后在同一行显示图标?
代码:
import sys
from PySide.QtCore import *
from PySide.QtGui import *
database = {'C:\Program Files\Internet Explorer\ExtExport.exe':(1,3), 'C:\Program Files\Internet Explorer\iexplore.exe':(0,0)}
class fileSystemBrowser(QTreeView):
def __init__(self, parent=None):
super().__init__(parent)
self.fileSystemModel = QFileSystemModel()
self.fileSystemModel.setRootPath(QDir.currentPath())
self.setModel(self.fileSystemModel)
def data(self, index, role=Qt.DisplayRole):
if index.isValid():
path = self.fileSystemModel.filePath(index)
if self.fileSystemModel.isDir(index):
if database.get(path) != None:
if database[path][0] > 0:
print("Acting on custom data 0.") # add another icon after the regular folder icon
if database[path][1] > 0:
print("Acting on custom data 1.") # add another (different) icon after the regular folder or previous icon
if __name__ == '__main__':
app = QApplication(sys.argv)
window = fileSystemBrowser()
window.show()
sys.exit(app.exec_())
编辑 2:
Subclass模型确实有所作为。现在脚本似乎在每个项目上调用我的新数据方法。不幸的是,数据方法还不起作用,所以结果是一个没有图标或文本的树视图。有时我收到错误:"QFileSystemWatcher: failed to add paths: C:/PerfLogs"。根据在线示例,我已经评论了我认为可能存在错误的地方,但我还不能让它发挥作用。我做错了什么?
import sys
from PySide.QtCore import *
from PySide.QtGui import *
database = {'C:\Program Files\Internet Explorer\ExtExport.exe':(1,3), 'C:\Program Files\Internet Explorer\iexplore.exe':(0,0)}
class newFileModel(QFileSystemModel):
def __init__(self, parent=None):
QFileSystemModel.__init__(self, parent)
#self.elements = [[Do I need this? What should go here?]]
def data(self, index, role=Qt.DisplayRole):
if index.isValid():
path = self.filePath(index)
if self.isDir(index):
if database.get(path) != None:
if database[path][0] > 0:
print("Acting on custom data 0.") # I can add code here for different color text, etc.
if database[path][1] > 0:
print("Acting on custom data 1.") # I'll add code later
#return self.data(index, role) # Do I need this about here?
class fileSystemBrowser(QTreeView):
def __init__(self, parent=None):
super().__init__(parent)
self.fileSystemModel = newFileModel()
self.fileSystemModel.setRootPath(QDir.currentPath())
self.setModel(self.fileSystemModel)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = fileSystemBrowser()
window.show()
sys.exit(app.exec_())
这是一个基本演示,展示了如何添加带有图标和其他格式的额外列。请注意,已尝试规范化文件路径,以便比较和字典查找应该更可靠:
import sys
from PySide.QtCore import *
from PySide.QtGui import *
database = {
QFileInfo('C:\Program Files\Internet Explorer\ExtExport.exe').absoluteFilePath(): (1, 3),
QFileInfo('C:\Program Files\Internet Explorer\iexplore.exe').absoluteFilePath(): (0, 0),
}
class FileSystemModel(QFileSystemModel):
def __init__(self, parent=None):
super().__init__(parent)
style = qApp.style()
self.icons = [
style.standardIcon(QStyle.SP_MessageBoxInformation),
style.standardIcon(QStyle.SP_MessageBoxWarning),
]
def columnCount(self, parent=QModelIndex()):
return super().columnCount(parent) + 1
def data(self, index, role=Qt.DisplayRole):
extra = False
if index.isValid():
extra = index.column() == self.columnCount(index.parent()) - 1
info = self.fileInfo(index)
path = info.absoluteFilePath()
if path in database:
major, minor = database[path]
print('found:', (major, minor), path)
if extra:
if role == Qt.DecorationRole:
if major > 0:
return self.icons[0]
else:
return self.icons[1]
elif role == Qt.DisplayRole:
return '%s/%s' % (major, minor)
elif role == Qt.ForegroundRole:
if minor > 2:
return QColor('red')
if not extra:
return super().data(index, role)
def headerData(self, section, orientation, role=Qt.DisplayRole):
if (orientation == Qt.Horizontal and
role == Qt.DisplayRole and
section == self.columnCount() - 1):
return 'Extra'
return super().headerData(section, orientation, role)
class FileSystemBrowser(QTreeView):
def __init__(self, parent=None):
super().__init__(parent)
self.fileSystemModel = FileSystemModel()
self.fileSystemModel.setRootPath(QDir.currentPath())
self.setModel(self.fileSystemModel)
self.header().moveSection(self.fileSystemModel.columnCount() - 1, 1)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = FileSystemBrowser()
window.show()
sys.exit(app.exec_())
编辑:
data
方法中用到的角色都记录在ItemDataRole enum下,介绍如下:
Each item in the model has a set of data elements associated with it,
each with its own role. The roles are used by the view to indicate to
the model which type of data it needs. Custom models should return
data in these types.
对于已添加的额外列,有必要提供所有内容,因为它是虚拟列,不属于基础模型的一部分。但是对于其他列,我们可以直接调用 base-class 实现来获取默认值(当然,如果需要,我们也可以为这些列 return 自定义值来修改现有行为) .
我想根据存储在数据库中的许多属性以及项目是文件夹还是文件,以不同方式呈现 QTreeView 中的每个项目。但是,我不明白 QTreeView 或 QFileSystemModel 如何与委托进行通信。每当必须绘制一个项目时,包括在初始化期间,我希望为委托提供它需要的所有参数,然后在委托中使用一系列 if
语句来设置特定项目的绘制方式。我只找到了 .setItemDelegate
方法,不知道实际调用委托的时间或方式,也不知道它如何循环遍历模型中的所有项目。下面是一个基于在线资料的例子。有两个问题:
我将无法正常工作的代码放在注释中。一旦我了解了委托如何从 QTreeView 接收信息(或调用 class),我相信我可以完成剩下的工作。
我无法让 QTreeView 的这个子class显示文件夹和文件图标。
代码:
import sys
from PySide.QtCore import *
from PySide.QtGui import *
class fileSystemDelegate(QItemDelegate):
def __init__(self, parent=None):
QItemDelegate.__init__(self, parent) #shouldn't this insure the icons are drawn?
def paint(self, painter, option, index):
painter.save()
# set background
painter.setPen(QPen(Qt.NoPen))
if option.state & QStyle.State_Selected: #DURING DRAW LOOP: idx = self.currentIndex(); if self.fileSystemModel.isDir(idx): PAINT RED
painter.setBrush(QBrush(Qt.red))
else:
painter.setBrush(QBrush(Qt.white)) #ELSE PAINT WHITE
painter.drawRect(option.rect)
# draw item
painter.setPen(QPen(Qt.black))
text = index.data(Qt.DisplayRole)
painter.drawText(option.rect, Qt.AlignLeft, text) #there is no painter.drawIcon?
painter.restore()
class fileSystemBrowser(QTreeView):
def __init__(self, parent=None):
super().__init__(parent)
delegate = fileSystemDelegate()
self.setItemDelegate(delegate) # how to provide delegate with additional info about the item to be drawn ?
self.fileSystemModel = QFileSystemModel()
self.fileSystemModel.setRootPath(QDir.currentPath())
self.setModel(self.fileSystemModel)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = fileSystemBrowser()
window.show()
sys.exit(app.exec_())
编辑 1:
我以字典的形式添加了一个示例 "database",并将方法更改为依赖数据方法而不是委托。我希望这段代码在树中显示信息时执行字典查找,因此当用户在 Microsoft Windows 计算机上输入 C:\Program Files\Internet Explorer\
时打印到终端。但是,它只显示目录而不向终端打印任何内容。我想知道:
如何让数据方法中的
if
语句在绘制时触发显示中的每个项目?如何在显示默认图标后在同一行显示图标?
代码:
import sys
from PySide.QtCore import *
from PySide.QtGui import *
database = {'C:\Program Files\Internet Explorer\ExtExport.exe':(1,3), 'C:\Program Files\Internet Explorer\iexplore.exe':(0,0)}
class fileSystemBrowser(QTreeView):
def __init__(self, parent=None):
super().__init__(parent)
self.fileSystemModel = QFileSystemModel()
self.fileSystemModel.setRootPath(QDir.currentPath())
self.setModel(self.fileSystemModel)
def data(self, index, role=Qt.DisplayRole):
if index.isValid():
path = self.fileSystemModel.filePath(index)
if self.fileSystemModel.isDir(index):
if database.get(path) != None:
if database[path][0] > 0:
print("Acting on custom data 0.") # add another icon after the regular folder icon
if database[path][1] > 0:
print("Acting on custom data 1.") # add another (different) icon after the regular folder or previous icon
if __name__ == '__main__':
app = QApplication(sys.argv)
window = fileSystemBrowser()
window.show()
sys.exit(app.exec_())
编辑 2:
Subclass模型确实有所作为。现在脚本似乎在每个项目上调用我的新数据方法。不幸的是,数据方法还不起作用,所以结果是一个没有图标或文本的树视图。有时我收到错误:"QFileSystemWatcher: failed to add paths: C:/PerfLogs"。根据在线示例,我已经评论了我认为可能存在错误的地方,但我还不能让它发挥作用。我做错了什么?
import sys
from PySide.QtCore import *
from PySide.QtGui import *
database = {'C:\Program Files\Internet Explorer\ExtExport.exe':(1,3), 'C:\Program Files\Internet Explorer\iexplore.exe':(0,0)}
class newFileModel(QFileSystemModel):
def __init__(self, parent=None):
QFileSystemModel.__init__(self, parent)
#self.elements = [[Do I need this? What should go here?]]
def data(self, index, role=Qt.DisplayRole):
if index.isValid():
path = self.filePath(index)
if self.isDir(index):
if database.get(path) != None:
if database[path][0] > 0:
print("Acting on custom data 0.") # I can add code here for different color text, etc.
if database[path][1] > 0:
print("Acting on custom data 1.") # I'll add code later
#return self.data(index, role) # Do I need this about here?
class fileSystemBrowser(QTreeView):
def __init__(self, parent=None):
super().__init__(parent)
self.fileSystemModel = newFileModel()
self.fileSystemModel.setRootPath(QDir.currentPath())
self.setModel(self.fileSystemModel)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = fileSystemBrowser()
window.show()
sys.exit(app.exec_())
这是一个基本演示,展示了如何添加带有图标和其他格式的额外列。请注意,已尝试规范化文件路径,以便比较和字典查找应该更可靠:
import sys
from PySide.QtCore import *
from PySide.QtGui import *
database = {
QFileInfo('C:\Program Files\Internet Explorer\ExtExport.exe').absoluteFilePath(): (1, 3),
QFileInfo('C:\Program Files\Internet Explorer\iexplore.exe').absoluteFilePath(): (0, 0),
}
class FileSystemModel(QFileSystemModel):
def __init__(self, parent=None):
super().__init__(parent)
style = qApp.style()
self.icons = [
style.standardIcon(QStyle.SP_MessageBoxInformation),
style.standardIcon(QStyle.SP_MessageBoxWarning),
]
def columnCount(self, parent=QModelIndex()):
return super().columnCount(parent) + 1
def data(self, index, role=Qt.DisplayRole):
extra = False
if index.isValid():
extra = index.column() == self.columnCount(index.parent()) - 1
info = self.fileInfo(index)
path = info.absoluteFilePath()
if path in database:
major, minor = database[path]
print('found:', (major, minor), path)
if extra:
if role == Qt.DecorationRole:
if major > 0:
return self.icons[0]
else:
return self.icons[1]
elif role == Qt.DisplayRole:
return '%s/%s' % (major, minor)
elif role == Qt.ForegroundRole:
if minor > 2:
return QColor('red')
if not extra:
return super().data(index, role)
def headerData(self, section, orientation, role=Qt.DisplayRole):
if (orientation == Qt.Horizontal and
role == Qt.DisplayRole and
section == self.columnCount() - 1):
return 'Extra'
return super().headerData(section, orientation, role)
class FileSystemBrowser(QTreeView):
def __init__(self, parent=None):
super().__init__(parent)
self.fileSystemModel = FileSystemModel()
self.fileSystemModel.setRootPath(QDir.currentPath())
self.setModel(self.fileSystemModel)
self.header().moveSection(self.fileSystemModel.columnCount() - 1, 1)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = FileSystemBrowser()
window.show()
sys.exit(app.exec_())
编辑:
data
方法中用到的角色都记录在ItemDataRole enum下,介绍如下:
Each item in the model has a set of data elements associated with it, each with its own role. The roles are used by the view to indicate to the model which type of data it needs. Custom models should return data in these types.
对于已添加的额外列,有必要提供所有内容,因为它是虚拟列,不属于基础模型的一部分。但是对于其他列,我们可以直接调用 base-class 实现来获取默认值(当然,如果需要,我们也可以为这些列 return 自定义值来修改现有行为) .