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 onl oad(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:\Users\hp\PP4E-Examples-1.4\Examples\PP4E\Gui\Tour\Grid\grid5c.py", line 84, in <module>
SumGrid(root).pack() # .grid() works here too
File "C:\Users\hp\PP4E-Examples-1.4\Examples\PP4E\Gui\Tour\Grid\grid5c.py", line 12, in __init__
self.makeWidgets(numrow, numcol) # else only usable one way
File "C:\Users\hp\PP4E-Examples-1.4\Examples\PP4E\Gui\Tour\Grid\grid5c.py", line 35, in makeWidgets
Quitter(self).grid(row=0, column=4) # fails: Quitter(self).pack()
File "C:\Users\hp\PP4E-Examples-1.4\Examples\PP4E\Gui\Tour\quitter.py", line 12, in __init__
self.pack()
File "C:\Users\hp\AppData\Local\Programs\Python\Python310\lib\tkinter\__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
CodePudding user response:
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.