0

我为 tkinter 创建了一个自定义小部件,它布置了 5 个按钮。该小部件在大多数情况下都可以很好地工作。问题是我无法弄清楚如何将用户在小部件中按下的按钮传递给主应用程序。自定义小部件将最后按下的按钮存储在一个变量中,但我无法弄清楚如何让主应用程序看到它已被更改,而无需将按钮释放事件绑定到 root。我想尝试进一步构建这个自定义小部件,并且我希望它能够工作而不必做一些凌乱的黑客攻击。理想情况下,在下面的示例中,当按下按钮时,标签应更改以反映按下的按钮。例如,如果用户单击“2”按钮,则标签应更改为“2 X 2 = 4”。如何将按钮上的文字直接传递给主应用程序使用?希望我说得足够清楚。我希望能够像使用 .get() 方法的任何其他 tkinter 小部件一样从小部件中获取值。这是我正在使用的代码:

import tkinter as tk
from tkinter import ttk

class ButtonBar(tk.Frame):
    def __init__(self, parent, width=5,  btnLabels=''):
        tk.Frame.__init__(self, parent)
        self.btnLabels = []
        self.btnNames = []
        self.setLabels(btnLabels)
        self.selButton = None
        self.display()

    def getPressedBtn(self,t):
        """
        This method will return the text on the button.
        """
        self.selButton = t
        print(t)

    def createBtnNames(self):
        """
        This method will create the button names for each button. The button
        name will be returned when getPressedBtn() is called.
        """
        for i in range(0,5):
            self.btnNames.append(self.btnLabels[i])


    def display(self):
        """
        This method is called after all options have been set. It will display
        the ButtonBar instance.
        """
        self.clear()
        for i in range(len(self.btnLabels)):
            self.btn = ttk.Button(self, text=self.btnLabels[i], command=lambda t=self.btnNames[i]: self.getPressedBtn(t))
            self.btn.grid(row=0, column=i)

    def setLabels(self, labelList):
        if labelList == '':
            self.btnLabels = ['1', '2', '3', '4', '5']
            self.createBtnNames()

        else:
            btnLabelStr = list(map(str, labelList))
            labelsLen = len(btnLabelStr)

    def clear(self):
        """
        This method clears the ButtonBar of its data.
        """
        for item in self.winfo_children():
            item.destroy()


root = tk.Tk()

def getButtonClicked(event):
    global selBtn
    print(event)
    if example.winfo_exists():
        selBtn = example.selButton
        answer = int(selBtn) * 2
        myLabel.config(text='2 X ' + selBtn + ' = ' + str(answer))

tabLayout = ttk.Notebook(root)
tabLayout.pack(fill='both')
vmTab = tk.Frame(tabLayout)
myLabel = tk.Label(vmTab, text='2 X 0 = 0', width=50, height=10)
myLabel.pack()
vmTab.pack(fill='both')
tabLayout.add(vmTab, text='Volume Movers')
#  Create the ButtonBar.
example = ButtonBar(vmTab)
selBtn = None
example.pack()
lbl = tk.Label(root, text='')
root.mainloop()

我查看了有关 stackoverflow 的其他一些帖子。这个在 tkinter中创建自定义小部件非常有帮助,但它没有解决按钮问题。我虽然这个使用 Tkinter 的子类化可能会有所帮助。我不明白如果我使用 绑定事件root.bind("<ButtonRelease-1>", getButtonClicked),那么小部件可以正常工作。还有其他方法吗?

4

1 回答 1

1

我会说您使代码比应有的更复杂,您实际上只需要创建按钮并给它们一些作为参数传递的回调。并且该回调应至少采用一个参数,该参数将是按钮上的文本,该文本也将传递给该回调。

import tkinter as tk
from tkinter import ttk


class ButtonBar(tk.Frame):
    def __init__(self, master, values: list, command=None):
        tk.Frame.__init__(self, master)

        for col, text in enumerate(values):
            btn = ttk.Button(self, text=text)
            if command is not None:
                btn.config(command=lambda t=text: command(t))
            btn.grid(row=0, column=col, sticky='news')


def change_label(val):
    res = 2 * int(val)
    new_text = f'2 X {val} = {res}'
    my_label.config(text=new_text)


root = tk.Tk()

my_label = tk.Label(root, text='2 X 0 = 0')
my_label.pack(pady=100)

texts = ['1', '2', '3', '4', '5']
example = ButtonBar(root, values=texts, command=change_label)
example.pack()

root.mainloop()

您还可以将按钮基于值列表,以便您可以指定任何值,它将创建具有该文本的按钮,按下它们将使用其文本参数调用给定函数。这样你就可以将它用作任何其他小部件,它需要主控、一些值(文本)和一个命令。然后,您只需创建该回调,它将采用该一个参数,然后相应地更改标签。(我还删除了所有笔记本的东西,但我只是展示了如何实现你的要求)

另外:
我强烈建议遵循PEP 8 - Style Guide for Python Code。函数名和变量名应在 中snake_case,类名应在CapitalCase. 在函数和类声明周围有两个空行。对象方法定义周围有一个空行。

于 2021-12-19T22:51:49.807 回答