0

I've been looking for a good python module to work with tables. In the past, I made a personal C# project, and using tables was pretty straight forward.

I found out that my solution could be in dmnfarrell's "tkintertable" repo: https://github.com/dmnfarrell/tkintertable

  • I'm currently working with python 3.7

  • The default Tcl lib installed in my python3.7 is Tcl8.6.


So I installed the repository and started to try it out, this is a short code snippet:

from tkintertable import TableCanvas, TableModel
from tkinter import *
from tkintertable.Testing import sampledata


data = sampledata()

"""data = {0: {'a': 0.85, 'b': 0.89, 'c': 0.01, 'd': 0.98, 'e': 0.88}, 
           1: {'a': 0.14, 'b': 0.52, 'c': 0.68, 'd': 0.68, 'e': 0.74},
           2: {'a': 0.75, 'b': 0.23, 'c': 0.92, 'd': 0.1, 'e': 0.42},
           3: {'a': 0.15, 'b': 0.2, 'c': 0.37, 'd': 0.96,'e': 0.08},
           4: {'a': 0.44, 'b': 0.41, 'c': 0.29, 'd': 0.16, 'e': 0.05},
           5: {'a': 0.7, 'b': 0.52, 'c': 0.3, 'd': 0.55, 'e': 0.01},
           6: {'a': 0.9, 'b': 0.63, 'c': 0.29, 'd': 0.66, 'e': 0.76},
           7: {'a': 0.19, 'b': 0.78, 'c': 0.04, 'd': 0.67, 'e': 0.41},
           8: {'a': 0.33, 'b': 0.94, 'c': 0.02, 'd': 0.38, 'e': 0.33},
           9: {'a': 0.81, 'b': 0.58, 'c': 0.57, 'd': 0.9, 'e': 0.89}} 
"""

table = TableCanvas(tframe,
                        data=data,
                        cellbackgr='#F1EFEF',
                        thefont=('Arial', 12),
                        rowheight=30,
                        bg="red",
                        reverseorder=1,
                        grid_color="black",
                        selectedcolor="gray",
                        multipleselectioncolor="#CCCCFF",
                        )

    table.show()

At some point, this worked well but after a while, I started getting this error:

    File "C:\MRES1\AppData\Roaming\Python\Python37\site-packages\tkintertable\Tables.py", line 
    1534, in drawGrid
        fill=self.grid_color, width=self.linewidth)
     File "C:\Program Files\Python37\lib\tkinter\__init__.py", line 2489, in create_line
        return self._create('line', args, kw)
     File "C:\Program Files\Python37\lib\tkinter\__init__.py", line 2477, in _create
            *(args + self._options(cnf, kw))))
     _tkinter.TclError: bad screen distance "1.0"

So I started looking for this error and ran into this: Matplotlib - _tkinter.TclError: bad screen distance "320.0"

So I told to my self "let's try this" I didn't know where to change this so I ran (I know this might be a mistake) int to the implementation of the TableCanvas class and looked for the line given int the error log. That would be 1534.

File "C:\MRES1\AppData\Roaming\Python\Python37\site-packages\tkintertable\Tables.py", line 1534, in drawGrid fill=self.grid_color, width=self.linewidth)

Inside that class that's actually from dmnfarrell's repo I did a little change to make it work. I'm not saying this is a good practice at all but the error stopped.

Old

        if self.vertlines==1:
        for col in range(cols+1):
            x=self.col_positions[col]
            self.create_line(x,y_start,x,y_start+rows*h, tag='gridline',
                                 fill=self.grid_color, width=self.linewidth)
    if self.horizlines==1:
        for row in range(startrow, endrow+1):
            y_pos=y_start+row*h
            self.create_line(x_start,y_pos,self.tablewidth,y_pos, tag='gridline',
                                fill=self.grid_color, width=self.linewidth)

New

        if self.vertlines==1:
        for col in range(cols+1):
            x=self.col_positions[col]
            self.create_line(x,y_start,x,y_start+rows*h, tag='gridline',
                                 fill=self.grid_color, width=int(self.linewidth))
    if self.horizlines==1:
        for row in range(startrow, endrow+1):
            y_pos=y_start+row*h
            self.create_line(x_start,y_pos,self.tablewidth,y_pos, tag='gridline',
                                fill=self.grid_color, width=int(self.linewidth))

Notice that the only thing that changes is in the width field precisely on the int() convertion.


This approach worked fine till I changed my data to something little more realistic coming from an sqlite3 data base with a few more fields and elements. So I gave needed format to the data to populate my table and once again:

_tkinter.TclError: bad screen distance "1323.5"

But this time the error occurred in another part of the TableCanvas class so I basically went there and did the same that in the other case to fix this and worked fine again.

This is the exact part :

File "C:\Users\MRES1\AppData\Roaming\Python\Python37\site-packages\tkintertable\Tables.py", line 332, in redraw
self.configure(scrollregion=(0,0, self.table.tablewidth+self.table.x_start, self.height))

So once again I converted to int() the width used there:

    self.tablewidth = int(self.tablewidth)  # Basically here is where I make the convertion. 
    
    # The line below is where I figured to be a good starting point to deal with the error.
    self.configure(scrollregion=(0,0, self.tablewidth+self.x_start, self.rowheight*self.rows+10))

I Know this might be one of the worst workarounds to fix this, I know I'm a newbie. Just want some advice from you guys to work properly with this module and if that's not possible it would be great if you could give me any advice.

I know I might not use the proper vocabulary, any advice on this is welcomed too. Thank you all!

1 Answers1

0

For tables in tkinter you can also use the tkinter.ttk Treeview widget. However, please note that there are user interface limitations with this such as being unable to sort the data in the columns and being unable to change the colours. Please see the below code snippet i had written it has comments breaking down the code. You can copy the code to demo it yourself Treeview in the code snippet

import tkinter as tk
from tkinter import ttk

# This is our data set of 151 Pokemon it is a list of lists
pokemon_info = [['Bulbasaur', 'Grass', '318'], ['Ivysaur', 'Grass', '405'], ['Venusaur', 'Grass', '525'], ['Charmander', 'Fire', '309'], ['Charmeleon', 'Fire', '405'], ['Charizard', 'Fire', '534'], ['Squirtle', 'Water', '314'], ['Wartortle', 'Water', '405'], ['Blastoise', 'Water', '530'], ['Caterpie', 'Bug', '195'], ['Metapod', 'Bug', '205'], ['Butterfree', 'Bug', '395'], ['Weedle', 'Bug', '195'], ['Kakuna', 'Bug', '205'], ['Beedrill', 'Bug', '395'], ['Pidgey', 'Normal', '251'], ['Pidgeotto', 'Normal', '349'], ['Pidgeot', 'Normal', '479'], ['Rattata', 'Normal', '253'], ['Raticate', 'Normal', '413'], ['Spearow', 'Normal', '262'], ['Fearow', 'Normal', '442'], ['Ekans', 'Poison', '288'], ['Arbok', 'Poison', '448'], ['Pikachu', 'Electric', '320'], ['Raichu', 'Electric', '485'], ['Sandshrew', 'Ground', '300'], ['Sandslash', 'Ground', '450'], ['Nidoran?', 'Poison', '275'], ['Nidorina', 'Poison', '365'], ['Nidoqueen', 'Poison', '505'], ['Nidoran?', 'Poison', '273'], ['Nidorino', 'Poison', '365'], ['Nidoking', 'Poison', '505'], ['Clefairy', 'Fairy', '323'], ['Clefable', 'Fairy', '483'], ['Vulpix', 'Fire', '299'], ['Ninetales', 'Fire', '505'], ['Jigglypuff', 'Normal', '270'], ['Wigglytuff', 'Normal', '435'], ['Zubat', 'Poison', '245'], ['Golbat', 'Poison', '455'], ['Oddish', 'Grass', '320'], ['Gloom', 'Grass', '395'], ['Vileplume', 'Grass', '490'], ['Paras', 'Bug', '285'], ['Parasect', 'Bug', '405'], ['Venonat', 'Bug', '305'], ['Venomoth', 'Bug', '450'], ['Diglett', 'Ground', '265'], ['Dugtrio', 'Ground', '425'], ['Meowth', 'Normal', '290'], ['Persian', 'Normal', '440'], ['Psyduck', 'Water', '320'], ['Golduck', 'Water', '500'], ['Mankey', 'Fighting', '305'], ['Primeape', 'Fighting', '455'], ['Growlithe', 'Fire', '350'], ['Arcanine', 'Fire', '555'], ['Poliwag', 'Water', '300'], ['Poliwhirl', 'Water', '385'], ['Poliwrath', 'Water', '510'], ['Abra', 'Psychic', '310'], ['Kadabra', 'Psychic', '400'], ['Alakazam', 'Psychic', '500'], ['Machop', 'Fighting', '305'], ['Machoke', 'Fighting', '405'], ['Machamp', 'Fighting', '505'], ['Bellsprout', 'Grass', '300'], ['Weepinbell', 'Grass', '390'], ['Victreebel', 'Grass', '490'], ['Tentacool', 'Water', '335'], ['Tentacruel', 'Water', '515'], ['Geodude', 'Rock', '300'], ['Graveler', 'Rock', '390'], ['Golem', 'Rock', '495'], ['Ponyta', 'Fire', '410'], ['Rapidash', 'Fire', '500'], ['Slowpoke', 'Water', '315'], ['Slowbro', 'Water', '490'], ['Magnemite', 'Electric', '325'], ['Magneton', 'Electric', '465'], ["Farfetch'd", 'Normal', '377'], ['Doduo', 'Normal', '310'], ['Dodrio', 'Normal', '470'], ['Seel', 'Water', '325'], ['Dewgong', 'Water', '475'], ['Grimer', 'Poison', '325'], ['Muk', 'Poison', '500'], ['Shellder', 'Water', '305'], ['Cloyster', 'Water', '525'], ['Gastly', 'Ghost', '310'], ['Haunter', 'Ghost', '405'], ['Gengar', 'Ghost', '500'], ['Onix', 'Rock', '385'], ['Drowzee', 'Psychic', '328'], ['Hypno', 'Psychic', '483'], ['Krabby', 'Water', '325'], ['Kingler', 'Water', '475'], ['Voltorb', 'Electric', '330'], ['Electrode', 'Electric', '490'], ['Exeggcute', 'Grass', '325'], ['Exeggutor', 'Grass', '530'], ['Cubone', 'Ground', '320'], ['Marowak', 'Ground', '425'], ['Hitmonlee', 'Fighting', '455'], ['Hitmonchan', 'Fighting', '455'], ['Lickitung', 'Normal', '385'], ['Koffing', 'Poison', '340'], ['Weezing', 'Poison', '490'], ['Rhyhorn', 'Ground', '345'], ['Rhydon', 'Ground', '485'], ['Chansey', 'Normal', '450'], ['Tangela', 'Grass', '435'], ['Kangaskhan', 'Normal', '490'], ['Horsea', 'Water', '295'], ['Seadra', 'Water', '440'], ['Goldeen', 'Water', '320'], ['Seaking', 'Water', '450'], ['Staryu', 'Water', '340'], ['Starmie', 'Water', '520'], ['Scyther', 'Bug', '500'], ['Jynx', 'Ice', '455'], ['Electabuzz', 'Electric', '490'], ['Magmar', 'Fire', '495'], ['Pinsir', 'Bug', '500'], ['Tauros', 'Normal', '490'], ['Magikarp', 'Water', '200'], ['Gyarados', 'Water', '540'], ['Lapras', 'Water', '535'], ['Ditto', 'Normal', '288'], ['Eevee', 'Normal', '325'], ['Vaporeon', 'Water', '525'], ['Jolteon', 'Electric', '525'], ['Flareon', 'Fire', '525'], ['Porygon', 'Normal', '395'], ['Omanyte', 'Rock', '355'], ['Omastar', 'Rock', '495'], ['Kabuto', 'Rock', '355'], ['Kabutops', 'Rock', '495'], ['Aerodactyl', 'Rock', '515'], ['Snorlax', 'Normal', '540'], ['Articuno', 'Ice', '580'], ['Zapdos', 'Electric', '580'], ['Moltres', 'Fire', '580'], ['Dratini', 'Dragon', '300'], ['Dragonair', 'Dragon', '420'], ['Dragonite', 'Dragon', '600'], ['Mewtwo', 'Psychic', '680'], ['Mew', 'Psychic', '600']]

# initialize the tkinter GUI
root = tk.Tk()

root.geometry("500x500")
root.pack_propagate(0)
root.resizable(0, 0)

# This is the frame were we will store our TreeView
frame1 = tk.LabelFrame(root, text="This is a LabelFrame containing a Treeview")
frame1.place(height=300, width=500)

# When this button is clicked it will refresh the TreeView
button1 = tk.Button(root, text="Refresh Table", command=lambda: Refresh_data())
button1.place(rely=0.65, relx=0.50)

tv1 = ttk.Treeview(frame1)  # This is the Treeview Widget
column_list_account = ["Name", "Type", "Base Stat Total"]  # These are our headings
tv1['columns'] = column_list_account  # We assign the column list to the widgets columns
tv1["show"] = "headings"  # this hides the default column..

for column in column_list_account:  # foreach column
    tv1.heading(column, text=column)  # let the column heading = column name
    tv1.column(column, width=50)  # set the columns size to 50px
tv1.place(relheight=1, relwidth=1)  # set the height and width of the widget to 100% of its container (frame1).
treescroll = tk.Scrollbar(frame1)  # create a scrollbar
treescroll.configure(command=tv1.yview)  # make it vertical
tv1.configure(yscrollcommand=treescroll.set)  # assign the scrollbar to the Treeview Widget
treescroll.pack(side="right", fill="y")  # make the scrollbar fill the yaxis of the Treeview widget


def Load_data():
    # foreach row of pokemon data insert the row into the treeview.
    for row in pokemon_info:
        tv1.insert("", "end", values=row)


def Refresh_data():
    # Deletes the data in the current treeview
    tv1.delete(*tv1.get_children())  # the '*' is a splat operator

    # loads the data again
    Load_data()

root.mainloop()  # The mainloop for our tkinter Gui
RamWill
  • 288
  • 1
  • 3
  • 6