使用Tkinter编写程序保存YAML时出现pickle _tkinter.tkapp对象错误
问题修复:TypeError: cannot pickle '_tkinter.tkapp' object
错误原因
你在saveCfg函数里直接把ttk.Entry控件对象(name和password变量)赋值给了yaml_dict,而YAML序列化时需要将对象转换为可pickle的格式,但tkinter的控件实例无法被pickle,这就是报错的核心原因。另外代码里还有一处循环配置行权重的错误,会导致窗口布局异常。
修复步骤
- 获取输入文本而非控件对象:调用Entry控件的
.get()方法提取用户输入的字符串,而不是直接保存控件本身。 - 修正窗口行权重配置:原代码中循环配置行权重时,错误地始终使用
row作为索引,应该遍历0到row-1的索引。 - 优化YAML读写的安全性与编码:读写文件时指定编码,避免乱码;加载YAML时明确使用CLoader,保持一致性。
修复后的完整代码
import yaml import tkinter as tk from tkinter import ttk # 加载YAML配置,指定编码并使用CLoader with open("settings.yaml", "r", encoding="utf-8") as f: yaml_dict = yaml.load(f, yaml.CLoader) class Window(tk.Tk): def __init__(self, row, h, w): super().__init__() self.title("Title") # 窗口配置 self.window_width = h # 默认600 self.window_height = w # 默认200 screen_width = self.winfo_screenwidth() screen_height = self.winfo_screenheight() center_x = int(screen_width / 2 - self.window_width / 2) center_y = int(screen_height / 2 - self.window_height / 2) self.geometry(f'{self.window_width}x{self.window_height}+{center_x}+{center_y}') self.resizable(False, False) # 网格列配置 self.columnconfigure(0, weight=1) self.columnconfigure(1, weight=2) self.columnconfigure(2, weight=2) self.columnconfigure(3, weight=2) self.columnconfigure(4, weight=1) # 修正行权重配置:遍历0到row-1的索引 for i in range(row): self.rowconfigure(i, weight=1) def close(self): self.destroy() def saveCfg(window, name_entry, password_entry): # 获取输入框的文本内容,而非控件对象 yaml_dict['name'] = name_entry.get() yaml_dict['password'] = password_entry.get() # 写入YAML时指定编码,使用CDumper提高效率 with open('settings.yaml', 'w', encoding="utf-8") as f: yaml.dump(yaml_dict, f, yaml.CDumper) window.close() def userConfig(): cfgWindow = Window(8, 300, 200) cfgWindow.title("Bot Configuration") nameLabel = ttk.Label(cfgWindow, text="Enter name below:", font='TkFixedFont') nameLabel.grid(column=2, row=1) name_entry = ttk.Entry(cfgWindow) name_entry.grid(column=2, row=2) passwordLabel = ttk.Label(cfgWindow, text="Enter password below:", font='TkFixedFont') passwordLabel.grid(column=2, row=3) password_entry = ttk.Entry(cfgWindow) password_entry.grid(column=2, row=4) # 调整参数名,更清晰区分控件和窗口 confirmButton = ttk.Button(cfgWindow, text="Save Details", command=lambda: saveCfg(cfgWindow, name_entry, password_entry)) confirmButton.grid(column=2, row=5) cfgWindow.mainloop() userConfig()
原YAML文件(无需修改)
--- name: "name" password: "password"
内容的提问来源于stack exchange,提问作者Tom154ce
相关产品推荐
相关产品推荐

