fix this code 'cannot use geometry manager grid inside . which already has slaves managed by pack'
Asked Answered
H

2

5

I wrote this simple code using grid(), but there seem to be a problem and shows the error :

class Input_screen:

    def __init__(self,master):
        frame = Frame(master)
        frame.pack()

        self.name_lable = Label(frame,text = 'NAME')
        self.name_e = Entry(root)

        self.name_lable.grid(row=1,column=0,sticky=W)
        self.name_e.grid(row=1,column=1)    

root = Tk()
b = Input_screen(root)
root.mainloop()

TclError: cannot use geometry manager grid inside . which already has slaves managed by pack

Herve answered 24/9, 2019 at 19:28 Comment(3)
You probably meant for the Entry to be a child of frame, rather that root.Antibiotic
Possible duplicate of Cannot use geometry manager pack insideDear
@Antibiotic is probably right about the code fix. The question itself is probably a duplicate of #23584825 which makes the same error just the other way round.Dear
N
3

Fixed code

import tkinter as tk
from tkinter import Entry, Frame, Label, Tk

class Input_screen:

    def __init__(self,master):
        frame = Frame(master)
        frame.grid(column=1)
        # frame.pack()

        self.name_label = Label(frame, text = 'NAME')
        self.name_entry = Entry(frame)

        self.name_label.grid(row=1, column=0, sticky='w')
        self.name_entry.grid(row=1, column=1, sticky='w')  

root = Tk()
width = 200
length = 100
root.geometry(f"""{width}x{length}""")
b = Input_screen(root)
root.mainloop()

Changes:

  • Write frame.grid(column=1) to allow columns 0 and 1 for the two widgets in that frame.
  • Both widgets are now in the Frame frame, see Entry(frame).
  • And the sticky parameter must be quoted.

Code output:

enter image description here

If you add the Entry widget only to the root window, and not to its frame, as is done in the code of the question (Entry(frame)), you will not see the output in the needed two columns anymore since the two widgets (Label and Entry) are not in the same frame anymore:

enter image description here

If you do not need a frame at all since everything fits in the main window, you can drop the frame from the code, and the default grid of the root window works fine and has the same output:

import tkinter as tk
from tkinter import Entry, Frame, Label, Tk

class Input_screen:

    def __init__(self,master):
        self.name_label = Label(master, text = 'NAME')
        self.name_entry = Entry(master)

        self.name_label.grid(row=1, column=0, sticky='w')
        self.name_entry.grid(row=1, column=1, sticky='e')    

root = Tk()
width = 200
length = 100
root.geometry(f"""{width}x{length}""")
b = Input_screen(root)
root.mainloop()

enter image description here

More on sticky

The sticky parameter only puts the "sides and corners of the cell" that the widget shall stick to: north, east, south and/or west, see Python tkinter how to use grid sticky. For more, see How does the sticky command affect the python code in Tkinter?. It does not influence the GUI as it is now since it only works if there's more room for the widget than needed, and the frame at hand has only one row, there is no other widget in the same column that is wider. That is why you could also drop the sticky parameter and get the same output, but since this class can be called again and again, it should still be in there. If you have more than one row, a sticky="e" for a Label widget would mean to align it to the right, example:

enter image description here

In words

Being new to tkinter and its wording (widgets, pack, grid, frame and so on), here is an overview of what this is all about.

The steps to get rid of the error are roughly:

  • Comment out all of the .pack() commands. The error will be gone, and it will only show the widgets that are left over that are published with the .grid() command.
  • Check your GUI: wherever you want to have more than one widget in one row (that is, having two or more columns), you need to put it into the right columns with the .grid() command. For example if you want to have a label left to an entry widget on the right, the label must be in column 0 and the entry field in column 1. And for this to work, the frame that holds these two widgets needs to offer these two columns (or you do not put it into a frame at all, then the default window can grow as big as you like, see Python tkinter how to use grid sticky, also for .grid_columnconfigure() as a way to change these columns. Put the max column number in the grid of the root's frame or the root window, but you put the Entry widget into the root window but the Label into the frame.
  • As a beginner, you will normally just have the "root" window and at the most one frame for it to make the grid, which is nothing but the whole window of the app as a grid. This is what your code in question asks for, and you should not even need a Frame then. For another example with a Frame, check again How does the sticky command affect the python code in Tkinter?.
  • If you have child frames as well, a window inside the window so to speak, then you need to understand nested frames (parent/child/grandchild... frames) and try to decide for each frame whether packing everything in a row is enough or whether you want to have widgets next to each other in a grid. A code example is at tkinter gui layout using frames and grid.

Wrap up

.grid needs to take over anything were .pack() was before as soon as you want columns next to each other since .pack() packs it all just in a row below each other in the order of the coding, see The Packer. Just replace the old .pack() lines with .grid(column=?) lines and add a Frame with the needed number of columns as well into which you can put the widgets, or drop the Frame and take the default root window for the grid.

Main tkinter guide

tkinter — Python interface to Tcl/Tk

Nonpayment answered 16/5, 2023 at 13:14 Comment(0)
E
4

The error is telling you exactly what is wrong: you can't use both pack and grid with widgets that share a common parent. In this case, the common parent is "." which is the internal name for the root widget.

You're using pack for frame and grid for self.name_e, and both of those have the root window as their parent. You either need to use grid for both or pack for both.

Eldon answered 24/9, 2019 at 19:49 Comment(2)
alright, so there is no way we can use pack and grid in the same class? ThanksHerve
@DarkKingAce: you can use them in the same class, no problem. You just can't use them on two or more widgets that have the same master.Eldon
N
3

Fixed code

import tkinter as tk
from tkinter import Entry, Frame, Label, Tk

class Input_screen:

    def __init__(self,master):
        frame = Frame(master)
        frame.grid(column=1)
        # frame.pack()

        self.name_label = Label(frame, text = 'NAME')
        self.name_entry = Entry(frame)

        self.name_label.grid(row=1, column=0, sticky='w')
        self.name_entry.grid(row=1, column=1, sticky='w')  

root = Tk()
width = 200
length = 100
root.geometry(f"""{width}x{length}""")
b = Input_screen(root)
root.mainloop()

Changes:

  • Write frame.grid(column=1) to allow columns 0 and 1 for the two widgets in that frame.
  • Both widgets are now in the Frame frame, see Entry(frame).
  • And the sticky parameter must be quoted.

Code output:

enter image description here

If you add the Entry widget only to the root window, and not to its frame, as is done in the code of the question (Entry(frame)), you will not see the output in the needed two columns anymore since the two widgets (Label and Entry) are not in the same frame anymore:

enter image description here

If you do not need a frame at all since everything fits in the main window, you can drop the frame from the code, and the default grid of the root window works fine and has the same output:

import tkinter as tk
from tkinter import Entry, Frame, Label, Tk

class Input_screen:

    def __init__(self,master):
        self.name_label = Label(master, text = 'NAME')
        self.name_entry = Entry(master)

        self.name_label.grid(row=1, column=0, sticky='w')
        self.name_entry.grid(row=1, column=1, sticky='e')    

root = Tk()
width = 200
length = 100
root.geometry(f"""{width}x{length}""")
b = Input_screen(root)
root.mainloop()

enter image description here

More on sticky

The sticky parameter only puts the "sides and corners of the cell" that the widget shall stick to: north, east, south and/or west, see Python tkinter how to use grid sticky. For more, see How does the sticky command affect the python code in Tkinter?. It does not influence the GUI as it is now since it only works if there's more room for the widget than needed, and the frame at hand has only one row, there is no other widget in the same column that is wider. That is why you could also drop the sticky parameter and get the same output, but since this class can be called again and again, it should still be in there. If you have more than one row, a sticky="e" for a Label widget would mean to align it to the right, example:

enter image description here

In words

Being new to tkinter and its wording (widgets, pack, grid, frame and so on), here is an overview of what this is all about.

The steps to get rid of the error are roughly:

  • Comment out all of the .pack() commands. The error will be gone, and it will only show the widgets that are left over that are published with the .grid() command.
  • Check your GUI: wherever you want to have more than one widget in one row (that is, having two or more columns), you need to put it into the right columns with the .grid() command. For example if you want to have a label left to an entry widget on the right, the label must be in column 0 and the entry field in column 1. And for this to work, the frame that holds these two widgets needs to offer these two columns (or you do not put it into a frame at all, then the default window can grow as big as you like, see Python tkinter how to use grid sticky, also for .grid_columnconfigure() as a way to change these columns. Put the max column number in the grid of the root's frame or the root window, but you put the Entry widget into the root window but the Label into the frame.
  • As a beginner, you will normally just have the "root" window and at the most one frame for it to make the grid, which is nothing but the whole window of the app as a grid. This is what your code in question asks for, and you should not even need a Frame then. For another example with a Frame, check again How does the sticky command affect the python code in Tkinter?.
  • If you have child frames as well, a window inside the window so to speak, then you need to understand nested frames (parent/child/grandchild... frames) and try to decide for each frame whether packing everything in a row is enough or whether you want to have widgets next to each other in a grid. A code example is at tkinter gui layout using frames and grid.

Wrap up

.grid needs to take over anything were .pack() was before as soon as you want columns next to each other since .pack() packs it all just in a row below each other in the order of the coding, see The Packer. Just replace the old .pack() lines with .grid(column=?) lines and add a Frame with the needed number of columns as well into which you can put the widgets, or drop the Frame and take the default root window for the grid.

Main tkinter guide

tkinter — Python interface to Tcl/Tk

Nonpayment answered 16/5, 2023 at 13:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.