我有以下问题。我用Tkinter创建了一个gui,当我在我的IDE(Spyder)中运行它时,一切都运行得很好,但当我将文件保存为并希望通过执行.py,everytime a window is created or a dialog opens, a second Tkinter window is poping up来启动它。当我将代码保存为.pyw时,会出现同样的问题。 我发布了一个持续存在相同问题的简短示例。
import tkinter as tk
from tkinter import messagebox
class test_GUI(tk.Frame):
def __init__(self,master=None):
super().__init__(master)
self._initializeWindow()
self._window.protocol("WM_DELETE_WINDOW", self.__on_closing)
self._window.mainloop()
def _initializeWindow(self):
self._window=tk.Tk()
self._window.title("The window I initzialized")
def __on_closing(self):
if(messagebox.askokcancel("Quit", "Quit program?")):
self._window.destroy()
self._window.quit()
app=test_GUI()
答案 0 :(得分:1)
您将班级定义为
class test_GUI(tk.Frame):
所以你的班级继承自tk.Frame
,这意味着你的班级基本上是一个具有额外功能的框架
当你这样做
super().__init__(master)
您初始化要继承的类,即tk.Frame
。目前,没有tk.Tk
个对象(和master=None
)。因为没有tk.Tk
的实例,Frame(或任何其他tkinter小部件)不能存在,所以tkinter会默默地为你创建一个。{1}}这是你的第一个窗口
之后你打电话给
self._window = tk.Tk()
自己制作tk.Tk
个实例。这是你的第二个窗口。除此之外你不想要两个窗口,你不应该同时运行多个tk.Tk
(或更准确地说是关联的Tcl解释器)的实例,因为这会导致意外的行为。
那么你怎么能解决这个问题呢?
您基本上有两个选择:删除继承或在启动课程之前启动tk.Tk
。
如果没有继承,您的应用可以像
一样构建import tkinter as tk
class test_GUI():
def __init__(self):
self._window=tk.Tk()
self._window.title("The window I initzialized")
self.button = tk.Button(self._window, text='Test button')
self.button.pack()
...
self._window.mainloop()
继承你可以这样做
import tkinter as tk
class test_GUI(tk.Frame):
def __init__(self, master=None):
super().__init__(master)
self.master = master
self.master.title("The window I initzialized")
self.button = tk.Button(self, text='Test button')
self.button.pack()
root = tk.Tk()
app=test_GUI(root)
app.pack(fill='both', expand=True)
root.mainloop()
两种方式都很好。我个人喜欢带继承的版本。另请参阅Bryan Oakley关于构建tkinter应用程序here的帖子。
答案 1 :(得分:0)
def _initializeWindow(self):
self._window=tk.Tk()
self._window.title("The window I initzialized")
self._window.withdraw()
self._window.withdraw()会删除第二个窗口。
super().__ init __(master)实际上负责第一个窗口。评论出来。在这种情况下,您不需要撤销在_initializeWindow中创建的窗口。
import tkinter as tk
from tkinter import messagebox
class test_GUI(tk.Frame):
def __init__(self,master=None):
#super().__init__(master)
self._initializeWindow()
self._window.protocol("WM_DELETE_WINDOW", self.__on_closing)
self._window.mainloop()
def _initializeWindow(self):
self._window=tk.Tk()
self._window.title("The window I initzialized")
#self._window.withdraw()
def __on_closing(self):
if(messagebox.askokcancel("Quit", "Quit program?")):
self._window.destroy()
self._window.quit()
app=test_GUI()
答案 2 :(得分:0)
对于那些试图对您的 GUI 进行单元测试并试图通过数据类插入根 tk 依赖项的人,您可以通过将 tk 初始化放在 __post_init__
方法中来解决多窗口问题:
from dataclasses import dataclass
import tkinter as tk
@dataclass
class App():
tk_root: tk.Tk = None
def __post_init__(self):
if self.tk_root is None:
self.tk_root = tk.Tk()
# ...
然后,如果您使用需要初始化根 Tk 的 tkinter 类(如 StringVars),则需要在 pytest 夹具中修补 tk:
import pytest
from unittest.mock import patch, MagicMock
from GUI import App
@pytest.fixture
def app():
with patch('GUI.tk'):
return GUI(tk_root=MagicMock())