[Rod Stephens Books]
Index Books Python Examples About Rod Contact
[Mastodon] [Bluesky] [Facebook]
[Build Your Own Python Action Arcade!]

[Build Your Own Ray Tracer With Python]

[Beginning Database Design Solutions, Second Edition]

[Beginning Software Engineering, Second Edition]

[Essential Algorithms, Second Edition]

[The Modern C# Challenge]

[WPF 3d, Three-Dimensional Graphics with WPF and C#]

[The C# Helper Top 100]

[Interview Puzzles Dissected]

Title: Make a row container with tkinter in Python

[Buttons arranged in row containers]

Two of the more annoying omissions from tkinter are row and column containers. You can't just drop widgets into a container and have the container arrange them in rows and columns, but it's actually quite easy to make a Frame widget do almost the same thing.

Pack It In

The only trick is to use pack to arrange the widgets. If you always set the side parameter to tk.TOP or tk.LEFT, the result is basically a row or column container.

Here's the code this example uses to create its buttons in rows.

def build_ui(self): '''Build the user interface.''' margin = 5 for row_number in range(10): frame = tk.Frame(self.window) frame.pack(side=tk.TOP, padx=margin, pady=margin, expand=True, fill=tk.X) for i in range(10): button = tk.Button(frame, text=f'{i}', width=2, bg='white') button.pack(side=tk.LEFT, padx=(2)) button.configure(command= lambda btn=button: self.delete_button(btn))

This code uses a loop to create 10 rows. For each row, it makes a frame to use as a row container and then uses a second loop to add buttons to the row.

Each button is packed with side=tk.LEFT so they fill the Frame in a row starting at the left.

After it creates each button, the program configures it to call the delete_button event handler when it is clicked. It passes the button into that method.

In case you haven't seen this syntax before, notice the btn=button part of the lambda function. That takes the current value of button, which is the button that was just created, and saves it in variable btn. It then passes btn into the call to delete_button. If you don't copy the button value into a local variable, the delete_button method uses the current value of the button variable when it executes, and that value is the last button created. That means delete_button deletes the last button added and none of the other ones.

delete_button

Here's the delete_button method in all of its laconic glory.

def delete_button(self, button): '''Destroy the button.''' button.destroy()

The method takes the clicked button as a parameter and calls its destroy method to (you guessed it!) destroy that button.

The really cool thing is that the Frame containing the button notices that it is gone and rearranges its other children. That's why the buttons are all pushed to the left in the picture at the top of this post. As buttons are destroyed, the others automatically slide over to fill in the gaps!

Conclusion

By packing widgets in a Frame with side=tk.LEFT or side=tk.TOP, you can easily make a row or column container. The pack method can do a lot more than that, so in a sense this is much ado about nothing. It's more a mental exercise than a programming trick. If you treat a Frame like a row or column container, it becomes one.

Download the example to experiment with it and to see additional details.

© 2025 Rocky Mountain Computer Consulting, Inc. All rights reserved.