Search code examples
pythonpandastkinterlayoutpandastable

In Python with Tinkter, how can I use a grid to display a PandasTable instead of pack?


I am researching how to use Tkinter ( CustomTkinter ) and I would like to display a pandastable using the Tkinter GRID layout, instead of the PACK layout. The code below will show the table but it is taking up the entire frame.

The entire project is very large and complex but here is the relevant code:

import customtkinter as ctk
import pandas as pd
from tkinter import END
from pandastable import Table

class DisplayTable(ctk.CTkFrame):
    def __init__(self, parent):
        ctk.CTkFrame.__init__(self, parent)
        
        label = ctk.CTkLabel(self, text="DisplayTable")
        label.grid(row=0, column=1, padx=10, pady=10, columnspan=4)

        df = pd.read_csv("data/data_points.csv")
        self.table = Table(self, dataframe=df, showtoolbar=True, showstatusbar=True)
        self.table.grid(row=1, column=1, padx=10, pady=10, columnspan=4)
        self.table.show()
 

My question is how to apply the GRID layout to the pandastable so that I have a label at the top of the screen and panddastable below?


Solution

  • First of all, I think there might be some issue with bindings in CustomTkinter because I got the same error as here: AttributeError in Ctk For some reason, Ctk doesn't allow bind_all

    The solution should be to have the master of the Table as a separate frame. This worked great when I used regular Tkinter (without this extra frame, the Table took up the whole window also):

    import customtkinter as ctk
    import pandas as pd
    from tkinter import END
    import tkinter as tk
    from pandastable import Table
    
    
    class DisplayTable(tk.Frame):
        def __init__(self, parent):
            tk.Frame.__init__(self, parent, relief="sunken")
    
            label = tk.Label(self, text="DisplayTable", relief="sunken")
            label.grid(row=0, column=1, padx=10, pady=10, columnspan=4)
    
            df = pd.read_csv("data_points.csv")
    
            self.table_FRAME = tk.Frame(self)
            self.table = Table(self.table_FRAME,
                               dataframe=df,
                               showtoolbar=True,
                               showstatusbar=True)
            self.table.grid(row=0, column=0, padx=10, pady=10, columnspan=4)
            self.table_FRAME.grid(row=1, column=1, padx=30, pady=10, columnspan=4,
                                  rowspan=10)
            # self.table_FRAME.grid_propagate(False)
            # self.table_FRAME.configure(width=10, height=20)
            self.table.show()
    
    
    if __name__ == '__main__':
        # Declare root window first to be able to get screen information
        root = tk.Tk()
    
        app = DisplayTable(parent=root)
        app.pack(fill="both", expand=True)
    
        root.mainloop()
    

    enter image description here

    If I try the same thing with CustomTkinter I get the AttributeError I mentioned in the beginning.


    Workaround with using CustomTkinter anyway (use at your own risk because it involves changing behaviors that the author of the code took into consideration):

    Code with Ctk:

    import customtkinter as ctk
    import pandas as pd
    from tkinter import END
    import tkinter as tk
    from pandastable import Table
    
    
    class DisplayTable(ctk.CTkFrame):
        def __init__(self, parent):
            ctk.CTkFrame.__init__(self, parent)
    
            label = ctk.CTkLabel(self, text="DisplayTable")
            label.grid(row=0, column=1, padx=10, pady=10, columnspan=4)
    
            df = pd.read_csv("data_points.csv")
    
            self.table_FRAME = ctk.CTkFrame(self)
            self.table = Table(self.table_FRAME,
                               dataframe=df,
                               showtoolbar=True,
                               showstatusbar=True)
            self.table.grid(row=0, column=0, padx=10, pady=10, columnspan=4)
            self.table_FRAME.grid(row=1, column=1, padx=30, pady=10, columnspan=4,
                                  rowspan=10)
            # self.table_FRAME.grid_propagate(False)
            # self.table_FRAME.configure(width=10, height=20)
            self.table.show()
    
    
    if __name__ == '__main__':
        # Declare root window first to be able to get screen information
        root = tk.Tk()
    
        app = DisplayTable(parent=root)
        app.pack(fill="both", expand=True)
    
        root.mainloop()
     
    

    Now when you get this error:

      File "C:\Dev\Python\Lib\site-packages\customtkinter\windows\widgets\core_widget_classes\ctk_base_class.py", line 253, in bind_all
        raise AttributeError("'bind_all' is not allowed, could result in undefined behavior")
    AttributeError: 'bind_all' is not allowed, could result in undefined behavior
    

    Follow the link to the bind_all method, comment out the raise AttributeError and just add pass

    def bind_all(self, sequence=None, func=None, add=None):
        # raise AttributeError("'bind_all' is not allowed, could result in undefined behavior")
        pass
    

    enter image description here

    This got it to work but I have no idea why bind_all could result in undefined behavior using CustomTkinter so again, use at your own risk.