How to make python tkinter treeview widget to fill empty row and column spaces on grid?

Question:

I have a window to display multiple treeview widgets. Currently there are some empty row spaces below the treeview when I expand it and I’m not sure on how to fill the empty spaces below dynamically when I expand the window. I have tried adjusting the rowspan/columnspan options but could not get the desired output as described in image below. I have also included a reproduceable code below for testing my program. Please help to advise on which part I need to make changes. Thanks!

Window Layout

import shutil
import tkinter as tk
import tkinter.ttk as ttk
import tempfile
import zipfile, re, os
from tkinter import *
from tkinter import filedialog
from pathlib import Path
import tkinter.messagebox
from fpdf import FPDF
from datetime import datetime, timedelta
import ctypes

DEPTH = 2
EXCLUDES = {'__MACOSX', 'resources'}

class HomePage(Tk):
    def __init__(self, *args, **kwargs):
        Tk.__init__(self, *args, **kwargs)
        self.notebook = ttk.Notebook()  # Create a notebook widget
        self.add_tab1()
        self.notebook.grid(row=0)
        self.notebook.pack(expand=1, fill="both")

    def add_tab1(self):
        tab1 = tab_one(self.notebook)
        self.notebook.add(tab1, text="Home")

class data_table(object):
    def __init__(self, site, panels_count, tev_count):
        self.site = site
        self.panels_count = panels_count
        self.tev_count = tev_count


class tab_one(Frame):
    def __init__(self, *args, **kwargs):
        Frame.__init__(self, *args, **kwargs)
        # Creating frames on the window/canvas for the first tab
        frame_selectfile = tk.LabelFrame(self, text="Step 1: Zip File Extraction ", bd=6)  # Frame1 on the window/canvas
        frame_selectfile.grid(column=0, row=0, padx=10, pady=10, sticky='NSEW')  # Positioning frame1
        frame_selectfile.configure(borderwidth=1)
        self.grid_columnconfigure(1, weight=1)  # Configuring the column for the main window/canvas
        self.grid_rowconfigure(1, weight=1)  # Configuring the row for the main window/canvas

        frame_checkpd = tk.LabelFrame(self, text="Step 2: Check PD ", bd=6)  # Frame2 on the window/canvas
        frame_checkpd.grid(column=1, row=0, padx=10, pady=10, sticky='NSEW')  # Positioning frame2
        frame_checkpd.configure(borderwidth=1)
        self.grid_columnconfigure(1, weight=1)  # Configuring the column for the main window/canvas
        self.grid_rowconfigure(1, weight=1)  # Configuring the row for the main window/canvas

        #Frame to display data in treeview
        frame_tree = tk.LabelFrame(self, text="PD Results ", bd=6)  # Frame2 on the window/canvas
        frame_tree.grid(column=0, row=1, columnspan=2, rowspan=2,  padx=10, pady=10, sticky='NSEW')  # Positioning frame2
        frame_tree.configure(borderwidth=1)
        self.grid_columnconfigure(1, weight=1)  # Configuring the column for the main window/canvas
        self.grid_rowconfigure(1, weight=1)  # Configuring the row for the main window/canvas

        # Initializing all variables in frame_selectfile
        file_ID = tk.StringVar()
        location_id = tk.StringVar()
        unzip_status = tk.StringVar()
        tmpdir = tempfile.TemporaryDirectory().name
        f_tem_sdir = open(os.getcwd()+"\temp_dir.txt", "w")
        f_tem_sdir.write(tmpdir)
        f_tem_sdir.close()
        zip_filename = tk.StringVar()
        site_id = tk.StringVar()
        site_id.set("0")
        data_table_list = []

        middleframe = tk.LabelFrame(frame_selectfile, bd=5)
        databaseView = ttk.Treeview(middleframe, selectmode="browse")
        label_filename = tk.Label(frame_selectfile, text=" ", width=10, relief='flat').grid(column=0, row=1, padx=5,
                                                                                            pady=5, sticky='NW')
        label_filelocation = tk.Label(frame_selectfile, text="File Location:", width=12, relief='flat').grid(column=0,
                                                                                                             row=2,
                                                                                                             padx=5,
                                                                                                             pady=5,
                                                                                                             sticky='NW')

        filename_Entry = tk.Label(frame_selectfile, width=52, textvariable=file_ID)
        filename_Entry.grid(column=1, row=1, padx=5, pady=5, sticky='NW')
        filename_Entry.configure(state='normal')

        filelocation_Entry = tk.Entry(frame_selectfile, width=63, textvariable=location_id)
        filelocation_Entry.grid(column=1, row=2, padx=5, pady=5, sticky='W')
        filelocation_Entry.configure(background='palegreen', foreground='black')

        unzip_status.set("")
        label_unzipstatus = tk.Label(frame_selectfile, width=20, relief='flat', textvariable=unzip_status)
        label_unzipstatus.grid(column=1, row=5, padx=5, pady=5, sticky='NSEW')

        selectzip_button = tk.Button(frame_selectfile, width=20, text="Select Zip File",
                                     command=lambda: self.upload_action(location_id, zip_filename, tmpdir))
        selectzip_button.grid(column=1, row=3, padx=5, pady=3, ipady=3, sticky='SW')

        unzip_button = tk.Button(frame_selectfile, width=20, text="Extract",
                                 command=lambda: self.extract_nested_zip(databaseView, data_table_list,
                                                                         location_id.get(), tmpdir, zip_filename,
                                                                         site_id, False))
        unzip_button.grid(column=1, row=3, padx=5, pady=3, ipady=3, sticky='NE')

        # Creating LabelFrame in frame_unzip
        upperframe = tk.LabelFrame(frame_selectfile, bd=0)
        frame_selectfile.rowconfigure(0, weight=1)
        frame_selectfile.columnconfigure(2, weight=1)
        upperframe.grid(column=0, row=6, columnspan=2, sticky='W')

        # middleframe = tk.LabelFrame(frame_selectfile, bd=5)
        middleframe.configure(borderwidth=1)
        frame_selectfile.columnconfigure(2, weight=1)
        frame_selectfile.rowconfigure(1, weight=1)
        middleframe.grid(column=0, row=7, columnspan=2, sticky="NSEW")

        lowerframe = tk.LabelFrame(frame_selectfile, bd=0)
        lowerframe.grid(column=0, row=7)
        frame_selectfile.columnconfigure(2, weight=1)
        frame_selectfile.rowconfigure(2, weight=0)

        # Labels in frame_unzip
        label18 = tk.Label(upperframe, text="Number of sites:", relief='flat')
        label18.grid(column=0, row=0, padx=5, pady=5, sticky='W')

        site_Entry = tk.Entry(upperframe, width=61, textvariable=site_id)
        site_Entry.grid(column=1, row=0, padx=10, pady=5, sticky='E')
        site_Entry.configure(state='normal', background='palegreen', foreground='black')

        label_details = tk.Label(upperframe, text=" ", relief='flat')
        label_details.grid(column=0, row=2, padx=5, pady=0, sticky='W')

        databaseView.columnconfigure(2, weight=1)
        databaseView.grid(column=0, row=0, columnspan=2, sticky="NSEW")

        # Creating treeview in frame_unzip
        vsb = Scrollbar(middleframe, orient="vertical", command=databaseView.yview())
        hsb = Scrollbar(middleframe, orient="horizontal")

        middleframe.columnconfigure(0, weight=1)
        middleframe.rowconfigure(0, weight=1)
        databaseView["show"] = "headings"
        databaseView["columns"] = ("site", "panels", "tevs")
        vsb.configure(command=databaseView.yview)
        vsb.grid(column=1, row=0, sticky="NS")

        # Treeview column headings
        databaseView.heading("site", text="Site")
        databaseView.column("site", anchor='w', width=250)
        databaseView.heading("panels", text="Number of Panels")
        databaseView.column("panels", anchor='center', width=150)
        databaseView.heading("tevs", text="Number of TEVs")
        databaseView.column("tevs", anchor='center', width=200)

        findpd_btn = tk.Button(frame_checkpd, width=20, text="Find PDs",
                               command=lambda: self.run_pd_model_exe(tmpdir, zip_filename,parent_tree, tree))
        findpd_btn.grid(column=0, row=0, padx=5, pady=5, sticky='E')
        export_pdf_btn = tk.Button(frame_checkpd, width=20, text="Export to PDF",
                                   command=lambda: self.export_to_pdf(tmpdir, location_id.get()))
        export_pdf_btn.grid(column=1, row=0, padx=5, pady=5, sticky='E')
        find_files_btn = tk.Button(frame_checkpd, width=20, text="Clear All",
                                   command=lambda: self.clear_all_files(tmpdir,parent_tree,tree,databaseView))
        find_files_btn.grid(column=2, row=0, padx=5, pady=5, sticky='W')

        scrollbary = Scrollbar(frame_tree, orient=VERTICAL)
        scrollbarx = Scrollbar(frame_tree, orient=HORIZONTAL)

        parentframe = tk.LabelFrame(frame_checkpd, bd=0)
        frame_checkpd.rowconfigure(2, weight=1)
        frame_checkpd.columnconfigure(2, weight=1, )
        parentframe.grid(column=0, row=1, columnspan=3, sticky='W')

        # PARENT TREE
        parent_tree = ttk.Treeview(parentframe,
                                   columns=("1", "2",
                                            "3", "4",
                                            "5", "6",
                                            "7", "8"),
                                   selectmode="extended")
        parent_tree.grid(row=1, column=0, pady=2, sticky=N + S + E + W)
        #self.parent_tree.pack(expand=True, fill='both')

        vsbb = Scrollbar(parentframe, orient="vertical", command=parent_tree.yview())

        vsbb.configure(command=parent_tree.yview)
        vsbb.grid(column=2, row=1, sticky="NS")

        parent_tree.heading("#0", text="")
        parent_tree.heading("1", text="File ID")
        parent_tree.heading("2", text="Date")
        parent_tree.heading("3", text="No")
        parent_tree.heading("4", text="Engineer")
        parent_tree.heading("5", text="Station")
        parent_tree.heading("6", text="Voltage (kV)")
        parent_tree.heading("7", text="Max dB")
        parent_tree.heading("8", text="Max PD (%)")

        # parent_tree.heading("8", text = "Panel No")
        parent_tree.column('#0', stretch=YES, minwidth=0, width=5, anchor=CENTER)
        parent_tree.column('#1', stretch=YES, minwidth=0, width=130, anchor=CENTER)
        parent_tree.column('#2', stretch=YES, minwidth=0, width=130, anchor=CENTER)
        parent_tree.column('#3', stretch=YES, minwidth=0, width=130, anchor=CENTER)
        parent_tree.column('#4', stretch=YES, minwidth=0, width=130, anchor=CENTER)
        parent_tree.column('#5', stretch=YES, minwidth=0, width=130, anchor=CENTER)
        parent_tree.column('#6', stretch=YES, minwidth=0, width=130, anchor=CENTER)
        parent_tree.column('#7', stretch=YES, minwidth=0, width=130, anchor=CENTER)
        parent_tree.column('#8', stretch=YES, minwidth=0, width=130, anchor=CENTER)

        # CHILD TREE
        tree = ttk.Treeview(frame_tree,
                            columns=("1", "2", "3", "4"
                                     , "5", "6", "7", "8"
                                     , "9"),
                            selectmode="extended")
                            #yscrollcommand=scrollbary.set,
                            #xscrollcommand=scrollbarx.set)
        tree.grid(row=0, column=0, pady=2, sticky=N + S + E + W)

#         scrollbary.config(command=tree.yview)
#         scrollbary.grid(row=0, column=1, pady=2, sticky=N + S)
# 
#         scrollbarx.config(command=tree.xview)
#         scrollbarx.grid(row=2, column=0, sticky=W + E)

        tree_vsb = Scrollbar(frame_tree, orient="vertical", command=tree.yview())
        tree_hsb = Scrollbar(frame_tree, orient="horizontal")
        tree_vsb.configure(command=tree.yview)
        tree_vsb.grid(column=1, row=0, sticky="NS")

        tree.heading("#0", text="")
        tree.heading("1", text="Panel No")
        tree.heading("2", text="TEV Name")
        tree.heading("3", text="Component")
        tree.heading("4", text="Sublocation")
        tree.heading("5", text="Phase Ref Lock")
        tree.heading("6", text="dB")
        tree.heading("7", text="PRPD")
        tree.heading("8", text="Pulse Wave")
        tree.heading("9", text="PD %")

        tree.column('#0', stretch=NO, minwidth=0, width=0, anchor=CENTER)
        tree.column('#1', stretch=YES, minwidth=0, width=175, anchor=CENTER)
        tree.column('#2', stretch=YES, minwidth=0, width=175, anchor=CENTER)
        tree.column('#3', stretch=YES, minwidth=0, width=175, anchor=CENTER)
        tree.column('#4', stretch=YES, minwidth=0, width=175, anchor=CENTER)
        tree.column('#5', stretch=YES, minwidth=0, width=175, anchor=CENTER)
        tree.column('#6', stretch=YES, minwidth=0, width=175, anchor=CENTER)
        tree.column('#7', stretch=YES, minwidth=0, width=175, anchor=CENTER)
        tree.column('#8', stretch=YES, minwidth=0, width=175, anchor=CENTER)
        tree.column('#9', stretch=YES, minwidth=0, width=175, anchor=CENTER)
        
if __name__ == '__main__':
    homePage = HomePage()
    homePage.title("Waveform Identifier")  # Window title
    screen_width = homePage.winfo_screenwidth()
    screen_height = homePage.winfo_screenheight()
    width = 1600
    height = 800
    x = (screen_width / 2) - (width / 2)
    y = (screen_height / 2) - (height / 2)
    homePage.geometry("%dx%d+%d+%d" % (width, height, x, y))
    homePage.resizable(1, 1)
    homePage.mainloop()
Asked By: Daniel

||

Answers:

Issues found

  • Wrong row number on frame_checkpd.rowconfigure(2, weight=1), it should be row 1.
  • Wrong sticky option on parentframe.grid(column=0, row=1, columnspan=3, sticky='W'), it should be ‘NSEW’.
  • missing parentframe.rowconfigure(...) and parentframe.columnconfigure(...)
  • missing frame_tree.rowconfigure(...) and frame_tree.columnconfigure(...)

Below is the required changes to achieve it:

class tab_one(Frame):
    def __init__(self, *args, **kwargs):
        ...
        parentframe = tk.LabelFrame(frame_checkpd, bd=0)
        frame_checkpd.rowconfigure(1, weight=1)    ### row 2 -> 1
        frame_checkpd.columnconfigure(2, weight=1, )
        parentframe.grid(column=0, row=1, columnspan=3, sticky='NSEW')  ### 'W' -> 'EW'

        # PARENT TREE
        parentframe.rowconfigure(1, weight=1) ### added
        parentframe.columnconfigure(0, weight=1) ### added
        ...
        # CHILD TREE
        frame_tree.rowconfigure(0, weight=1)  ### added
        frame_tree.columnconfigure(0, weight=1)  ### added
        ...

Result:

enter image description here

Answered By: acw1668