【问题标题】:Why is PyQt5 showing me my first file dialog but not my second one?为什么 PyQt5 向我显示我的第一个文件对话框而不是我的第二个?
【发布时间】:2021-07-18 09:48:49
【问题描述】:

我正在尝试使用 PyQt5 为 python 项目制作一个基本的前端 gui。具体来说,我想从两件事开始。首先,我想提示用户选择一个输入数据文件。然后,我想提示用户选择一个可以保存文件的目录。

可以在下面找到代码的工作示例。 我的问题是为什么当用户的代码中有两个提示时用户只收到一个提示(首先是输入文件,然后是保存目录)。代码没有抛出错误;注释掉输入文件例程(__init__Interface 方法中的self.select_save_directory())将允许运行保存目录例程。

首先,所有的导入。

import sys
from PyQt5 import QtWidgets # QtGui, QtCore

然后,提示用户选择输入 .csv 文件的小部件。

class FileSelectionWidget(QtWidgets.QWidget):

    def __init__(self, parent=None):
        super().__init__(parent)
        button = QtWidgets.QPushButton("Click here and select the data file you want to read")
        button.clicked.connect(self.on_clicked)
        lay = QtWidgets.QVBoxLayout(self)
        lay.addWidget(button)
        self._fpath = None

    @property
    def fpath(self):
        return self._fpath

    def on_clicked(self):
        dialog = QtWidgets.QFileDialog(
            self,
            "Select input file",
            "path",
            "*.csv",
            supportedSchemes=["file"],
            options=QtWidgets.QFileDialog.DontUseNativeDialog)
        fpath = dialog.getOpenFileName(None, 'Open file', '/home')[0]
        self._fpath = fpath
        self.close()
        print(self.fpath) # verify

然后,提示用户选择保存目录的小部件。

class DirectorySelectionWidget(QtWidgets.QWidget):

    """
    This class allows the user to select the directory
    to save files into via gui.
    """

    def __init__(self, parent=None):
        super().__init__(parent)
        button = QtWidgets.QPushButton("Click here and select the directory \nin which you would like to save files")
        button.clicked.connect(self.on_clicked)
        lay = QtWidgets.QVBoxLayout(self)
        lay.addWidget(button)
        self._savedir = None

    @property
    def savedir(self):
        return self._savedir

    def on_clicked(self):
        dialog = QtWidgets.QFileDialog()
        savedir = dialog.getExistingDirectory(None, "Select directory")
        self._savedir = savedir
        self.close()
        print(self.savedir) # verify

我计划添加我现有的后端。

class BackEnd():

    def __init__(self):
        super().__init__()

    # data processing functions

最后是从后端继承方法并且可以调用/实例化上面的UI方法的接口。

class Interface(BackEnd):

    def __init__(self):
        """

        """
        super().__init__()
        self.select_data_file()
        self.select_save_directory()
        ... # more back-end things

    def select_data_file(self):
        app = QtWidgets.QApplication(sys.argv)
        file_selection_widget = FileSelectionWidget()
        file_selection_widget.show()
        sys.exit(app.exec_())

    def select_save_directory(self):
        app = QtWidgets.QApplication(sys.argv)
        directory_selection_widget = DirectorySelectionWidget()
        directory_selection_widget.show()
        sys.exit(app.exec_())

if __name__ == '__main__':
    interface = Interface()

【问题讨论】:

    标签: python-3.x user-interface dialog pyqt5 widget


    【解决方案1】:

    sys.exit([arg]):
    退出 Python。

    这与 PyQt 无关。问题是select_data_fileselect_save_directory 都以sys.exit 结尾,导致您的程序立即退出,无论之后调用什么函数。

    除此之外,如果您要重用对话框(或在程序的生命周期内显示其他内容),通常最好避免重新创建 QApplication。

    您可以做的是在您的main 中启动一个单个 QApplication,然后将您的类更改为QDialog 而不是QWidget,并使用exec_() 而不是show() 显示它们。这允许保持与您现在相同的“阻止”效果(使用app.exec_()),一旦关闭对话框,该效果就会被清除,然后您可以在需要时显示其他窗口。

    请注意,为防止程序进一步退出,您应该使用setQuitOnLastWindowClosed(False),然后在您想真正退出时手动调用QApplication.quit()

    最后,请注意getOpenFileNamegetExistingDirectory 都是QFileDialog 的静态 方法。它们返回一个 new 预先构建的文件对话框实例,因此在此之前创建一个实例是没有意义的。
    您需要将参数添加到静态函数本身。

       def on_clicked(self):
            fpath, _ = QtWidgets.QFileDialog.getOpenFileName(
                None, 'Select input file', '/home', '*.csv', 
                options=QtWidgets.QFileDialog.DontUseNativeDialog)
            if fpath:
                self._fpath = fpath
                self.close()
    

    【讨论】:

    • 我没有足够的代表来投票,但谢谢。关于sys.exit 和只使用一个QApplication 的部分是有道理的。关于您的最后一段,当您说“在此之前创建实例毫无意义”时,您指的是什么实例?
    • on_clicked 的第一行中,您正在创建一个新实例(dialog = QtWidgets.QFileDialog(...))。该实例将永远不会被使用,因为使用 getOpenFileName 会创建一个全新的实例。请参阅我的编辑,其中包含完整功能并删除了该部分,因为它是不必要的
    猜你喜欢
    • 1970-01-01
    • 2020-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-21
    相关资源
    最近更新 更多