pack(3tk)

πŸ’– pack(3tk) β€” the packer geometry manager, explained by your bestie πŸŽ€

okay so this one lives in the Tk Built-In Commands family, and honestly? it's the blueprint for like every Tk layout you've ever seen. no cap. let's get into it πŸ¦‹


✨ NAME ✨

pack β€” the geometry manager that packs windows around the edges of a cavity πŸ’…


✨ SYNOPSIS ✨

pack option arg ?arg ...?

✨ DESCRIPTION ✨

bestie. listen. the pack command is how you talk to the packer β€” that's the geometry manager that arranges the children of a parent by packing them, in order, around the edges of the parent. it's giving very much "tetris but make it widgets" 🧚

the pack command has several forms, and which one you get depends on that option argument. buckle up:

  • pack window ?window ...? ?options? β€” if the very first argument you hand it is a window name (and by "window name" we mean any value starting with "."), then it just gets processed the exact same way as pack configure. yes it's the cute little shortcut. πŸ™ˆ
  • pack configure window ?window ...? ?options? β€” here's your main character. the arguments are the names of one or more content windows, followed by pairs of arguments that say how to manage that content. want the deets on how the packer actually uses these? scroll down to THE PACKER ALGORITHM hun. here's every option that's supported:
    • -after other β€” other has to be the name of another window. use other's container as the container for your content, and insert the content just after other in the packing order.
    • -anchor anchor β€” anchor has to be a valid anchor position, like n or sw. it says where each content gets positioned inside its parcel. defaults to center. πŸ’«
    • -before other β€” other must be the name of another window. use its container as the container for the content, and insert the content just before other in the packing order.
    • -expand boolean β€” says whether the content should be expanded to eat up the extra space in its container. boolean can be any proper boolean value, like 1 or no. defaults to 0.
    • -fill style β€” if a content's parcel is bigger than its requested dimensions, this is the one that stretches it. style has to be one of these:
      • none β€” give the content its requested dimensions plus any internal padding requested with -ipadx or -ipady. this is the default. πŸŽ€
      • x β€” stretch the content horizontally to fill the entire width of its parcel (except it leaves external padding alone, as specified by -padx).
      • y β€” stretch the content vertically to fill the entire height of its parcel (except it leaves external padding alone, as specified by -pady).
      • both β€” stretch it both horizontally and vertically. the overachiever. πŸ’…
    • -in container β€” insert the window at the end of the packing order for the container window given by container.
    • -ipadx amount β€” amount says how much horizontal internal padding to leave on each side of the content. it has to be a valid screen distance, like 2 or .5c. defaults to 0.
    • -ipady amount β€” amount says how much vertical internal padding to leave on each side of the content. defaults to 0.
    • -padx amount β€” amount says how much horizontal external padding to leave on each side of the content. amount can also be a list of two values if you wanna specify left and right separately. defaults to 0.
    • -pady amount β€” amount says how much vertical external padding to leave on each side of the content. amount can be a list of two values to specify top and bottom separately. defaults to 0.
    • -side side β€” which side of the container the content gets packed against. must be left, right, top, or bottom. defaults to top.

okay so now the important lil rules paragraph, don't skip it:

if you don't specify any of -in, -after or -before, then each content gets inserted at the end of the packing list for its parent β€” unless it's already managed by the packer, in which case it just stays where it is, periodt. but if you do specify one of those options, then all the content gets inserted at that specified point. and if any of the content is already managed by the geometry manager, then any options you didn't specify for them keep their previous values instead of getting defaults. she remembers. πŸ‘‘

  • pack content window β€” returns a list of all the content windows in the packing order for window. the order of the content windows in that list is the same as their order in the packing order. and if window has no content? you get an empty string back. nothing. void. πŸ’€
  • pack forget window ?window ...? β€” removes each of the windows from the packing order for its container and unmaps their windows. the content is no longer managed by the packer. bye bestie 🫢
also, heads up: if the last content window of the container becomes unmanaged, this will also send the virtual event <<NoManagedChild>> to the container. the container may choose to resize itself (or respond some other way) to that change. so it's not just ✨gone✨, it's announced. πŸ“’
  • pack info window β€” returns a list whose elements are the current configuration state of the window given by window, in the same option-value form you might pass to pack configure. and the first two elements of that list are -in container, where container is the window's container. cute lil header on your info dump. πŸ’–
  • pack propagate container ?boolean? β€” if boolean has a true boolean value like 1 or on, then propagation gets enabled for container, which has to be a window name (peep GEOMETRY PROPAGATION below for the whole story). if boolean has a false boolean value then propagation gets disabled for container. in either of those cases you get an empty string back. but if boolean is omitted entirely, the command returns 0 or 1 to tell you whether propagation is currently enabled for container. and fyi, propagation is enabled by default. 🌈
  • pack slaves window β€” synonym for pack content window. same thing, different name, we love a double act. ✨

🧠 THE PACKER ALGORITHM 🧠

okay this is the part where it gets ✨mechanical✨ and honestly it's so satisfying once it clicks.

for each container, the packer keeps an ordered list of content windows called the packing list. the -in, -after, and -before configuration options are how you specify the container for each content and that content's position in the packing list. and if you give none of those options for a content, then that content just gets added to the end of the packing list for its parent. no drama. πŸ’…

so the packer arranges the content windows for a container by scanning the packing list in order. at the moment it processes each content, there's a rectangular area within the container that's still unallocated. that area is called the cavity β€” and for the very first content, the cavity is the entire area of the container. iconic. πŸ‘‘

for each content, the packer does these three steps:

  1. the packer allocates a rectangular parcel for the content along the side of the cavity given by the content's -side option. if that side is top or bottom, then the parcel's width is the width of the cavity, and its height is the content's requested height plus the -ipady and -pady options. for the left or right side, the parcel's height is the height of the cavity, and its width is the content's requested width plus the -ipadx and -padx options. the parcel may get enlarged even further because of the -expand option (peep EXPANSION below). 🌸
  2. the packer picks the dimensions of the content. normally the width is the content's requested width plus twice its -ipadx option, and the height is the content's requested height plus twice its -ipady option. however β€” if the -fill option is x or both, then the content's width gets expanded to fill the width of the parcel, minus twice the -padx option. and if -fill is y or both, then the height gets expanded to fill the parcel's height, minus twice the -pady option.
  3. the packer positions the content over its parcel. if the content is smaller than the parcel, then the -anchor option decides where in the parcel the content lands. and if -padx or -pady is non-zero, then that given amount of external padding is always left between the content and the edges of the parcel. always always. 🀝

once a content has been packed, the area of its parcel gets subtracted from the cavity, leaving a smaller rectangular cavity for the next content. and important: if a content doesn't use all of its parcel, that unused space in the parcel will not be used by subsequent content. sorry bestie, no leftovers. πŸ™ˆ

and if the cavity becomes too small to meet the needs of a content, then the content gets whatever space is left in the cavity. if the cavity shrinks all the way to zero size, then all the remaining content on the packing list gets unmapped from the screen until the container window becomes large enough to hold them again. dramatic? yes. correct? also yes. πŸ’€

🌈 EXPANSION 🌈

if a container window is so big that there's extra space left over after all of its content has been packed, then that extra space gets distributed uniformly among all the content for which the -expand option is set. specifically: extra horizontal space is distributed among the expandable content whose -side is left or right, and extra vertical space is distributed among the expandable content whose -side is top or bottom. sharing is caring fr fr. 🫢

πŸ¦‹ GEOMETRY PROPAGATION πŸ¦‹

the packer normally computes how large a container has to be to just exactly meet the needs of its content, and it sets the requested width and height of the container to those dimensions. this makes geometry information propagate up through a window hierarchy to a top-level window, so the whole entire sub-tree sizes itself to fit the needs of the leaf windows. it's giving cascade. it's giving lineage. 🌸

however β€” the pack propagate command can be used to turn off propagation for one or more containers. if propagation is disabled, then the packer will not set the requested width and height of the packer. which is lowkey useful if, for example, you want a container window to have a fixed size that you specify. you're the main character, you decide. πŸ‘‘


🌸 RESTRICTIONS ON CONTAINER WINDOWS 🌸

okay bestie, here's the tea on containers, and this one is a rule rule, not a suggestion πŸ’…

The container for each content has to be either the content's parent (which is the default, iykyk) or a descendant of the content's parent. That's it, that's the whole guest list.

And why tho? Because this restriction is necessary to guarantee that the content can be placed over any part of its container that is visible without danger of the content getting clipped by its parent. Like, no cap β€” if you break this rule, your content is gonna get cut off and you're gonna be sad about it. 🫢


πŸ’… PACKING ORDER πŸ’…

Now listen, if the container for a content is not its parent, then you must make sure that the content is higher in the stacking order than the container. Periodt.

Otherwise? The container will obscure the content, and it will look like the content has not been packed correctly. It's giving "why is my widget invisible" energy and the answer is stacking order, always is. πŸ’€

Two ways to make sure the content sits higher than the container, pick your fighter:

  • Create the container window first β€” this is the easiest way, fr. The most recently created window will be highest in the stacking order, so just go container-first and you're golden ✨
  • Use the raise and lower commands to change the stacking order of either the container or the content. Manual mode, full control, no notes. πŸ‘‘

πŸŽ€ EXAMPLE πŸŽ€

here's a whole layout that's lowkey iconic β€” a Java BorderLayout clone, and yes we're doing it in like eight lines of Tcl:

# Make the widgets
label .t -text "This widget is at the top"    -bg red
label .b -text "This widget is at the bottom" -bg green
label .l -text "Left\nHand\nSide"
label .r -text "Right\nHand\nSide"
text .mid
.mid insert end "This layout is like Java's BorderLayout"
# Lay them out
pack .t   -side top    -fill x
pack .b   -side bottom -fill x
pack .l   -side left   -fill y
pack .r   -side right  -fill y
pack .mid -expand 1    -fill both

look at that. top, bottom, left, right, and a text widget in the middle soaking up all the extra space with -expand 1 and -fill both. main character energy, honestly 🧚


πŸ¦‹ SEE ALSO πŸ¦‹

your other geometry managers, in case pack isn't the one:


πŸ’– KEYWORDS πŸ’–

the search terms, the vibe check, the tags:

  • geometry manager
  • location
  • packer
  • parcel
  • propagation
  • size

and that's a wrap on the pack(3tk) page, bestie! this one's from Tk 4.0 β€” yes, the version is right there in the footer, we're keeping it vintage and iconic πŸ’œ go pack something beautiful, and remember: container first, stacking order always, and never let your parent clip you. slay πŸŽ€βœ¨

πŸ“¦ where this page comes from
  • ubuntu stonking: tk9.0-doc 9.0.4-1
  • πŸ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms