【问题标题】:IPython Notebook: Open/select file with GUI (Qt Dialog)IPython Notebook:使用 GUI 打开/选择文件(Qt 对话框)
【发布时间】:2014-01-14 11:15:30
【问题描述】:

当您在笔记本中对不同的数据文件执行相同的分析时,以图形方式选择数据文件可能会很方便。

在我的 python 脚本中,我通常实现一个 QT 对话框,返回所选文件的文件名:

from PySide import QtCore, QtGui

def gui_fname(dir=None):
    """Select a file via a dialog and return the file name.
    """
    if dir is None: dir ='./'
    fname = QtGui.QFileDialog.getOpenFileName(None, "Select data file...", 
            dir, filter="All files (*);; SM Files (*.sm)")
    return fname[0]

但是,从笔记本运行此功能

full_fname = gui_fname()

导致内核死机(并重新启动):

有趣的是,将这 3 个命令放在 3 个单独的单元格中是可行的

%matplotlib qt
full_fname = gui_fname()
%matplotlib inline

但是当我将这些命令放在一个单元格中时,内核又死了。

这可以防止创建像 gui_fname_ipynb() 这样的函数,该函数透明地允许使用 GUI 选择文件。

为方便起见,我创建了一个笔记本来说明问题:

关于如何在 IPython Notebook 中执行文件选择对话框有什么建议吗?

【问题讨论】:

    标签: ipython ipython-notebook


    【解决方案1】:

    在 Windows 上使用 Anaconda 5.0.0(Python 3.6.2、IPython 6.1.0),以下两个选项都适用于我。

    选项 1:完全在 Jupyter 笔记本中:

    单元格 1:

    %gui qt
    
    from PyQt5.QtWidgets import QFileDialog
    
    def gui_fname(dir=None):
        """Select a file via a dialog and return the file name."""
        if dir is None: dir ='./'
        fname = QFileDialog.getOpenFileName(None, "Select data file...", 
                    dir, filter="All files (*);; SM Files (*.sm)")
        return fname[0]
    

    单元格 2:

    gui_fname()
    

    这对我有用,但似乎有点……脆弱。如果我将这两件事合并到同一个单元格中,它就会崩溃。或者如果我省略了%gui qt,它就会崩溃。如果我“重新启动内核并运行所有单元”,它就不起作用。所以我有点喜欢这个其他选项...

    更可靠的选项:在新进程中打开对话框的单独脚本

    (基于 mkrog 代码here。)

    将以下内容放入名为 blah.py 的单独 Python 脚本中:

    from sys import executable, argv
    from subprocess import check_output
    from PyQt5.QtWidgets import QFileDialog, QApplication
    
    def gui_fname(directory='./'):
        """Open a file dialog, starting in the given directory, and return
        the chosen filename"""
        # run this exact file in a separate process, and grab the result
        file = check_output([executable, __file__, directory])
        return file.strip()
    
    if __name__ == "__main__":
        directory = argv[1]
        app = QApplication([directory])
        fname = QFileDialog.getOpenFileName(None, "Select a file...", 
                directory, filter="All files (*)")
        print(fname[0])
    

    ...在你的 JUPYTER 笔记本中

    import blah
    blah.gui_fname()
    

    【讨论】:

    • 这在 Windows 10 上使用 Jupyter (Classic) Notebook v6.1.5 对我有用,但它有点笨重,因为我希望笔记本是独立的。所以我使用 iPython Notebook 魔术命令“%%writefile >>”将上面的 Python 输入单元源代码写入本地文件,然后导入模块并在下一个单元中运行它。 Qt 文件选择器以“pop-behind”而不是弹出对话框的形式打开,这有点麻烦。但是,它有效。谢谢。
    【解决方案2】:

    我有一个通用代码,它可以毫无问题地完成工作。这是我的建议:

    try:
        from tkinter import Tk
        from tkFileDialog import askopenfilenames
    except:
        from tkinter import Tk
        from tkinter import filedialog
    
    Tk().withdraw() # we don't want a full GUI, so keep the root window from appearing
    filenames = filedialog.askopenfilenames() # show an "Open" dialog box and return the path to the selected file
    
    print (filenames)
    

    希望对你有用

    【讨论】:

    • 只有当 jupyter 实验室实例与浏览器在同一主机上运行时,所有这些解决方案才有效,这是否正确?
    • 这不适用于 Jupyter Classic Notebook v6.1.5 或 Spyder v4.2.3。它挂起 iPythonNB 内核并需要重新启动服务器内核。我尝试在 Spyder 中使用它,它会打开 Tkinter 对话框,但仅作为“pop-behind”,然后在选择文件后,文件名实际上从未返回给调用程序。这让我在 2021 年投下反对票。
    【解决方案3】:

    这种行为是 IPython 中的一个错误:

    https://github.com/ipython/ipython/issues/4997

    这里已修复:

    https://github.com/ipython/ipython/pull/5077

    打开 gui 对话框的功能应该可以在当前 master 和即将发布的 2.0 版本上运行。

    迄今为止,最新的 1.x 版本 (1.2.1)包含修复的反向移植。

    编辑:示例代码仍然会导致 IPython 2.x 崩溃,请参阅 this issue

    【讨论】:

      猜你喜欢
      • 2015-02-17
      • 1970-01-01
      • 2021-10-28
      • 2016-06-10
      • 1970-01-01
      • 2012-03-02
      • 2011-04-25
      • 2012-08-19
      • 2012-05-06
      相关资源
      最近更新 更多