python - QTreeView/QFileSystemModel - 比较文件和显示颜色
问题描述
我有 2 个 QTreeViews 都附有 QFileSystemModel。一个是本地目录,一个指向服务器。
我希望根据文件与相反位置的关系来更改文件上文本的颜色。例如: 如果服务器和本地具有相同的修改时间 - 设置为绿色 如果服务器是最新的 - 将本地设置为红色,服务器设置为橙色。等等等等。
我有多个这样的工作示例,但我一直遇到相同的障碍,缓慢的 UI 响应。我在两个 QFileSystemModels 中都使用 data() 函数来实现这一点,我尝试在 data() 之外线程化操作以返回颜色,但它只会让我的所有文件变成灯光秀。基于我移动鼠标,文件将随机变为绿色/红色/橙色。
我目前将日期修改列作为一种解决方法可见,但它不能帮助用户知道他们是否已经在本地拥有来自服务器的文件。
有没有人在没有 UI 突突的情况下有这样的工作?或者甚至找到了一种从线程返回结果并使其适用于正确条目的方法?
我很欣赏这可能看起来有点乱,但这是我初始化根的地方(其中一些全局变量在其他地方使用)
def initRoots(self, loc):
'''
This function sets the starting directories for both server and local
Does not handle anything except top level
'''
global localMask
global serverMask
global serverRoot
global userRoot
global GserverModel
global GlocalModel
if loc == "Server":
self.serverRoot = self.cb_serverWorkspace.currentText()
serverRoot = self.serverRoot
self.serverModel = ServerFileSystemModel()
GserverModel = self.serverModel
self.tv_serverFiles.setModel(self.serverModel)
#self.serverModel.setRootPath(QtCore.QDir.rootPath())
self.serverModel.setRootPath("")
self.tv_serverFiles.setRootIndex(self.serverModel.index(self.serverRoot))
self.tv_serverFiles.setUniformRowHeights(True)
self.tv_serverFiles.setExpandsOnDoubleClick(True)
self.tv_serverFiles.hideColumn(1)
self.tv_serverFiles.hideColumn(2)
self.tv_serverFiles.setColumnWidth(0,400)
if loc == "Local":
self.userRoot = self.cb_localWorkspace.currentText()
userRoot = self.userRoot
self.localModel = LocalFileSystemModel()
GlocalModel = self.localModel
self.tv_localFiles.setModel(self.localModel)
#self.localModel.setRootPath(QtCore.QDir.rootPath())
self.localModel.setRootPath("")
self.tv_localFiles.setRootIndex(self.localModel.index(self.userRoot))
self.tv_serverFiles.setUniformRowHeights(True)
self.tv_localFiles.setExpandsOnDoubleClick(True)
self.tv_localFiles.hideColumn(1)
self.tv_localFiles.hideColumn(2)
self.tv_localFiles.setColumnWidth(0,400)
然后我的两个 QFileSystemModel 差不多就是这个(这是我的非线程示例)
class ServerFileSystemModel(QtWidgets.QFileSystemModel):
def __init__(self, *args, **kwargs):
super(ServerFileSystemModel, self).__init__(*args, **kwargs)
def data(self, index, role=QtCore.Qt.DisplayRole):
try:
global GlocalModel
global GserverModel
serverPath = self.filePath(index)
localMask = userRoot + "/"
serverMask = serverRoot + "/"
newPath = serverPath.replace(serverMask, localMask)
serverIndex = GserverModel.index(serverPath)
localIndex = GlocalModel.index(newPath)
if role == QtCore.Qt.TextColorRole and serverPath.endswith(".fbx") and os.path.exists(newPath) and downloading == False:
if GlocalModel.lastModified(localIndex) == GserverModel.lastModified(serverIndex):
return QtGui.QColor("#58cd1c")
if GlocalModel.lastModified(localIndex) < GserverModel.lastModified(serverIndex):
return QtGui.QColor("#ed7011")
if GlocalModel.lastModified(localIndex) > GserverModel.lastModified(serverIndex):
return QtGui.QColor("#ed1111")
return super(ServerFileSystemModel, self).data(index, role)
except:
return super(ServerFileSystemModel, self).data(index, role)
有其他事情就告诉我。
编辑******
我被要求输入最少的可复制代码,所以我们开始吧
主窗口
class WorkspacerUI(QMainWindow, Ui_MainWindow):
def __init__(self, parent = None):
super(WorkspacerUI, self).__init__(parent)
self.setupUi(self)
self.userRoot = "D:/OCooke_Workspace"
self.serverRoot = "D:/OCooke_Server"
self.initRoots("Local")
self.initRoots("Server")
def initRoots(self, loc):
'''
This function sets the starting directories for both server and local
Does not handle anything except top level
'''
if loc == "Server":
self.serverModel = ServerFileSystemModel()
self.tv_serverFiles.setModel(self.serverModel)
#self.serverModel.setRootPath(QtCore.QDir.rootPath())
self.serverModel.setRootPath("")
self.tv_serverFiles.setRootIndex(self.serverModel.index(self.serverRoot))
self.tv_serverFiles.setUniformRowHeights(True)
self.tv_serverFiles.setExpandsOnDoubleClick(True)
self.tv_serverFiles.hideColumn(1)
self.tv_serverFiles.hideColumn(2)
self.tv_serverFiles.setColumnWidth(0,400)
if loc == "Local":
self.localModel = LocalFileSystemModel()
self.tv_localFiles.setModel(self.localModel)
#self.localModel.setRootPath(QtCore.QDir.rootPath())
self.localModel.setRootPath("")
self.tv_localFiles.setRootIndex(self.localModel.index(self.userRoot))
self.tv_serverFiles.setUniformRowHeights(True)
self.tv_localFiles.setExpandsOnDoubleClick(True)
self.tv_localFiles.hideColumn(1)
self.tv_localFiles.hideColumn(2)
self.tv_localFiles.setColumnWidth(0,400)
带有信号的 QRunnable
class WorkerSignals(QObject):
finished = Signal()
result = Signal(object)
progress = Signal(int)
class ColourWorker(QRunnable):
'''
Worker thread
Inherits from QRunnable to handler worker thread setup, signals and wrap-up.
:param callback: The function callback to run on this worker thread. Supplied args and
kwargs will be passed through to the runner.
:type callback: function
:param args: Arguments to pass to the callback function
:param kwargs: Keywords to pass to the callback function
'''
def __init__(self, fn, *args, **kwargs):
super(ColourWorker, self).__init__()
# Store constructor arguments (re-used for processing)
self.fn = fn
self.args = args
self.kwargs = kwargs
self.signals = WorkerSignals()
# Add the callback to our kwargs
self.kwargs['progress_callback'] = self.signals.progress
self.kwargs['indexy']
@Slot()
def run(self):
'''
Initialise the runner function with passed args, kwargs.
'''
# Retrieve args/kwargs here; and fire processing using them
try:
result = self.fn(*self.args, **self.kwargs)
except:
traceback.print_exc()
exctype, value = sys.exc_info()[:2]
self.signals.error.emit((exctype, value, traceback.format_exc()))
else:
self.signals.result.emit(result) # Return the result of the processing
finally:
self.signals.finished.emit() # Done
最后是 2 个 QSystemFileModels
class ServerFileSystemModel(QFileSystemModel):
def __init__(self, *args, **kwargs):
super(ServerFileSystemModel, self).__init__(*args, **kwargs)
self.threadpool = QThreadPool()
self.colour = None
def data(self, index, role=Qt.DisplayRole):
if role == Qt.TextColorRole:
worker = ColourWorker(self.execute_this_fn, indexy = index) # Any other args, kwargs are passed to the run function
worker.signals.result.connect(self.print_output)
worker.signals.finished.connect(self.thread_complete)
# Execute
self.threadpool.start(worker)
return self.colour
return super(ServerFileSystemModel, self).data(index, role)
#
def execute_this_fn(self, progress_callback, indexy):
serverPath = self.filePath(indexy)
localMask = "D:/OCooke_Workspace/"
serverMask = "D:/OCooke_Server/"
#create an expected path to the local using the server address
# D:/OCooke_Server/2020/file1 turns into D:/OCooke_Workspace/2020/file1
newPath = serverPath.replace(serverMask, localMask)
#Check the stat time between the two locations
if os.stat(newPath).st_mtime == os.stat(serverPath).st_mtime:
return QColor("#58cd1c")
if os.stat(newPath).st_mtime < os.stat(serverPath).st_mtime:
return QColor("#ed7011")
if os.stat(newPath).st_mtime > os.stat(serverPath).st_mtime:
return QColor("#ed1111")
else:
return None
def print_output(self, s):
#return the value of color
self.colour = s
def thread_complete(self):
#ive tried passing the color once the thread completes, no joy
pass
class LocalFileSystemModel(QFileSystemModel):
def __init__(self, *args, **kwargs):
super(LocalFileSystemModel, self).__init__(*args, **kwargs)
def data(self, index, role=Qt.DisplayRole):
return super(LocalFileSystemModel, self).data(index, role)
主要的
def main():
app = QApplication(sys.argv)
MainWindow = WorkspacerUI()
MainWindow.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
解决方案
推荐阅读
- swift - 如何在 Xcode 11 中将图像添加为具有透明背景的按钮
- reactjs - 在 useEffect 中反应条件
- deepsecurity - 从列表导入和创建智能文件夹
- r - mutate_all 除了一些列
- prolog - Prolog:最后一个元素和列表的其余部分
- javascript - 某些网站(例如 reddit)如何绕过广告拦截器来展示广告?
- javascript - 使用 Blazor(客户端)按像素绘制 HTML Canvas 图像的有效方法
- git - 如何使不同存储库中的不同文件夹保持同步?(只有某些文件夹不是整个回购)
- javascript - Javascript:在异步通信中继续循环之前等待来自 MIDI 设备的响应
- mysql - 不能在 mysql 表中的值中使用破折号(-)