【问题标题】:How do I properly work with Tables with tkinter?如何使用 tkinter 正确处理表格?
【发布时间】:2020-07-15 03:20:04
【问题描述】:

我一直在寻找一个很好的 python 模块来处理表格。过去,我做了一个个人 C# 项目,使用表格非常简单。

我发现我的解决方案可能在 dmnfarrell 的“tkintertable”存储库中: https://github.com/dmnfarrell/tkintertable

  • 我目前正在使用 python 3.7

  • 我的python3.7中安装的默认Tcl库是Tcl8.6


于是我安装了存储库并开始尝试,这是一个短代码sn-p:

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()

在某些时候,这工作得很好,但过了一段时间,我开始收到这个错误:

    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"

所以我开始寻找这个错误并遇到了这个:Matplotlib - _tkinter.TclError: bad screen distance "320.0"

所以我告诉自己“让我们试试这个”我不知道在哪里改变它所以我跑(我知道这可能是一个错误)int 到 @987654327 的实现@class 并查找错误日志中给出的行。那将是1534

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

class 内部,实际上来自 dmnfarrell 的存储库,我做了一些更改以使其正常工作。 我并不是说这是一个好习惯,但错误停止了。

        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)

        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))

请注意,唯一改变的是 width 字段中的 int() 转换。


这种方法效果很好直到我将我的 数据 更改为来自 sqlite3 数据库的更真实的东西,其中包含更多字段和元素。所以我给数据提供了所需的格式来填充我的表格,然后再一次:

_tkinter.TclError: bad screen distance "1323.5"

但这次错误发生在 TableCanvas 类的另一部分,所以我基本上去了那里,并在另一种情况下做了同样的事情来解决这个问题并再次正常工作。

这是确切的部分:

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))

所以我再一次转换为int() 那里使用的width

    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))

我知道这可能是解决此问题的最糟糕的解决方法之一,我知道我是新手。 只是想从你们那里得到一些建议,以便正确使用这个模块,如果这不可能,如果你能给我任何建议,那就太好了。

我知道我可能不会使用正确的词汇,也欢迎对此提出任何建议。 谢谢大家!

【问题讨论】:

  • 该代码在我的 Python 3.7 和 tkintertable 1.3.2 中运行良好。

标签: python tkinter python-3.7 tkintertable


【解决方案1】:

对于 tkinter 中的表格,您还可以使用 tkinter.ttk Treeview 小部件。但是,请注意,这存在用户界面限制,例如无法对列中的数据进行排序以及无法更改颜色。请看下面的代码 sn-p 我写的它有 cmets 分解代码。可以自己复制代码来演示

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-31
    • 1970-01-01
    • 1970-01-01
    • 2018-02-05
    • 2016-12-11
    • 1970-01-01
    • 2010-09-27
    相关资源
    最近更新 更多