使用重试/取消对话框(在GUI线程中)检查QThread中的文件权限

2024-06-28 15:25:45 发布

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

我有一个运行在QThread中的进程,它生成一些我想保存到文件中的数据。在执行此操作之前,我需要检查是否具有写入文件的正确权限(这在Windows上),并且我确实希望使用带有“重试”和“取消”选项的QtWidgets.QMessageBox。这很容易通过例如(在我的例子中,典型的问题是用户在Excel中打开了xlsx文件)

reply = QtWidgets.QMessageBox.warning(
    self, "PermissionError",
    "Could not open file \"%s\". Try closing the file if it is open." % filename,
    QtWidgets.QMessageBox.StandardButton.Retry,
    QtWidgets.QMessageBox.StandardButton.Cancel
)

但这只在主(GUI)线程中有效,而不在单独的QThread中有效。从QThread执行此操作的好方法是什么

我已经用QThread发送到GUI线程中打开对话框的插槽的信号进行了一些测试。但是我发现很难将权限检查的结果反馈给QThread,逻辑很快就会变得混乱


Tags: 文件数据权限进程windows选项guiopen
1条回答
网友
1楼 · 发布于 2024-06-28 15:25:45

根据我的经验,将QThread子分类的方法不适合这些情况

一个简单的解决方案是使用worker(QThread)-thread方法,因为worker可以执行多个任务,例如执行繁重的计算和保存文件。因此GUI可以启动第一个任务,然后生活在另一个线程中的工作人员通过向GUI发送信号发出确认请求,然后GUI可以根据您的结果调用另一个任务

上述情况的一个例子如下:

from PySide2 import QtCore, QtGui, QtWidgets


class Worker(QtCore.QObject):
    requestSignal = QtCore.Signal(str)

    def __init__(self, parent=None):
        super(Worker, self).__init__(parent)
        self.data = None

    @QtCore.Slot()
    def process(self):
        print("start process")
        # emulate heavy task
        QtCore.QThread.sleep(5)
        self.data = "Foo"
        print("end process")
        self.requestSignal.emit("filename.xlsx")

    @QtCore.Slot(bool)
    def save_data(self, result):
        print(result)
        print(self.data)


class Widget(QtWidgets.QWidget):
    sendResult = QtCore.Signal(bool)

    def __init__(self, parent=None):
        super(Widget, self).__init__(parent)

        self.m_button = QtWidgets.QPushButton(
            "Press me", clicked=self.start_process
        )
        lay = QtWidgets.QVBoxLayout(self)
        lay.addWidget(self.m_button)

        self.m_thread = QtCore.QThread(self)
        self.m_thread.start()

        self.m_worker = Worker()
        self.m_worker.moveToThread(self.m_thread)
        self.m_worker.requestSignal.connect(self.on_request)
        self.sendResult.connect(self.m_worker.save_data)

    @QtCore.Slot()
    def start_process(self):
        # launch process
        QtCore.QTimer.singleShot(0, self.m_worker.process)
        self.m_button.setDisabled(True)

    @QtCore.Slot(str)
    def on_request(self, filename):
        reply = QtWidgets.QMessageBox.warning(
            self,
            "PermissionError",
            'Could not open file "%s". Try closing the file if it is open.'
            % filename,
            QtWidgets.QMessageBox.Retry,
            QtWidgets.QMessageBox.Cancel,
        )
        result = reply == QtWidgets.QMessageBox.Retry
        print(result)
        self.sendResult.emit(result)
        self.m_button.setDisabled(False)

    def closeEvent(self, event):
        super(Widget, self).closeEvent(event)
        self.m_thread.quit()
        self.m_thread.wait()


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)

    w = Widget()
    w.show()
    sys.exit(app.exec_())

相关问题 更多 >