Spyder中Tkinter按钮需多次点击才执行的问题求助
Tkinter按钮首次点击无响应(Spyder IDE环境)
所有用Tkinter在Spyder里编写的程序都存在同一个问题:首次运行后,点击任意按钮都无法在第一次点击时触发执行,必须多次点击才行。我附上自己写的密码生成器代码,问题并非仅出现在这个程序里。
from tkinter import * from tkinter import messagebox from random import randint, choice, shuffle import pyperclip import json # ---------------------------- PASSWORD GENERATOR ------------------------------- def generate_password(): print("generating password") letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'] numbers = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] symbols = ['!', '#', '$', '%', '&', '(', ')', '*', '+'] password_letters = [choice(letters) for _ in range(randint(8, 10))] password_numbers = [choice(numbers) for _ in range(randint(2, 4))] password_symbols = [choice(symbols) for _ in range(randint(2, 4))] password_list = password_letters + password_numbers + password_symbols shuffle(password_list) password = "".join(password_list) password_box.insert(0, password) pyperclip.copy(password) # ---------------------------- SAVE PASSWORD ------------------------------- def save(): print("saving") website = website_box.get() username = username_box.get() password = password_box.get() new_data = { website: { "username": username, "password": password, } } if len(website) == 0 or len(password) == 0: messagebox.showinfo(title="oops", message="Please fill in the empty fields") else: try: with open("data.json", "r") as data_file: # Read the file first # Reading old data data = json.load(data_file) except FileNotFoundError: with open("data.json", "w") as data_file: # Then write the file # Writing the updated data and saving it json.dump(new_data, data_file, indent=4) else: # Updating old data with the new data data.update(new_data) with open("data.json", "w") as data_file: json.dump(data, data_file, indent=4) finally: website_box.delete(0, END) # Removes previous entry in 'website box' when the user clicks 'Add' button password_box.delete(0, END) # Removes previous entry in 'password box' when the user clicks 'Add' button # ---------------------------- SEARCH FUNCTION ------------------------------- def search(): print("searching") searching_for = website_box.get() try: with open("data.json", "r") as data_file: data = json.load(data_file) except FileNotFoundError: messagebox.showinfo(title="Error", message="No data file found") else: if searching_for in data: username = data[searching_for]["username"] password = data[searching_for]["password"] messagebox.showinfo(title=searching_for, message=f"Username: {username}\nPassword: {password}") else: messagebox.showinfo(title="Error", message=f"No details for {searching_for} exists") # ---------------------------- UI SETUP ------------------------------- window = Tk() window.title("Password Manager") window.config(padx=50, pady=50) canvas = Canvas(width=200, height=200) lock_image = PhotoImage(file="logo.png") canvas.create_image(100, 100, image=lock_image) canvas.grid(column=1, row=0) # ------------------------ LABELS ------------------------ website_label = Label(text="Website:") website_label.grid(column=0, row=1) username_label = Label(text="Email/Username:") username_label.grid(column=0, row=2) password_label = Label(text="Password:") password_label.grid(column=0, row=3) # ------------------------ ENTRY BOXES ------------------------ website_box = Entry(width=20) website_box.grid(column=1, row=1, columnspan=1) website_box.focus() # Launches with cursor inside the website entry box to allow typing username_box = Entry(width=35) username_box.grid(column=1, row=2, columnspan=2) username_box.insert(0, "johnsmith@hotmail.com") # Prepopulate the username box with a username password_box = Entry(width=20) password_box.grid(column=1, row=3, columnspan=1) # ------------------------ BUTTONS ------------------------ generate_button = Button(text="Generate Password", width=11, command=generate_password) generate_button.grid(column=2, row=3) add_button = Button(text="Add", width=33, command=save) add_button.grid(column=1, row=4, columnspan=2) search_button = Button(text="Search", width=11, command=search) search_button.grid(column=2, row=1) window.mainloop()
解决方法
这个问题是Spyder IDE默认的图形后端设置和Tkinter事件循环冲突导致的,按以下步骤修复:
修改Spyder图形后端设置
- 打开Spyder,依次点击
Tools > Preferences > IPython console > Graphics - 将
Graphics backend选项从Inline改为Automatic或Tkinter - 重启Spyder后生效
- 打开Spyder,依次点击
临时代码修复(无需改IDE设置)
在代码最开头添加以下代码,强制指定Tkinter兼容的后端:import matplotlib matplotlib.use('TkAgg')(如果未安装matplotlib,先执行
pip install matplotlib)升级Spyder到最新版
旧版本Spyder可能存在此类兼容性bug,执行以下命令升级:pip install --upgrade spyder
原因说明
Spyder默认的Inline图形后端会拦截并处理GUI事件,导致Tkinter的事件循环在首次点击时无法正常响应,切换后端后Tkinter的事件循环可以独立运行,按钮点击就能正常触发。
内容的提问来源于stack exchange,提问作者Gary L
相关产品推荐
相关产品推荐

