我有一个python应用程序控制某些技术设备的测试平台。 Python本身并没有使用GUI,所有内容都显示在浏览器中,我们使用套接字连接进行通信。
有一点,操作员必须保存协议文件,我们需要一个对话框来选择这个文件。为此,我决定使用Tkinter插件。
所以现在我有一个小模块dialogs.py
用于所有GUI的东西,这可能相当过分,但是nvm。这是:
from Tkinter import Toplevel, Tk
from tkFileDialog import asksaveasfilename, askopenfilename, askdirectory
class Getter:
def _create(self):
self.gui = Tk() # create instance
self.gui.wm_attributes('-topmost', 1) # ensure it is on top
self.gui.geometry('0x0+0+0') # minimize
def _destroy(self):
self.gui.destroy() # destroy instance
def get(self):
pass
class SaveFileGetter(Getter):
def get(self, ext=None, dir=None, file=None):
self._create()
filename = asksaveasfilename(parent=self.gui, defaultextension=ext, initialdir=dir, initialfile=file) # show the dialog
self._destroy()
return filename
然后在另一个模块中有某处:
from helpers.dialogs import SaveFileGetter
# lots of code
def saveOnRemote(self):
# code
protocolFilePath = SaveFileGetter().get(ext='.html')
# more code
# even more code
当应用程序第一次运行时,一切都很好。但是当第二次运行时,程序到达
行self.gui = Tk()
没有任何反应。没有对话框打开,没有例外,没有哔哔声,没有。该计划可以说是冻结的。 CPU使用率保持很高,所以很明显后台发生了一些事情,但应用程序本身并没有向前发展。
使事情变得奇怪:如果我使用Toplevel()而不是Tk(),对话框会多次打开,但偶尔会在同一行代码中出现异常:
self.gui = Toplevel()
显示的错误是:
File "C:/path/to/my/project/somepythonfile.py", line 324, in saveOnRemote
protocolFilePath = SaveFileGetter().get(ext='.html')
File "C:/path/to/my/project/dialogs.py", line 22, in get
self._create()
File "C:/path/to/my/project/dialogs.py", line 8, in _create
self.gui = Toplevel()
File "C:\Python27\lib\lib-tk\Tkinter.py", line 2129, in __init__
BaseWidget.__init__(self, master, 'toplevel', cnf, {}, extra)
File "C:\Python27\lib\lib-tk\Tkinter.py", line 2086, in __init__
(widgetName, self._w) + extra + self._options(cnf))
TclError: out of stack space (infinite loop?)
对于大师的怪异,这可能发生在任何时候,第三次执行,第十次......或更晚。稍后运行它可能每小时使用一次,但我无法接受,因为操作员必须重新启动程序才能使其再次正常工作,并且btw无法在此时保存协议文件。
我已经写了一个小的独立脚本,在无限循环中请求保存文件对话框。即使没有self.gui.destroy()
部分,一切都按照需要使用Tk()或Toplevel()。
因此,我的应用程序中必须有其他内容导致此行为。当然我无法显示整个代码(太多,公司工作等),我想你很难猜到。我的同事们都没有任何线索,我自己刚刚开始担任软件开发人员的第3个月并且也很无能为力。
所以如果你有一个想法的最微小的方法,可能是什么原因,请告诉我。
受到rolika评论的启发,我将我的Getter课程改为:
class Getter:
def __init__(self):
self.gui = Tk()
self.gui.wm_attributes('-topmost', 1)
self.gui.geometry('0x0+0+0')
def __del__(self):
self.gui.destroy()
不幸的是,它并没有明显地改变任何东西。
答案 0 :(得分:0)
这只是一个建议:
您是否在未提供父母的情况下尝试过?家长是可选的,如果您不提供,则会在您应用的根窗口上弹出对话框。
请在此处查看:http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/tkFileDialog.html
答案 1 :(得分:0)
仅仅是为了记录,虽然它不是真正的答案,但是一个解决方案。我现在正在使用wxPython
而不是Tkinter
。所以这是我的Getter课程:
import wx
class Getter():
def __init__(self):
self.app = wx.App()
self.frame = wx.Frame(None, -1, style=wx.CAPTION, size=(0, 0))
def __del__(self):
self.app.Destroy()
def saveFile(self, ext='*.*', dir='', file='', title=''):
dialog = wx.FileDialog(self.frame, title, dir, file, '|'+ext, wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
dialog.ShowModal()
return dialog.GetPath()
每次都有效。