0

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?

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
vscoder
  • 929
  • 1
  • 10
  • 25

1 Answers1

1

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.

  • 1
    Excellent answer, the project is for a limited number of users so I can probably live with 'undefined' behaviors. I would suspect the toolbars are the main concern with that and I intend to disable them anyways. I'm at work and can't test this right now, after I confirm that your solution is correct I will award the you correct anwser. Again, nice job digging into the code and finding the exception. – vscoder May 08 '23 at 14:59
  • Thanx @vscoder! Hope it works on your side as well :) – Robert Salamon May 08 '23 at 17:47