【问题标题】:How to edit button text in same place in python tkinter?如何在 python tkinter 中的同一位置编辑按钮文本?
【发布时间】:2019-10-13 05:43:29
【问题描述】:

我正在 tkinter 中构建一个 8 谜题求解器,我希望它是用户交互的,就像用户可以相应地更改状态一样。
所以我创建了一个带有如下按钮的窗口

现在希望,如果我单击按钮 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()

【问题讨论】:

  • “点击按钮...变为可编辑”Button 小部件不可编辑,您必须打开 Entry在点击的Button 顶部,输入并更新<Return> 上的Button 文本。

标签: python python-3.x user-interface tkinter


【解决方案1】:

考虑到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 上的外观和工作原理:

【讨论】:

    猜你喜欢
    • 2016-04-07
    • 1970-01-01
    • 2022-12-04
    • 2021-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多