【问题标题】:Repeated dialog window with Tkinter and Matplotlib on Mac OS XMac OS X 上带有 Tkinter 和 Matplotlib 的重复对话窗口
【发布时间】:2014-08-30 21:15:56
【问题描述】:

我是 Tkinter 的新手。我尝试使用下一个代码使用tkFileDialog.askopenfilename 打开一个文件,然后用 Matplotlib 绘制一些东西:

import matplotlib.pyplot as plt
import Tkinter, tkFileDialog

root = Tkinter.Tk()
root.withdraw()
file_path = tkFileDialog.askopenfilename()

x = range(10)
plt.plot(x)
plt.show()

运行上面的脚本后,我得到对话框窗口来打开我的文件。文件选择后,我得到重复的对话窗口来打开文件,并在屏幕底部出现一个新窗口。我知道问题是因为plt.show()。会发生什么以及如何避免重新打开对话框窗口?我应该为我的任务设置一个 Matplotlib 后端吗?

我的版本:

Tcl/Tk 8.5.9

Matplotlib 1.3.1

Tkinter $Revision: 81008 $

OS X 10.9.4

我发现了两个相关的 stackoverflow 问题: pyplot-show-reopens-old-tkinter-dialogmatplotlib-figures-not-working-after-tkinter-file-dialog 但没有答案。 root.destroy() 似乎对我不起作用。

【问题讨论】:

  • 我已经用tkFileDialog.askopenfilename() 执行的 Tk 命令的细分更新了我的答案。你能试试这个并描述你系统上的行为吗?
  • 我已将 matplotlib 的 Tk 调用分解为显示图形所需的绝对最小值。您能否检查 Edit 2 中的代码是否最终显示了预期的行为?
  • 请检查 Edit 3,它现在明确包含 matplotlib 的所有 Tk 操作,并且现在完全独立于 matplotlib。如果问题仍然存在,我们可以断定这是Tkinter中的一个错误,应该报告。
  • 我玩过Edit 3,问题依然存在。我也认为这是 Tkinter 问题。非常感谢@Stefan!

标签: python macos python-2.7 matplotlib tkinter


【解决方案1】:

当使用python test.py 运行时,以下似乎对我有用:

import matplotlib.pyplot as plt
import Tkinter, tkFileDialog

root = Tkinter.Tk()
root.withdraw()
file_path = tkFileDialog.askopenfilename()
root.destroy()

print file_path

x = range(10)
plt.plot(x)
plt.show()

我认为它可以工作,因为文件对话框的 Tk 实例在 matplotlib 启动它自己之前就被破坏了。有趣的是,它在运行时也适用于我

ipython --pylab=tk

我预计两次启动事件循环会出现问题。在这种情况下,规范的解决方案是在启动之前(再次)检查 Tk 是否已经在运行。

我在 MacOSX 10.7.5 上,自定义构建的 matplotlib(应该没关系)。

我唯一注意到的是,在尝试了这个之后,我的 Mac 上的触摸板滑动手势不再起作用......调查一下。

编辑

这是tkFileDialog.askopenfilename()执行的Tk命令的细分:

# breakdown of tkFileDialog.askopenfilename()
import Tkinter as Tk
window = Tk.Tk()
window.withdraw()
w = Tk.Frame(window)

s = w.tk.call('tk_getOpenFile', *w._options({}))
print s

w.destroy()
window.destroy()

当我运行它时(使用python test.py),我会看到文件打开对话框,我可以在其中选择一个文件。在“确定”时,它会打印文件名并退出。这在我的系统上每次都有效。但是,有时我的触摸板上的三指手势在运行此程序时会停止工作!而且程序退出后他们不会回来!即使在我杀死程序运行的终端之后也没有!!!

我发现将它们带回来的唯一方法是将以下 matplotlib 代码添加到test.py

import matplotlib
matplotlib.use('tkagg')
import matplotlib.pyplot as plt
plt.figure()     # simplified from plt.plot(range(10))
plt.show()

然后点击“图1”的标题栏。这立即带回了三指手势。我怀疑这只是Tkinter 中的一个错误。 (顺便说一下,我使用的是 Tcl/Tk 8.5)

我无法重现文件打开对话框在我的系统上不断重新启动的行为。

如果您在没有任何 matplotlib 命令的情况下启动 test.py,您能否描述一下您的系统会发生什么?

另外,由于 Tkinter 很旧而且显然有问题,我可以建议改用 Qt 吗?它不仅看起来更漂亮,而且更快捷,而且我没有任何错误问题。

编辑 2

我已经分解了 matplotlib 在非交互式环境中执行上述命令时所采取的 Tk 操作(即使用 python test.py 而不是来自 iPython)。这些是基本的后端调用:

import matplotlib.backends.backend_tkagg as backend
figManager = backend.new_figure_manager(1)
figManager.show()
backend.show.mainloop()

这些仍然是后端独立的。即,对于 Qt 图,只需使用:

import matplotlib.backends.backend_qt4agg as backend

如果我们进一步分解到后端特定层,我们有:

import matplotlib.backends.backend_tkagg as backend
import Tkinter as Tk
window = Tk.Tk()
window.withdraw()

# uncomment this to use the same Tk instance for tkFileDialog and matplotlib
#import tkFileDialog
#fname = tkFileDialog.askopenfilename(master=window)
#print fname

# figManager = backend.new_figure_manager(1)
from matplotlib.figure import Figure
figure = Figure()
canvas = backend.FigureCanvasTkAgg(figure, master=window)
figManager = backend.FigureManagerTkAgg(canvas, 1, window)

# figManager.show()
window.deiconify()

# backend.show.mainloop()
Tk.mainloop()

首先,使用注释掉的 tkFileDialog 调用运行并检查 matplotlib 图形是否出现并且行为正确。然后取消注释 tkFileDialog 调用,看看你是否最终得到了预期的行为。

如果不是,则必须继续分解FigureCanvasTkAggFigureManagerTkAgg 以了解发生了什么...

编辑 3

好的,既然问题仍然存在,让我们进一步分解 matplotlib 的 Tk 调用。以下代码完全隔离了我认为必不可少的所有 matplotlib 的 Tk 操作(因此不再需要从 matplotlib 导入任何内容!)。请注意,我没有生成工具栏并分配大量回调和按键事件。如果下面的代码现在可以工作,那么问题就在于这些。如果它不起作用,我们可以得出结论,这纯粹是一个 Tk 问题,并且很可能是一个应该报告的错误。代码如下:

import Tkinter as Tk
window = Tk.Tk()
window.withdraw()

# uncomment this to use the same Tk instance for tkFileDialog and matplotlib
#w = Tk.Frame(window)
#fname = w.tk.call('tk_getOpenFile', *w._options({}))
#print fname
#w.destroy()

# canvas = backend.FigureCanvasTkAgg(figure, master=window)
_tkcanvas = Tk.Canvas(master=window, width=640, height=480, borderwidth=4)
_tkphoto = Tk.PhotoImage(master=_tkcanvas, width=640, height=480)
_tkcanvas.create_image(320, 240, image=_tkphoto)
_tkcanvas.focus_set()

# figManager = backend.FigureManagerTkAgg(canvas, 1, window)
window.wm_title("Figure 1")
window.minsize(480, 360)
_tkcanvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)

# figManager.show()
window.deiconify()

# backend.show.mainloop()
Tk.mainloop()

请尝试注释掉一些行,看看是否可以使其正常工作。如果不是,我会断定这是Tkinter 中的一个错误,应该报告。

【讨论】:

  • 谢谢@Stefan 但python test.py 不适合我。我面临和以前一样的问题。顺便说一句,我忘了提到我的触摸板的问题。
  • 当我在没有任何 matplotlib 命令的情况下启动 test.py 时,一切都正常工作。添加 matplotlib 命令仍会导致出现第二个对话框窗口奇怪的触摸板行为。是的,我已经开始研究 Qt。非常感谢@Stefan!
  • 抱歉@Stefan 回复晚了!我很忙。当 Tk 块被评论时,一切都运行良好。当我取消注释它时,我得到对话框窗口并再次重复对话框窗口。但现在好多了,因为我的触摸板没有问题。
  • 我有同样的问题,Tkinter 破坏了我的 Mac 的手势。在 Terminal.app 中运行 killall Dock 可以修复它,但这有点让人头疼。
猜你喜欢
  • 2013-07-20
  • 1970-01-01
  • 2011-07-27
  • 2016-08-17
  • 2011-08-30
  • 2012-03-16
  • 2020-10-22
  • 1970-01-01
  • 2019-07-28
相关资源
最近更新 更多