Как редактировать текст кнопки в том же месте в Python Tkinter? - PullRequest
0 голосов
/ 13 октября 2019

Я создаю 8 головоломок в tkinter, и я хочу, чтобы он был интерактивным для пользователя, чтобы пользователь мог соответствующим образом изменять состояния.
Итак, я создал окно с кнопкой, как показано ниже enter image description here

Теперь хочу, чтобы, если я нажму на кнопку 1, она стала редактируемой, как пользователь может изменить текст этой кнопки. Подскажите, пожалуйста, как мне это сделать?
Вот код для создания окна и добавления кнопок. Извините, это немного грязно.


from tkinter import *

window  = Tk()
window.geometry("500x500")
window.resizable(0,0)

btn_frame = Frame(window , width = 500 , height = 500 , bd = 2)
btn_frame.pack()
one = Button(btn_frame, text = "1" , width = 10 , height = 3)
one.grid(column = 0 , row = 0 , padx = 1 , pady = 1)
two = Button(btn_frame, text = "2" , width = 10 , height = 3)
two.grid(column = 1 , row = 0 , padx = 1 , pady = 1)
three = Button(btn_frame, text = "3" , width = 10 , height = 3)
three.grid(column = 2 , row = 0 , padx = 1 , pady = 1)

four = Button(btn_frame, text = "4" , width = 10 , height = 3)
four.grid(column = 0 , row = 1 , padx = 1 , pady = 1)
five = Button(btn_frame, text = "5" , width = 10 , height = 3)
five.grid(column = 1 , row = 1 , padx = 1 , pady = 1)
six = Button(btn_frame, text = "6" , width = 10 , height = 3)
six.grid(column = 2 , row = 1 , padx = 1 , pady = 1)

seven = Button(btn_frame, text = "7" , width = 10 , height = 3)
seven.grid(column = 0 , row = 2 , padx = 1 , pady = 1)
eight = Button(btn_frame, text = "8" , width = 10 , height = 3)
eight.grid(column = 1 , row = 2 , padx = 1 , pady = 1)
nine = Button(btn_frame, text = "" , width = 10 , height = 3)
nine.grid(column = 2 , row = 2 , padx = 1 , pady = 1)


list = [[one , two , three ], [four , five , six] , [seven , eight , nine]]

#window.after(5000 , window.destroy)
window.mainloop()

1 Ответ

1 голос
/ 13 октября 2019

Учитывая тот факт, что 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:

Demonstration in action

...