qtreeview中几种元素的选择及其加工

2024-04-20 13:41:52 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个有两个QTreeView的程序。当我按下一个按钮时,我需要允许用户选择几个元素,当用户按下Escape时,将所选元素转移到一个等待函数,然后传递到handler函数。你知道吗

我试过使用线程、gevent和asyncio。你知道吗

这个函数在主类中,当我需要获取一些文件时,我运行这个函数。你知道吗

import sys
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtWidgets import *
import ui
import exampleQTV
import asyncio

class PyMap(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.select.clicked.connect(self.selectAction)

    def selectAction(self):
        self.getSomeFiles("Example", "Select some files, and press Escape", self.leftView)

    def getSomeFiles(self, title, path, view):
        # return QFileDialog.getOpenFileNames(self, title, path) ### older, and ugly variant                                                                                                
        buttonReply =  QMessageBox.information(self, "Information", "Select needed files",
                                               QMessageBox.Ok)
        loop = asyncio.get_event_loop()
        tasks = [loop.create_task(view.getFiles())]
        wait_tasks = asyncio.wait(tasks)
        result = loop.run_until_complete(asyncio.gather(*tasks))
        print (result)

        # result = view.getFiles()                                                                                                                                                          
        return result

    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 600)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
        self.gridLayout.setObjectName("gridLayout")
        self.rightView = exampleQTV.exampleQTV()
        self.rightView.setObjectName("rightView")
        self.gridLayout.addWidget(self.rightView, 1, 1, 1, 1)
        self.leftView = exampleQTV.exampleQTV()
        self.leftView.setObjectName("leftView")
        self.gridLayout.addWidget(self.leftView, 1, 0, 1, 1)
        self.select = QtWidgets.QPushButton(self.centralwidget)
        self.select.setObjectName("select")
        self.gridLayout.addWidget(self.select, 0, 0, 1, 2)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 22))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.select.setText(_translate("MainWindow", "Select"))


def main():
    app = QtWidgets.QApplication(sys.argv)
    window = PyMap()
    window.show()
    app.exec_()


if __name__ == '__main__':
    main()


此函数在QTreeView的类中起作用

from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from multiprocessing.pool import ThreadPool
import asyncio

class exampleQTV(QTreeView):
    def __init__(self):
        QTreeView.__init__(self)
        self.model = QFileSystemModel()
        self.model.setRootPath("/") # i'm on linux if you not change from / to for example D:\\
        self.setModel(self.model)
        self.eventCalled = False
        self.requestForEscape = False

        self.setColumnHidden(1, True)
        self.setColumnHidden(2, True)
        self.setColumnHidden(3, True)

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Escape:
            self.eventCalled = false

    def getFiles_thread(self):
        while True:
            if self.requestForEscape == True:
                if self.eventCalled == False:
                    return self.selectedIndexes()


    async def getFiles(self):
        self.setSelectionMode(QAbstractItemView.SelectionMode.MultiSelection)
        self.eventCalled = True

        self.requestForEscape = True

        pool = ThreadPool(processes=1)
        self.printMessage(1)
        async_result = pool.apply_async(self.getFiles_thread)
        self.printMessage(2)
        result = await async_result.get()
        self.printMessage(3)

        # ### Sorry if it not corrent, i'm just copied from doc                             
        # tasks = [self.getFiles_thread()]                                                  
        # loop = asyncio.get_event_loop()                                                   
        # result = loop.run_until_complete(asyncio.gather(*tasks))

        # task = [gevent.spawn(self.getFiles_thread(), 2)]                                  
        # result = gevent.joinall(task)                                                     

        # result = await self.getFiles_thread()                                             

        self.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
        return result

    def printMessage(self, message):
        print(message)

输出: 1 二


Tags: fromimportselfloopasynciotruedefresult
1条回答
网友
1楼 · 发布于 2024-04-20 13:41:52

GUI的任务,如选择项目、监听键盘事件等,不需要在另一个线程中执行,也不需要在另一个进程中执行。你知道吗

您的编程方式是程序化的,但是在GUI中使用了事件驱动编程的范例,在Qt的情况下,它是通过信号、插槽和事件来实现的。只有同步消耗大量时间的任务必须在另一个线程中执行,例如,我用QtCore.QThread.sleep(...)模拟了复制任务。你知道吗

考虑到上述情况,我实现了启用选择的逻辑,侦听keyPressEvent,用所选索引发出信号,并用数据调用重载函数。你知道吗

你知道吗主.py你知道吗

import sys
from functools import partial
from PyQt5 import QtCore, QtGui, QtWidgets
import exampleQTV


class PyMap(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.select.clicked.connect(self.selectAction)
        self.leftView.selectedIndexesSignal.connect(
            self.on_selectedIndexesSignal
        )

        thread = QtCore.QThread(self)
        thread.start()
        self.m_worker = Worker()
        self.m_worker.moveToThread(thread)

    @QtCore.pyqtSlot()
    def selectAction(self):
        buttonReply = QtWidgets.QMessageBox.information(
            self,
            "Information",
            "Select needed files",
            QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel,
        )
        if buttonReply == QtWidgets.QMessageBox.Ok:
            self.leftView.setEnableMultiSelection(True)

    @QtCore.pyqtSlot(list)
    def on_selectedIndexesSignal(self, indexes):
        paths = []
        for ix in indexes:
            path = ix.data(QtWidgets.QFileSystemModel.FilePathRole)
            paths.append(path)
        print(paths)
        wrapper = partial(self.m_worker.heavyTask, paths)
        QtCore.QTimer.singleShot(0, wrapper)

    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 600)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
        self.gridLayout.setObjectName("gridLayout")
        self.rightView = exampleQTV.ExampleQTV()
        self.rightView.setObjectName("rightView")
        self.gridLayout.addWidget(self.rightView, 1, 1, 1, 1)
        self.leftView = exampleQTV.ExampleQTV()
        self.leftView.setObjectName("leftView")
        self.gridLayout.addWidget(self.leftView, 1, 0, 1, 1)
        self.select = QtWidgets.QPushButton(self.centralwidget)
        self.select.setObjectName("select")
        self.gridLayout.addWidget(self.select, 0, 0, 1, 2)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 22))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.select.setText(_translate("MainWindow", "Select"))


class Worker(QtCore.QObject):
    @QtCore.pyqtSlot(list)
    def heavyTask(self, paths):
        print("started")
        # emulate heavy task
        QtCore.QThread.sleep(5)
        print(paths)
        print("finished")


def main():
    app = QtWidgets.QApplication(sys.argv)
    window = PyMap()
    window.show()
    app.exec_()


if __name__ == "__main__":
    main()

示例qtv.py

from PyQt5 import QtCore, QtGui, QtWidgets


class ExampleQTV(QtWidgets.QTreeView):
    selectedIndexesSignal = QtCore.pyqtSignal(list)

    def __init__(self, parent=None):
        super(ExampleQTV, self).__init__(parent)
        self.model = QtWidgets.QFileSystemModel(self)
        self.model.setRootPath(QtCore.QDir.rootPath())
        self.setModel(self.model)
        for i in (1, 2, 3):
            self.setColumnHidden(i, True)
        self.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
        self.expandAll()

    def setEnableMultiSelection(self, enable):
        self.setSelectionMode(
            QtWidgets.QAbstractItemView.MultiSelection
            if enable
            else QtWidgets.QAbstractItemView.NoSelection
        )

    def keyPressEvent(self, event):
        if event.key() == QtCore.Qt.Key_Escape:
            self.selectedIndexesSignal.emit(self.selectedIndexes())
            self.selectionModel().clearSelection()
            self.setEnableMultiSelection(False)
        super(ExampleQTV, self).keyPressEvent(event)

相关问题 更多 >