单击时如何将按钮值从自定义小部件传递到 tkinter 中的主应用程序

Posted

技术标签:

【中文标题】单击时如何将按钮值从自定义小部件传递到 tkinter 中的主应用程序【英文标题】:how to pass button value from custom widget to main application in tkinter when clicked 【发布时间】:2022-01-21 16:07:35 【问题描述】:

我为 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()

我查看了有关 *** 的其他一些帖子。这个creating a custom widget in tkinter 很有帮助,但它没有解决按钮问题。我虽然这个Subclassing with Tkinter 可能会有所帮助。我不明白如果我使用root.bind("<ButtonRelease-1>", getButtonClicked) 绑定事件,那么小部件可以正常工作。还有其他方法吗?

【问题讨论】:

【参考方案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。在函数和类声明周围有两个空行。对象方法定义周围有一个空行。

【讨论】:

效果很好!我将查看这些链接并根据需要更改我的代码。

以上是关于单击时如何将按钮值从自定义小部件传递到 tkinter 中的主应用程序的主要内容,如果未能解决你的问题,请参考以下文章

Flutter 如何从自定义小部件中获取价值

如何在 Swift 中将值从自定义单元格设置/传递到视图控制器

如何将值从基本适配器传递到 Android 中的 Activity

无法将选中的值从自定义复选框组件传递给父组件

如何将值从initstate传递给flutter中的小部件

列表视图中的页脚按钮,如何从自定义列表适配器中获取值