首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >tkinger --如何在动态创建的网格中更新正确的小部件?

tkinger --如何在动态创建的网格中更新正确的小部件?
EN

Stack Overflow用户
提问于 2019-04-22 17:14:55
回答 2查看 114关注 0票数 0

我正在从一个列表中创建一个框架网格。我有一个框架类,它的弹出菜单绑定到Button-1。我想使用这个弹出菜单来更新称为弹出菜单的框架内的标签。现在,只有最后一个帧的标签文本正在更新。

我尝试过使用绑定标记,因为我认为Button-1可能只绑定到最近创建的小部件,但这似乎是一条红鲱鱼。实际上,我完全不知道该从哪里出发。

代码语言:javascript
运行
AI代码解释
复制
#!/bin/env python

import tkinter
import tkinter.messagebox


def create_grid():
    grid = []
    for i in range(0, 3001, 1000):
        row = []
        for j in range(8):
            row.append(i+j)
        grid.append(row)
    grid.reverse()
    return grid


class GridFrame(tkinter.Frame):
    def __init__(self, root, index, *args, **kwargs):
        tkinter.Frame.__init__(self, root, *args, **kwargs)
        self.labeltext = tkinter.StringVar()
        self.labeltext.set("+")

        self.popup_menu = tkinter.Menu(root, tearoff=0)
        self.popup_menu.add_command(label="Set label to 'test'", command=self.update_label)
        self.popup_menu.add_command(label="Do nothing", command=print)

        self.bind_all("<Button-1>", self.popup)
        self.bind_all("<Button-3>", self.reset_label)

        self.index_label = tkinter.Label(self, text="{0:04d}".format(index))
        self.index_label.pack()
        self.framelabel = tkinter.Label(self, textvariable=self.labeltext)
        self.framelabel.pack()

    def popup(self, event):
        try:
            self.popup_menu.tk_popup(event.x_root, event.y_root, 0)
        finally:
            self.popup_menu.grab_release()

    def reset_label(self, event):
        self.labeltext.set("+")

    def update_label(self):
        self.labeltext.set("test")


class GridGUI:
    def __init__(self, root, grid, *args, **kwargs):
        self.root = root
        root.title("Grid")

        for i, row in enumerate(grid):
            for j, index in enumerate(row):
                gridframe = GridFrame(root, index)
                gridframe.config(borderwidth=3, relief="raised")

                gridframe.grid(row=i, column=j, padx=2, pady=2, ipadx=20, ipady=30, sticky="nsew")


def main():
    grid = create_grid()
    root = tkinter.Tk()

    menubar = tkinter.Menu(root)
    filemenu = tkinter.Menu(menubar, tearoff=0)

    filemenu.add_command(label="Exit", command=root.quit)

    menubar.add_cascade(label="File", menu=filemenu)

    root.config(menu=menubar)

    my_gui = GridGUI(root, grid)
    root.mainloop()


main()

我希望框架中的标签弹出菜单会更新。根据我当前的代码,似乎只有最近创建的框架更新中的标签。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-04-23 05:32:36

您的问题是,您使用的是bind_all,而且每次创建新的GridFrame时都要重新设置绑定。因此,只有绑定到最后一个GridFrame才会被tkinter识别。当tkinter检测到绑定时,它将调用最终GridFrameGridFrame方法。

您可以处理这个问题,因为事件对象告诉您单击了哪个小部件。由此,您可以确定单击了哪个GridFrame实例。然而,有一个更简单的解决办法。

解决方案是不使用bind_all,而是单独绑定到每个小部件。当绑定触发时,它将调用与适当对象关联的函数。

创建小部件后,将绑定应用于每个小部件:

代码语言:javascript
运行
AI代码解释
复制
class GridFrame(tkinter.Frame):
    def __init__(self, root, index, *args, **kwargs):
        ...
        for widget in (self, self.index_label, self.framelabel):
            widget.bind("<Button-1>", self.popup)

这有一个额外的好处,即您可以在屏幕上拥有任何其他小部件,这些小部件可以接受按钮单击(按钮、滚动条等),而不会受到鼠标单击的全局绑定的影响。

票数 0
EN

Stack Overflow用户

发布于 2019-04-22 19:24:26

如果你不介意丑陋的黑客,这里有一个方法。不要在每个框架中创建一个单独的弹出菜单,只在主GUI中创建一个,检查弹出位置,并更改相应的StringVar

代码语言:javascript
运行
AI代码解释
复制
import tkinter
import tkinter.messagebox

y = []

def create_grid():
    grid_list = []
    for i in range(0, 3001, 1000):
        row = []
        for j in range(8):
            row.append(i+j)
        grid_list.append(row)
    grid_list.reverse()
    return grid_list

class GridFrame(tkinter.Frame):
    def __init__(self, root, index, num, *args, **kwargs):
        tkinter.Frame.__init__(self, root, *args, **kwargs,name=f"{num}")
        self.labeltext = tkinter.StringVar()
        y.append(self.labeltext)
        self.labeltext.set("+")
        self.index_label = tkinter.Label(self, text="{0:04d}".format(index))
        self.index_label.pack()
        self.framelabel = tkinter.Label(self, textvariable=self.labeltext)
        self.framelabel.pack()

class GridGUI:
    def __init__(self, root, grid_list, *args, **kwargs):
        root.title("Grid")
        num = 0
        for i, row in enumerate(grid_list):
            for j, index in enumerate(row):
                gridframe = GridFrame(root, index, num)
                gridframe.config(borderwidth=3, relief="raised")
                gridframe.grid(row=i, column=j, padx=2, pady=2, ipadx=20, ipady=30, sticky="nsew")
                num+=1
        self.popup_menu = tkinter.Menu(root, tearoff=0)
        self.popup_menu.add_command(label="Set label to 'test'", command=lambda: self.update_label(self.event))
        self.popup_menu.add_command(label="Do nothing", command=lambda: self.reset_label(self.event))

        root.bind_all("<Button-1>", self.popup)
        root.bind_all("<Button-3>", self.reset_label)

    def popup(self, event):
        self.event = event
        try:
            self.popup_menu.tk_popup(event.x_root, event.y_root, 0)
        finally:
            self.popup_menu.grab_release()

    def reset_label(self, event):
        result = str(event.widget).split(".")[1]
        y[int(result)].set("+")

    def update_label(self,event):
        result = str(event.widget).split(".")[1]
        y[int(result)].set("test")

def main():
    grid = create_grid()
    root = tkinter.Tk()

    menubar = tkinter.Menu(root)
    filemenu = tkinter.Menu(menubar, tearoff=0)

    filemenu.add_command(label="Exit", command=root.quit)

    menubar.add_cascade(label="File", menu=filemenu)

    root.config(menu=menubar)

    my_gui = GridGUI(root, grid)
    root.mainloop()

main()
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55803008

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文