Tkinter Entry组件设置readonly模式后变灰,如何仅禁止编辑?
如何让Tkinter Entry组件只读但保持正常外观(不变灰)?
我在开发项目时,想把Tkinter的Entry组件设置为只读模式,禁止用户修改内容,但设置state='readonly'后输入框会变灰(如图左上角输入框所示),不符合需求。请问有什么解决办法?
# Render canvas to contain tabular results from character table with scrollbars for GUI functionality self.character_records_canvas = tkinter.Canvas(self.options_main_frame, width = 1150, height = 800) # Define properties of scrollbars to render on frame self.scrollbar_vertical = tkinter.Scrollbar(self.options_main_frame, orient = tkinter.VERTICAL, command = self.character_records_canvas.yview) self.scrollbar_horizontal = tkinter.Scrollbar(self.options_main_frame, orient = tkinter.HORIZONTAL, command = self.character_records_canvas.xview) # Pack widget objects into main frame self.scrollbar_horizontal.pack(side = tkinter.BOTTOM, fill = tkinter.X) self.scrollbar_vertical.pack(side = tkinter.RIGHT, fill = tkinter.Y) self.character_records_canvas.pack(side = tkinter.LEFT, fill = tkinter.BOTH, expand = 1) # Configure canvas to communicate with scrollbars self.character_records_canvas.configure(yscrollcommand=self.scrollbar_vertical.set) self.character_records_canvas.configure(xscrollcommand=self.scrollbar_horizontal.set) # Bind box around canvas to enable scrollbar functionality self.character_records_canvas.bind('<Configure>', lambda e : self.character_records_canvas.configure(scrollregion = self.character_records_canvas.bbox("all"))) # Render child frame in canvas to display tabular results self.character_records_frame = tkinter.Frame(self.character_records_canvas) self.character_records_frame.pack(side = tkinter.LEFT, fill = tkinter.BOTH, expand = 1) # Configure the child frame to communicate with the canvas self.character_records_canvas.create_window((0,0), window = self.character_records_frame, anchor = "nw") self.character_records_canvas.configure(scrollregion = self.character_records_canvas.bbox("all")) # Return list of results from character database table query = "USE tictactoe_office_db;" self.db_obj.execute_query(query) query = """ SELECT * FROM `character`; """ character_results_list = self.db_obj.read_query(query) # Render table column headers on frame self.character_id_header = tkinter.Entry(self.character_records_frame, state = 'readonly') self.first_name_header = tkinter.Entry(self.character_records_frame) self.last_name_header = tkinter.Entry(self.character_records_frame) self.branch_name_header = tkinter.Entry(self.character_records_frame) self.game_wins_header = tkinter.Entry(self.character_records_frame) self.game_losses_header = tkinter.Entry(self.character_records_frame) self.match_wins_header = tkinter.Entry(self.character_records_frame) self.match_ties_header = tkinter.Entry(self.character_records_frame) self.match_losses_header = tkinter.Entry(self.character_records_frame) self.match_total_header = tkinter.Entry(self.character_records_frame) self.character_id_header.grid(row = 3, column = 0, sticky = "w") self.first_name_header.grid(row = 3, column = 1, sticky = "w") self.last_name_header.grid(row = 3, column = 2, sticky = "w") self.branch_name_header.grid(row = 3, column = 3, sticky = "w") self.game_wins_header.grid(row = 3, column = 4, sticky = "w") self.game_losses_header.grid(row = 3, column = 5, sticky = "w") self.match_wins_header.grid(row = 3, column = 6, sticky = "w") self.match_ties_header.grid(row = 3, column = 7, sticky = "w") self.match_losses_header.grid(row = 3, column = 8, sticky = "w") self.match_total_header.grid(row = 3, column = 9, sticky = "w") self.character_id_header.insert(0, "character_id") self.first_name_header.insert(0, "first_name") self.last_name_header.insert(0, "last_name") self.branch_name_header.insert(0, "branch_name") self.game_wins_header.insert(0, "game_wins") self.game_losses_header.insert(0, "game_losses") self.match_wins_header.insert(0, "match_wins") self.match_ties_header.insert(0, "match_ties") self.match_losses_header.insert(0, "match_losses") self.match_total_header.insert(0, "match_total") # Render tabular results on child frame for i in range(0, len(character_results_list)): for j in range(0,len(character_results_list[0])): self.entry = tkinter.Entry(self.character_records_frame) self.entry.grid(row = i + 4, column = j, sticky = "w") self.entry.insert(tkinter.END, str(character_results_list[i][j])) # Render column header border labels for i in range(0, 10): self.character_records_menu_label_2 = tkinter.Entry(self.character_records_frame) self.character_records_menu_label_2.grid(row = 2, column = i, sticky = "n") self.character_records_menu_label_2.insert(0, "-----------------------------------") # Render "back" buttons self.options_back_button_1 = tkinter.Button(self.character_records_frame, text = "BACK", width = 10, command = self.destroy_character_records_canvas) self.options_back_button_1.grid(row = 47, column = 9) self.options_back_button_2 = tkinter.Button(self.character_records_frame, text = "BACK", width = 10, command = self.destroy_character_records_canvas) self.options_back_button_2.grid(row = 47, column = 0)

解决方法
方法1:绑定事件阻止输入操作
保持Entry的state='normal',但绑定相关事件阻止用户输入、粘贴等修改操作:
# 创建Entry时不设置readonly,绑定事件拦截操作 self.character_id_header = tkinter.Entry(self.character_records_frame) # 阻止按键输入 self.character_id_header.bind("<Key>", lambda e: "break") # 阻止右键粘贴(Windows/Linux) self.character_id_header.bind("<Button-2>", lambda e: "break") # 阻止Mac快捷键粘贴 self.character_id_header.bind("<Command-v>", lambda e: "break") # 插入内容 self.character_id_header.insert(0, "character_id")
这种方式下Entry外观和正常状态完全一致,用户无法修改内容,但仍可选中复制。
方法2:用disabled状态并修正样式
如果使用state='disabled',可以手动设置前景色和背景色为正常Entry的样式,抵消变灰效果:
# 获取父容器的默认颜色(和正常Entry一致) normal_fg = self.character_records_frame.cget("fg") normal_bg = self.character_records_frame.cget("bg") # 创建disabled状态的Entry并设置样式 self.character_id_header = tkinter.Entry( self.character_records_frame, state='disabled', fg=normal_fg, bg=normal_bg ) # 注意:修改内容时需要临时切换状态 self.character_id_header.config(state='normal') self.character_id_header.insert(0, "character_id") self.character_id_header.config(state='disabled')
方法3:自定义只读Entry类
如果多处需要使用,可封装一个复用的只读Entry组件:
class ReadOnlyEntry(tkinter.Entry): def __init__(self, master=None, **kwargs): super().__init__(master, **kwargs) # 绑定所有修改相关事件 self.bind("<Key>", lambda e: "break") self.bind("<Button-2>", lambda e: "break") self.bind("<Command-v>", lambda e: "break") # 使用时直接创建 self.character_id_header = ReadOnlyEntry(self.character_records_frame) self.character_id_header.insert(0, "character_id")
内容的提问来源于stack exchange,提问作者JCam989
相关产品推荐
相关产品推荐

