考虑到Button 只是看起来不同的Label,而command 参数自动绑定到<Button-1> 事件(单击鼠标左键);我将使用Label 来演示Entry 覆盖实际上如何解决您的问题。
基本上,我将创建一个继承自Label 的自定义小部件,它看起来像一个Button,点击后会变成一个接受文本的Entry。当用户在Entry 上按下Enter 时,它的值将转移到Label 并且覆盖Entry 从视图中消失。为了定义该自定义小部件,我将利用面向对象范例 (OOP) 及其继承概念。
完成后,您只需在代码中使用WriteLabel 而不是Button。如果您需要进一步自定义“按钮”的行为,您可以修改edit 方法:直接或通过派生一个覆盖edit 方法的新小部件(可能在定义自己的之前使用其祖先实现的小部件)行为)。
from tkinter import Tk, Entry, Label, StringVar
from typing import Any, Dict, Tuple
class WriteLabel(Label):
"""
Just a writable label widget.
"""
def __init__(self, master: Any = None, *args: Tuple[Any], **kwargs: Any):
"""
Constructor.
:param master: The parent of the widget.
:type master: Any.
:param args: Additional positional arguments.
:type args: Tuple[Any].
:param kwargs: Additional keyword arguments.
:type kwargs: Any.
"""
super().__init__(*args, master=master, **kwargs)
self._parent = master
self._value = StringVar()
self._entry_value = StringVar()
if 'text' in kwargs:
self._entry_value.set(value=kwargs['text'])
self.config(
textvariable=self._value,
relief='raised'
)
self._entry = Entry(
textvariable=self._entry_value,
justify='center'
)
self.behaviours()
self.update()
def behaviours(self) -> None:
"""
Sets the binding for interested events by defining in fact the behaviour of the widget.
:return: None.
:rtype: None.
"""
self.bind('<Button-1>',self.edit)
self.bind('<Configure>', self.save)
self._entry.bind('<FocusOut>', self.save)
self._entry.bind('<Return>', self.save)
def edit(self, _) -> None:
"""
It place the entry as overlay on top of the current widget.
:param _: The event object [unused].
:type _: Event.
:return: None.
:rtype: None.
"""
self._entry.place_forget()
self._entry_value.set(value=self._value.get())
self._entry.place(
x=self.winfo_x(),
y=self.winfo_y(),
width=self.winfo_width(),
height=self.winfo_height()
)
self._entry.focus_set()
def save(self, _) -> None:
"""
It hides the entry and copy its actual value to the current widget.
:param _: The event object [unused].
:type _: Event.
:return: None.
:rtype: None.
"""
self._entry.place_forget()
self._value.set(value=self._entry_value.get())
self.update()
if __name__ == '__main__':
from tkinter import *
window = Tk()
window.title('Application')
window.geometry("500x500")
window.resizable(width=False, height=False)
btn_frame = Frame(window, width=500, height=500, bd=2)
btn_frame.pack()
one = WriteLabel(btn_frame, text="1", width=10, height=3)
one.grid(column=0, row=0, padx=1, pady=1)
two = WriteLabel(btn_frame, text="2", width=10, height=3)
two.grid(column=1, row=0, padx=1, pady=1)
three = WriteLabel(btn_frame, text="3", width=10, height=3)
three.grid(column=2, row=0, padx=1, pady=1)
four = WriteLabel(btn_frame, text="4", width=10, height=3)
four.grid(column=0, row=1, padx=1, pady=1)
five = WriteLabel(btn_frame, text="5", width=10, height=3)
five.grid(column=1, row=1, padx=1, pady=1)
six = WriteLabel(btn_frame, text="6", width=10, height=3)
six.grid(column=2, row=1, padx=1, pady=1)
seven = WriteLabel(btn_frame, text="7", width=10, height=3)
seven.grid(column=0, row=2, padx=1, pady=1)
eight = WriteLabel(btn_frame, text="8", width=10, height=3)
eight.grid(column=1, row=2, padx=1, pady=1)
nine = WriteLabel(btn_frame, text="", width=10, height=3)
nine.grid(column=2, row=2, padx=1, pady=1)
items = [[one, two, three], [four, five, six], [seven, eight, nine]]
[i.save(None) for j in items for i in j]
window.mainloop()
这里有一个 gif 礼物展示它在 Windows 10 上的外观和工作原理: