Учитывая тот факт, что Button
- это просто другой Label
с аргументом command
, автоматически привязанным к событию <Button-1>
(которое является одним щелчком левой кнопки мыши);Я буду использовать Label
, чтобы продемонстрировать, как наложение Entry
действительно решает вашу проблему.
По сути, я создам собственный виджет, унаследованный от Label
, который выглядит как Button
, ипри нажатии превращается в Entry
, который принимает текст. Когда пользователь нажимает Enter
на Entry
, его значение передается на Label
и наложение Entry
исчезает из поля зрения. Чтобы определить этот пользовательский виджет, я воспользуюсь объектно-ориентированной парадигмой (ООП) и ее концепцией наследования.
После этого в вашем коде вам просто нужно будет использовать 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: