A question about 'pack' or 'grid' for tkinter widgets error

Question:

I am learning python.I follow the book example code. This code make SumGrid class in order to be attachable to containers where other widgets are being gridded or packed. The author said that it leaves its own geometry management ambiguous and requires callers to pack or grid its instances. It’s OK for containers to pick either scheme for their own children because they effectively seal off the pack-or-grid choice. But attachable component classes that aim to be reused under both geometry managers cannot manage themselves because they cannot predict their parent’s policy.

from tkinter import *
from tkinter.filedialog import askopenfilename
from PP4E.Gui.Tour.quitter import Quitter          # reuse, pack, and grid

class SumGrid(Frame):
    def __init__(self, parent=None, numrow=5, numcol=5):
        Frame.__init__(self, parent)
        self.numrow = numrow                       # I am a frame container
        self.numcol = numcol                       # caller packs or grids me
        self.makeWidgets(numrow, numcol)           # else only usable one way

    def makeWidgets(self, numrow, numcol):
        self.rows = []
        for i in range(numrow):
            cols = []
            for j in range(numcol):
                ent = Entry(self, relief=RIDGE)
                ent.grid(row=i+1, column=j, sticky=NSEW)
                ent.insert(END, '%d.%d' % (i, j))
                cols.append(ent)
            self.rows.append(cols)

        self.sums = []
        for i in range(numcol):
            lab = Label(self, text='?', relief=SUNKEN)
            lab.grid(row=numrow+1, column=i, sticky=NSEW)
            self.sums.append(lab)

        Button(self, text='Sum',   command=self.onSum).grid(row=0, column=0)
        Button(self, text='Print', command=self.onPrint).grid(row=0, column=1)
        Button(self, text='Clear', command=self.onClear).grid(row=0, column=2)
        Button(self, text='Load',  command=self.onLoad).grid(row=0, column=3)
        Quitter(self).grid(row=0, column=4)    # fails: Quitter(self).pack()

    def onPrint(self):
        for row in self.rows:
            for col in row:
                print(col.get(), end=' ')
            print()
        print()

    def onSum(self):
        tots = [0] * self.numcol
        for i in range(self.numcol):
            for j in range(self.numrow):
                tots[i] += eval(self.rows[j][i].get())        # sum current data
        for i in range(self.numcol):
            self.sums[i].config(text=str(tots[i]))

    def onClear(self):
        for row in self.rows:
            for col in row:
                col.delete('0', END)                          # delete content
                col.insert(END, '0.0')                        # preserve display
        for sum in self.sums:
            sum.config(text='?')

    def onLoad(self):
        file = askopenfilename()
        if file:
            for row in self.rows:
                for col in row: col.grid_forget()             # erase current gui
            for sum in self.sums:
                sum.grid_forget()

            filelines   = open(file, 'r').readlines()         # load file data
            self.numrow = len(filelines)                      # resize to data
            self.numcol = len(filelines[0].split())
            self.makeWidgets(self.numrow, self.numcol)

            for (row, line) in enumerate(filelines):          # load into gui
                fields = line.split()
                for col in range(self.numcol):
                    self.rows[row][col].delete('0', END)
                    self.rows[row][col].insert(END, fields[col])

if __name__ == '__main__':
    import sys
    root = Tk()
    root.title('Summer Grid')
    if len(sys.argv) != 3:
        SumGrid(root).pack()    # .grid() works here too
    else:
        rows, cols = eval(sys.argv[1]), eval(sys.argv[2])
        SumGrid(root, rows, cols).pack()
    root.mainloop()

When I run this .py file in my window shell. It can’t work. The err message like below. I think SumGrid is a Frame. The caller can decide to pack or grid this Frame. But it can’t work on my computer. Why? Thank you.

Traceback (most recent call last):
  File "C:UsershpPP4E-Examples-1.4ExamplesPP4EGuiTourGridgrid5c.py", line 84, in <module>
    SumGrid(root).pack()    # .grid() works here too
  File "C:UsershpPP4E-Examples-1.4ExamplesPP4EGuiTourGridgrid5c.py", line 12, in __init__
    self.makeWidgets(numrow, numcol)           # else only usable one way
  File "C:UsershpPP4E-Examples-1.4ExamplesPP4EGuiTourGridgrid5c.py", line 35, in makeWidgets
    Quitter(self).grid(row=0, column=4)    # fails: Quitter(self).pack()
  File "C:UsershpPP4E-Examples-1.4ExamplesPP4EGuiTourquitter.py", line 12, in __init__
    self.pack()
  File "C:UsershpAppDataLocalProgramsPythonPython310libtkinter__init__.py", line 2425, in pack_configure
    self.tk.call(
_tkinter.TclError: cannot use geometry manager pack inside .!sumgrid which already has slaves managed by grid
Asked By: Rui Lin

||

Answers:

Like the error says, you can’t use both grid and pack on widgets that have the same parent.

Let’s look at these two lines of code:

Button(self, text='Load',  command=self.onLoad).grid(row=0, column=3)
Quitter(self).grid(row=0, column=4)    # fails: Quitter(self).pack()

Notice how both Quitter and Button are using self as the parent. That means that you must only use one of grid or pack for both widgets (and the other widgets that have self as the parent). If you use grid for the button, you cannot use pack for Quitter, which is exactly what the error is telling you.

Answered By: Bryan Oakley
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.