13

I am looking to create something that resembles a table in Tkinter but it doesn't necessarily have to be one.

I would like to create headers 'Name1', 'Name2', 'Value' for example and beneath each one I wish to have several blank rows.

These rows I then wish to fill in later (therefore a Label) with values I have calculated or string values for names.

For 'Name2' I would actually like for the entire column to be a drop down menu. I have already created the code for one on it's own but am not sure how to incorporate it into this 'table'.

Is it for example possible to create a border around a Label widget so it looks like a 'table'?

Any pointers towards what would be possible in this situation would be very much appreciated. If you require any of my code to have a go at something, just ask. Thank you!

user2063
  • 975
  • 4
  • 15
  • 35

3 Answers3

42

What problem are you having? The simple solution is to lay out widgets using grid. You can put whatever type of widget you want in each cell. And yes, labels can have borders. Though, a simple way to do grid lines is to use a padding around each cell, so that the color of the frame will show through the gaps.

Do this in a frame. If you need to be able to scroll the table, put the frame inside a canvas and add scrollbars. There are examples all over the web for how to create a scrollable frame using a canvas.

Here's a really quick example that uses just labels, and doesn't scroll. I'll leave the exact implementation of what you need as an exercise for the reader.

import Tkinter as tk

class ExampleApp(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        t = SimpleTable(self, 10,2)
        t.pack(side="top", fill="x")
        t.set(0,0,"Hello, world")

class SimpleTable(tk.Frame):
    def __init__(self, parent, rows=10, columns=2):
        # use black background so it "peeks through" to 
        # form grid lines
        tk.Frame.__init__(self, parent, background="black")
        self._widgets = []
        for row in range(rows):
            current_row = []
            for column in range(columns):
                label = tk.Label(self, text="%s/%s" % (row, column), 
                                 borderwidth=0, width=10)
                label.grid(row=row, column=column, sticky="nsew", padx=1, pady=1)
                current_row.append(label)
            self._widgets.append(current_row)

        for column in range(columns):
            self.grid_columnconfigure(column, weight=1)


    def set(self, row, column, value):
        widget = self._widgets[row][column]
        widget.configure(text=value)

if __name__ == "__main__":
    app = ExampleApp()
    app.mainloop()
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • My only problem now is that I've never really used 'self' or '__init__' much and don't quite understand how to incorporate my other functions for menus etc. Would you be able to give me some advice (for extreme beginners!) please? – user2063 Jun 15 '12 at 12:19
  • For example, I'm even a little confused as to how to assign a name to the Frame...but I have functions for opening and menus etc. – user2063 Jun 15 '12 at 12:26
  • @user20: why do you think you need to assign a name to the frame? In the above example, `t` holds a reference to the frame, that's all you need to be able to use it. – Bryan Oakley Jun 15 '12 at 12:28
  • 1
    What does `self.grid_columnconfigure(column, weight=1)` do? (I tried omitting this part of your example and see NO change) (Python 3.6) – Siemkowski Jul 26 '17 at 16:12
  • 2
    @Siemkowski: it tells the grid geometry manager how to allocate extra space. If you omit the code, you will see a difference as soon as you manually resize the widget to make it bigger. – Bryan Oakley Jul 26 '17 at 16:26
4

A fairly simple object-less solution I found:

from Tkinter import *

rows = []
for i in range(5):
    cols = []
    for j in range(4):
        e = Entry(relief=RIDGE)
        e.grid(row=i, column=j, sticky=NSEW)
        e.insert(END, '%d.%d' % (i, j))
        cols.append(e)
    rows.append(cols)

def onPress():
    for row in rows:
        for col in row:
            print col.get(),
        print

Button(text='Fetch', command=onPress).grid()
mainloop()

or

# simple 2d table

from Tkinter import *

for i in range(5):
    for j in range(4):
        l = Label(text='%d.%d' % (i, j), relief=RIDGE)
        l.grid(row=i, column=j, sticky=NSEW)

mainloop()

All available at http://www.java2s.com/Code/Python/GUI-Tk/

HCLivess
  • 1,015
  • 1
  • 13
  • 21
0

How to create table from a dictionary:

my_dict = {
    1: {'Header1': 'Row1_Value1', 'Header2': 'Row1_Value2', 'Header3': 'Row1_Value3', },
    2: {'Header1': 'Row2_Value1', 'Header2': 'Row2_Value2', 'Header3': 'Row2_Value3', },

    }

# Create the header
for column, header in enumerate(my_dict[1]):
    Label(self, text=header).grid(row=0, column=0+column)

# Fill in the values
for row, element in enumerate(my_dict.values()):
    for column, (header, value) in enumerate(element.items()):
        Label(self, text=value).grid(row=1+row, column=0+column)
Toby
  • 51
  • 3