7

I am new to Python and even newer to tkinter.

I've utilised code from stackoverflow (Switch between two frames in tkinter) to produce a program where new frames are called and placed on top of each other depending on what options the user selects. A stripped down version of my code is below. There are a lot more frames.

import tkinter as tk                
from tkinter import font  as tkfont 
import pandas as pd

class My_GUI(tk.Tk):

    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)

        self.title_font = tkfont.Font(family='Helvetica', size=18, weight="bold", slant="italic")


        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand=True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.frames = {}
        for F in (StartPage, Page_2):
            page_name = F.__name__
            frame = F(parent=container, controller=self)
            self.frames[page_name] = frame


            frame.grid(row=0, column=0, sticky="nsew")

        self.show_frame("StartPage")

    def show_frame(self, page_name):
        '''Show a frame for the given page name'''
        frame = self.frames[page_name]
        frame.tkraise()

class StartPage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(self, text="Welcome to....", font=controller.title_font)
        label.pack(side="top", fill="x", pady=10)

        button1 = tk.Button(self, text="Option selected",
                            command=lambda: controller.show_frame("Page_2"))
        button1.pack()



class Page_2(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(self, text="The payment options are displayed below", font=controller.title_font)
        label.pack(side="top", fill="x", pady=10)

        #I want the able to be display the dataframe here

        button = tk.Button(self, text="Restart",
                           command=lambda: controller.show_frame("StartPage"))
        button.pack()

a = {'Option_1':[150,82.50,150,157.50,78.75],
     'Option2':[245,134.75,245,257.25,128.63]}
df = pd.DataFrame(a,index=['a',
                    'b',
                    'c',
                    'd',
                    'e']) 

print(df.iloc[:6,1:2])

if __name__ == "__main__":
    app = My_GUI()
    app.mainloop()

When Page_2 appears I want it to display a dataframe with the code below.

a = {'Option_1':[150,82.50,150,157.50,78.75],
     'Option2':[245,134.75,245,257.25,128.63]}
df = pd.DataFrame(a,index=['a',
                    'b',
                    'c',
                    'd',
                    'e']) 

print(df.iloc[:6,1:2])

I've searched SO e.g. How to display a pandas dataframe in a tkinter window (tk frame to be precise) (no answer provided) and other websites for an answer to similar question but without success.

How and where would I place my dataframe code selection to appear in the area I want when I select Page_2?

bagpuss
  • 89
  • 2
  • 2
  • 10

2 Answers2

16

Check out pandastable. It is quite a fancy library for displaying and working with pandas tables.

Here is a code example from their documentation:

from tkinter import *
from pandastable import Table, TableModel

class TestApp(Frame):
        """Basic test frame for the table"""
        def __init__(self, parent=None):
            self.parent = parent
            Frame.__init__(self)
            self.main = self.master
            self.main.geometry('600x400+200+100')
            self.main.title('Table app')
            f = Frame(self.main)
            f.pack(fill=BOTH,expand=1)
            df = TableModel.getSampleData()
            self.table = pt = Table(f, dataframe=df,
                                    showtoolbar=True, showstatusbar=True)
            pt.show()
            return

app = TestApp()
#launch the app
app.mainloop()

and here a screenshot (also from their docs):

Screenshot from the pandastable documentation

Thawn
  • 765
  • 4
  • 15
5

As a start, you could have a look at Label and Text widgets, that usually are used to display text in your GUI.

You could probably try something like:

class Page_2(tk.Frame):
    def __init__(self, parent, controller):
        # ... your code ...
        global df # quick and dirty way to access `df`, think about making it an attribute or creating a function that returns it
        text = tk.Text(self)
        text.insert(tk.END, str(df.iloc[:6,1:2]))
        text.pack()
        # lbl = tk.Label(self, text=str(df.iloc[:6,1:2])) # other option
        # lbl.pack()                                      #

In the end, it really boils down to how fancy you want to be: the widgets are highly customizable, so you could achieve something very pleasing to the eye instead of the basic look of this example.


Edit:

I added a Combobox widget to select the option to display and a Button that prints it to the "display" widget of your choice.

from tkinter import ttk # necessary for the Combobox widget

# ... your code ...

class Page_2(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(self, text="The payment options are displayed below", font=controller.title_font)
        label.pack(side="top", fill="x", pady=10)

        global df
        tk.Label(self, text='Select option:').pack()
        self.options = ttk.Combobox(self, values=list(df.columns))
        self.options.pack()
        tk.Button(self, text='Show option', command=self.show_option).pack()

        self.text = tk.Text(self)
        self.text.pack()

        tk.Button(self, text="Restart",
                  command=lambda: controller.show_frame("StartPage")).pack()

    def show_option(self):
        identifier = self.options.get() # get option
        self.text.delete(1.0, tk.END)   # empty widget to print new text
        self.text.insert(tk.END, str(df[identifier]))

The text that is displayed is the default string representation of a data-frame's column; a custom text is left as an exercise.

Pier Paolo
  • 878
  • 1
  • 14
  • 23
  • @ Pier Paolo. Thank you for your suggestion. This has added in my dataframe. Is it possible to set it so it can be edited by user? – bagpuss Jun 28 '17 at 12:57
  • @bagpuss: In general, yes. But you'll have to be more specific about that: what should the user do? Should they choose which dataframe to load, or should they choose which columns/rows to display, or something else altogether? – Pier Paolo Jun 28 '17 at 13:09
  • @ Pier Paolo. I don't want the user having any editing functionality e.g. can't change what dataframe to load, can't change the dataframe contents, can't format the dataframe - completely lock down the dataframe that is displayed. When the frame is displayed it should show the dataframe for that particular option (based on my coding) so there's no need for it to be altered. – bagpuss Jun 28 '17 at 13:58
  • @bagpuss: I edited my answer. Please let me know wether I understood what you were asking for. – Pier Paolo Jun 28 '17 at 14:36
  • @ Pier Paolo: Not what I was after but will be useful for another idea I have. I think I've found a solution. I've added text.config(state = 'disabled') after text.pack(). This has stopped me changing the dataframe. Could you point me to where I can read about how to format this text table? In you first post you advised I could make it "fancy". Thinking lines, placement, bold, colour etc – bagpuss Jun 28 '17 at 15:34
  • @bagpuss: Have a look [here](http://www.tkdocs.com/tutorial/text.html) and [here](http://effbot.org/tkinterbook/entry.htm). – Pier Paolo Jun 28 '17 at 15:47
  • 2
    @ Pier Paolo: appreciate the links and thanks for all the advice. – bagpuss Jun 28 '17 at 16:45