如何在Python3 / Tkinter中重绘网格时删除列(或行)

时间:2018-03-16 05:41:07

标签: python tkinter

我有一段代码可以创建很少的小部件并将它们放在网格中(例如3x2)。当特定事件发生时,我希望重绘网格,但这次是切换位置(从而创建网格2x3)。为了简单起见,我创建了一个示例代码,按钮单击进行交换。

问题:单击按钮,小部件按预期重新排列在网格上,但随后窗口显示第三个"空列(并且对称地,再次转置它们会创建第三个空行)。就像网格模式记得在交换之前有第三列。我已尝试使用destroy()小部件grid_forget()grid_remove(),但仍然是网格模式"记住"它有额外的列/行。我怀疑问题在于grid_rowconfiguregrid_columnconfigure,我必须调用才能获得可调整大小的效果。但我不确定如何取消配置他们......可以这么说。

是否有人知道如何仅使用显示小部件的新布局所需的列和行重新绘制网格?

import tkinter as tk


class TestGrid(tk.Frame):
    def __init__(self, master):
        tk.Frame.__init__(self, master, bg='white')
        colors = ['cyan', 'magenta', 'green', 'gold', 'lavender', 'purple']
        self.switch = True
        self.widgets = []
        for i in range(6):
            self.widgets.append(tk.Label(self, text=i, bg=colors[i]))

    def refresh(self, *args):
        self.switch = not self.switch
        for w in self.widgets:
            w.grid_forget()

        positions = [(0, 0), (1, 0), (2, 0), (0, 1), (1, 1), (2, 1)]
        for i in range(6):
            c, r = positions[i][0], positions[i][1]
            if self.switch:
                c, r = r, c
            self.grid_columnconfigure(c, weight=1, uniform="aaa")
            self.grid_rowconfigure(r, weight=1, uniform="bbb")
            self.widgets[i].grid(column=c, row=r, sticky=tk.NSEW)

def main():
    root = tk.Tk()
    root.geometry('400x400+20+20')
    btn = tk.Button(root, text="click me")
    btn.pack(side=tk.TOP, fill=tk.X)
    frm = TestGrid(root)
    frm.pack(fill=tk.BOTH, expand=1, padx=5, pady=5)
    frm.refresh()
    btn.bind("<Button-1>", frm.refresh)

    root.mainloop()

if __name__ == '__main__':
    main()

2 个答案:

答案 0 :(得分:0)

只是想分享一下我找到解决问题的唯一方法就是简单地销毁()整个框架并重新创建它。这是代码,以防有人遇到同样的问题。

import tkinter as tk


class TestGrid(tk.Frame):
    def __init__(self, master, switch):
        tk.Frame.__init__(self, master, bg='white')
        colors = ['cyan', 'magenta', 'green', 'gold', 'lavender', 'purple']
        self.switch = switch

        self.widgets = []
        for i in range(6):
            self.widgets.append(tk.Label(self, text=i, bg=colors[i]))

    def draw(self):
        for w in self.widgets:
            w.grid_forget()

        positions = [(0, 0), (1, 0), (2, 0), (0, 1), (1, 1), (2, 1)]
        for i in range(6):
            c, r = positions[i][0], positions[i][1]
            if self.switch:
                c, r = r, c
            self.grid_columnconfigure(c, weight=1, uniform="aaa")
            self.grid_rowconfigure(r, weight=1, uniform="bbb")
            self.widgets[i].grid(column=c, row=r, sticky=tk.NSEW)


class MyApp(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.geometry('400x400+20+20')

        btn = tk.Button(self, text="click me")
        btn.pack(side=tk.TOP, fill=tk.X)
        btn.bind("<Button-1>", self.transpose)

        self.switch = False
        self.frm = None
        self.create_frm()

    def create_frm(self):
        self.frm = TestGrid(self, self.switch)
        self.frm.draw()
        self.frm.pack(fill=tk.BOTH, expand=1, padx=5, pady=5)

    def transpose(self, *args):
        self.frm.destroy()
        self.switch = not self.switch
        self.create_frm()


def main():
    root = MyApp()
    root.mainloop()


if __name__ == '__main__':
    main()

答案 1 :(得分:0)

参加聚会的时间不算太晚,但是当封闭框架缩小时,我在处理具有固定大小单元格的动态网格大小调整时也遇到了这个问题。根据我自己的调查,即使该列中不再有任何小部件,网格几何管理器似乎也记得该列在那里。

诀窍是通过将weight设置为0并将uniform属性更改为与非空列或行不同的内容来告诉网格管理器不赋予空列或行权重。这样,就不必拆除所有东西并从头开始。

这是程序的修改版本,显示了它的工作方式:

import tkinter as tk


class TestGrid(tk.Frame):
    def __init__(self, master):
        tk.Frame.__init__(self, master, bg='white')
        colors = ['cyan', 'magenta', 'green', 'gold', 'lavender', 'purple']
        self.switch = True
        self.widgets = []
        for i in range(6):
            self.widgets.append(tk.Label(self, text=i, bg=colors[i]))

    def refresh(self, *args):
        self.switch = not self.switch
        for w in self.widgets:
            w.grid_forget()

        positions = [(0, 0), (1, 0), (2, 0), (0, 1), (1, 1), (2, 1)]
        for i in range(6):
            c, r = positions[i][0], positions[i][1]
            if self.switch:
                c, r = r, c
            self.widgets[i].grid(column=c, row=r, sticky=tk.NSEW)
        for i in range(2):
            # set the weight for the always present columns and rows
            self.grid_columnconfigure(i, weight=1, uniform="aaa")
            self.grid_rowconfigure(i, weight=1, uniform="bbb")
        if self.switch:
            # tell grid manager to give no weight to the empty column
            self.grid_columnconfigure(2, weight=0, uniform="ignore")
            self.grid_rowconfigure(2, weight=1, uniform="bbb")
        else:
            # tell grid manager to give no weight to the empty row
            self.grid_columnconfigure(2, weight=1, uniform="aaa")
            self.grid_rowconfigure(2, weight=0, uniform="ignore")


def main():
    root = tk.Tk()
    root.geometry('400x400+20+20')
    btn = tk.Button(root, text="click me")
    btn.pack(side=tk.TOP, fill=tk.X)
    frm = TestGrid(root)
    frm.pack(fill=tk.BOTH, expand=1, padx=5, pady=5)
    frm.refresh()
    btn.bind("<Button-1>", frm.refresh)

    root.mainloop()

if __name__ == '__main__':
    main()

这有点笨拙,但是我认为比使用一些优雅的pythonesque方式更好地说明正在发生的事情。