简体   繁体   English

奇怪的行为:使用tkfiledialog的python应用程序,对话框没有第二次打开

[英]weird behaviour: python application using tkfiledialog, dialog doesn't open a 2nd time

I have a python application controlling a testbed for some technical device. 我有一个python应用程序,用于控制某些技术设备的测试平台。 Python itself doesn't use a GUI, everything is displayed in a browser and we use socket connections to communicate. Python本身不使用GUI,所有内容都显示在浏览器中,并且我们使用套接字连接进行通信。

There is one point, where the operator has to save a protocol file and we need a dialog to select this file. 有一点,操作员必须保存协议文件,我们需要一个对话框来选择该文件。 I decided to use the Tkinter plugin for that purpose. 我决定为此使用Tkinter插件。

So now I have a small module dialogs.py for all the GUI stuff, which is probably quite overdone, but nvm. 因此,现在我为所有GUI组件提供了一个小模块dialogs.py ,这可能有点过头了,但是是nvm。 Here it is: 这里是:

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

And then there is somewhere in another module: 然后另一个模块中的某个位置:

from helpers.dialogs import SaveFileGetter

# lots of code

def saveOnRemote(self):
    # code
    protocolFilePath = SaveFileGetter().get(ext='.html')
    # more code

# even more code

When the application runs for the first time everything is fine. 当应用程序第一次运行时,一切都很好。 But when run the 2nd time, the program reaches the line 但是当第二次运行时,程序到达该行

self.gui = Tk()

and nothing happens. 并没有任何反应。 No dialog does open, there is no exception, no beeping, nothing. 没有打开对话框,没有例外,没有提示音,什么也没有。 The program is so to speak frozen. 该程序可以说是冻结的。 The CPU usage stays high, so obviously there is something happening in the background, but the application itself doesn't move forward. CPU使用率一直很高,因此很明显在后台发生了一些事情,但是应用程序本身并没有前进。

To make things weird: If I use Toplevel() instead of Tk() the dialog does open multiple times, but occasionally there is an exception at the same line of code: 使事情变得奇怪:如果我使用Toplevel()而不是Tk(),则对话框会多次打开,但是偶尔在同一行代码中会出现异常:

self.gui = Toplevel()

The error displayed is: 显示的错误是:

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?)

And for master weirdness, this may happen at any time it seems, at the third execution, at the tenth ... or later. 对于大师级的怪异,这可能会在第三次执行,第十次或更晚的任何时候发生。 Later in operation it will be used maybe once per hour, but I can't accept that as the operator would have to restart the program to make it work properly again and btw cannot save the protocol file at that moment. 稍后在运行时,它可能每小时使用一次,但是我不能接受,因为操作员必须重新启动程序才能使其再次正常运行,并且btw此时无法保存协议文件。

I already wrote a little standalone script, requesting the save file dialog in an endless loop. 我已经编写了一个小独立脚本,以无休止的循环请求保存文件对话框。 Everything works as wanted using Tk() or Toplevel(), even without the self.gui.destroy() part. 即使没有self.gui.destroy()部分,也可以使用Tk()或Toplevel()一切正常运行。

So there must be something else in my application causing this behaviour. 因此,我的应用程序中肯定还有其他原因导致这种行为。 Of course I cannot show the whole code (too much, company work etc.) and I imagine it's hard to guess for you. 当然,我无法显示全部代码(太多,公司工作等),我想很难为您猜测。 None of my colleagues has a clue, I myself just started the 3rd month of being a software developer and am clueless as well. 我的同事们一无所知,我本人刚开始担任软件开发人员的第三个月,也一无所知。

So if you have the tiniest approach of an idea, what could be the reason, please tell me. 因此,如果您采用最小的想法,可能是什么原因,请告诉我。


Inspired by rolika's comment I changed my Getter class to: 受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()

Unfortunately it doesn't change anything visibly. 不幸的是,它并没有明显改变任何东西。

This really is just a suggestion: 这确实只是一个建议:

Have you tried it without supplying a parent? 您是否在没有父母的情况下尝试了它? Parent is optional, and if you don't supply, the dialog pops up over your app's root window. 父项是可选的,如果您不提供,则对话框会在应用程序的根窗口上方弹出。

Please see it here: http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/tkFileDialog.html 请在此处查看: http : //infohost.nmt.edu/tcc/help/pubs/tkinter/web/tkFileDialog.html

Just for the records, although it is no real answer, but a solution. 仅作记录,虽然不是真正的答案,但是解决方案。 I'm using wxPython instead of Tkinter now. 我现在使用wxPython而不是Tkinter So this is my Getter class: 这是我的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()

And it works, every time. 而且它每次都有效。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM