Inserting new rows in Tkinter grid

Viewed 7129

Let's say I have a Tkinter app with 2 rows displaying 2 widgets:

from tkinter import *
from tkinter.ttk import *
root = Tk()
Label(root, text="Some Data").grid(row=0)
Label(root, text="Some Data").grid(row=1)
root.mainloop()

Now this will display two widgets on row0 and row1. Now if I want to insert another (one or more) widget between these two rows at a later stage (say as a response to a button click event), what would be the best way to do that.

Current output:

Some Data
Some Data

Expected output:

Some Data
<<New data>>
Some Data

<<New Data>> will be inserted at a later stage as a response to a button click.

<<New Data>> may be one or more rows.

1 Answers

I do have a simple solution for you.

If you are expecting to insert a widget later and you know you will be then you can simply place your 2nd label on grid row 2 and then place your new widget on grid row 1 later. If you need to have more than one row you could place your 2nd label even further down the line.

from tkinter import *
from tkinter.ttk import *
root = Tk()

def add_new_data():
    Label(root, text="<<New Data>>").grid(row=1)

Label(root, text="Some Data").grid(row=0)
Label(root, text="Some Data").grid(row=2)

Button(root, text="Add New Data", command=add_new_data).grid(row=3)

root.mainloop()

Results:

enter image description here enter image description here

The reason this works is because Tkinter's geometry manager will collapse rows and columns to nothing if there is nothing in them so you can use this behavior to your advantage when working with something like this.


Now if you wanted something that could work with any number of label then we can use a list to help us accomplish that.

My next example with be written in class and will show the use of a list to do what we want.

We can store widgets in a list and because we can do this we are also able to decide where in that list to put stuff and use the lists index to our advantage when setting up the grid.

First thing is to create our Some Data labels and append them to a list. The next is the add the button to that list at the end of the list. This button we will used to call a class method that will insert() a new label into our list.

Next that same method will forget the grid for all widgets inside of our label frame and then it will perform a for loop over the list and re add all the old widgets and the new one in the correct order.

Take a look at the below example.

import tkinter as tk


class App(tk.Frame):

    def __init__(self, master, *args, **kwargs):
        tk.Frame.__init__(self, master, *args, **kwargs)
        self.master = master
        self.label_frame = tk.Frame(self.master)
        self.label_frame.grid()

        self.label_list = []

        for i in range(2):
            self.label_list.append(tk.Label(self.label_frame, text="Some Data"))
            self.label_list[i].grid(row=i)

        self.label_list.append(tk.Button(self.label_frame, text="Add new data", command=self.add_new_data))
        self.label_list[2].grid(row=2)

    def add_new_data(self):
        self.label_list.insert(1, tk.Label(self.label_frame, text="<<New Data>>"))

        for widget in self.label_frame.children.values():
            widget.grid_forget() 

        for ndex, i in enumerate(self.label_list):
            i.grid(row=ndex)


if __name__ == "__main__":
    root = tk.Tk() 
    my_app = App(root)
    root.mainloop()

Results:

enter image description here

We can add as many new labels as we like.

Related