You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

运行Tkinter代码出现‘Tk’小窗口及按钮样式异常问题求助

问题描述

运行以下代码时,会打开所需的主菜单窗口,同时弹出一个名为Tk的小型白色窗口。当我将MainMenu = Toplevel()替换为MainMenu = Tk()时,所有按钮都没有样式;若将样式配置放入main()函数,第二个窗口的按钮则无样式。请问哪里出错了?

代码示例

from tkinter import *
from tkinter import ttk
import tkinter as tk

style = ttk.Style()

def main():
    global MainMenu
    global style
    MainMenu = Toplevel()
    MainMenu.title('Rubiks Cube Solver')  # 创建标题为"Rubiks Cube Solver"的窗口,尺寸640x480,灰色背景
    MainMenu.geometry('640x480')
    MainMenu.config(bg='gray')

    style.configure('W.TButton', font=('Consolas', 25), foreground = 'black')  # 按钮样式配置

    
    Label(MainMenu, text='Rubiks Cube Solver', font=('Consolas', 40, 'bold'), bg='gray').pack()  # 显示标题
    
    timerbtn = ttk.Button(MainMenu, text='Timer', style='W.TButton')
    timerbtn.place(relx=0.5, rely=0.7, anchor=CENTER)   # 创建按钮并居中放置
    
    solverbtn = ttk.Button(MainMenu, text='Solver', style='W.TButton')
    solverbtn.place(relx=0.5, rely=0.5, anchor=CENTER)  
    
    databasebtn = ttk.Button(MainMenu, text='Database', style='W.TButton', command=maindatabase)
    databasebtn.place(relx=0.5, rely=0.3, anchor=CENTER)

def maindatabase():
    MainMenu.withdraw()
    DataMenu = Toplevel(MainMenu)
    DataMenu.title('Database Viewer')  # 创建标题为"Database Viewer"的窗口,尺寸640x480,灰色背景
    DataMenu.geometry('640x480')
    DataMenu.config(bg='gray')

    
    Label(DataMenu, text='Database Viewer', font=('Consolas', 40, 'bold'), bg='gray').pack()  # 显示标题

    
    searchbtn = ttk.Button(DataMenu, text='Search', style='W.TButton')
    searchbtn.place(relx=0.5, rely=0.5, anchor=CENTER)   # 创建按钮并居中放置
    
    fullbtn = ttk.Button(DataMenu, text='Full View', style='W.TButton')
    fullbtn.place(relx=0.5, rely=0.6, anchor=CENTER)  
    
    backbtn = ttk.Button(DataMenu, text='Back', command=lambda:[DataMenu.destroy(), MainMenu.deiconify()])
    backbtn.place(relx=0.9, rely=0.3, anchor=CENTER)
    
if __name__ == "__main__":
    main()

问题原因及解决方法

1. 弹出额外Tk窗口的原因

tkinter程序启动时,若未显式创建Tk()根窗口,调用Toplevel()时系统会自动生成一个默认的Tk根窗口,这就是那个额外弹出的白色小窗口。

解决方法:
在启动时先创建并隐藏根窗口,或者直接将主菜单设为根窗口。示例:

if __name__ == "__main__":
    root = Tk()
    root.withdraw()  # 隐藏默认根窗口
    main()
    root.mainloop()

或者直接把MainMenu = Toplevel()改成MainMenu = Tk(),并在main()函数末尾加上MainMenu.mainloop()。

2. 按钮样式失效的问题

  • 换成MainMenu = Tk()后样式失效:全局作用域中提前创建style = ttk.Style()时,根窗口还未存在,ttk样式需要绑定到已创建的根窗口,提前初始化会导致样式无法生效。
  • 样式放main()里第二个窗口按钮无样式:样式配置需要在根窗口创建后执行,且要确保所有子窗口能继承已配置的样式。

统一解决方法:

  1. 先创建根窗口,再初始化样式对象,确保样式与根窗口绑定。
  2. 样式只需配置一次,所有子窗口的ttk组件都会自动继承。

修改后的完整代码:

from tkinter import *
from tkinter import ttk
import tkinter as tk

def main():
    # 先创建主窗口
    MainMenu = Tk()
    MainMenu.title('Rubiks Cube Solver')
    MainMenu.geometry('640x480')
    MainMenu.config(bg='gray')

    # 主窗口创建后再初始化样式并配置
    style = ttk.Style(MainMenu)
    style.configure('W.TButton', font=('Consolas', 25), foreground='black')

    Label(MainMenu, text='Rubiks Cube Solver', font=('Consolas', 40, 'bold'), bg='gray').pack()
    
    timerbtn = ttk.Button(MainMenu, text='Timer', style='W.TButton')
    timerbtn.place(relx=0.5, rely=0.7, anchor=CENTER)
    
    solverbtn = ttk.Button(MainMenu, text='Solver', style='W.TButton')
    solverbtn.place(relx=0.5, rely=0.5, anchor=CENTER)  
    
    databasebtn = ttk.Button(MainMenu, text='Database', style='W.TButton', command=lambda: maindatabase(MainMenu))
    databasebtn.place(relx=0.5, rely=0.3, anchor=CENTER)

    MainMenu.mainloop()

def maindatabase(parent):
    parent.withdraw()
    DataMenu = Toplevel(parent)
    DataMenu.title('Database Viewer')
    DataMenu.geometry('640x480')
    DataMenu.config(bg='gray')

    Label(DataMenu, text='Database Viewer', font=('Consolas', 40, 'bold'), bg='gray').pack()

    # 直接使用已配置好的样式
    searchbtn = ttk.Button(DataMenu, text='Search', style='W.TButton')
    searchbtn.place(relx=0.5, rely=0.5, anchor=CENTER)
    
    fullbtn = ttk.Button(DataMenu, text='Full View', style='W.TButton')
    fullbtn.place(relx=0.5, rely=0.6, anchor=CENTER)  
    
    backbtn = ttk.Button(DataMenu, text='Back', command=lambda:[DataMenu.destroy(), parent.deiconify()])
    backbtn.place(relx=0.9, rely=0.3, anchor=CENTER)
    
if __name__ == "__main__":
    main()

关键要点总结

  • 必须先创建根窗口(Tk()),再初始化ttk样式对象,否则样式无法正确绑定。
  • 避免全局创建样式对象,最好在根窗口创建后再初始化样式。
  • 所有Toplevel()窗口要指定父窗口为根窗口,确保样式能正常继承。

内容的提问来源于stack exchange,提问作者Connor McGuire

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 02:47:05