首页 > 解决方案 > tkinter treeview 行显示值与下划线的差异

问题描述

我有发票相关数据的树视图显示。发票标识符有下划线。我注意到下划线在 GUI 中正确显示,但是从树行数据获得的发票编号值省略了下划线。在将数据插入完整应用程序以处理问题之前,我目前正在替换 - 为 _ 。

我使用树视图或检索用户选择的行数据的方式是否会导致问题?或者,对于 GUI 显示与检索到的具有下划线字符的值之间的差异,是否有另一种解释?

我正在使用 python 3.6 和 tkinter 8.6

这是一个例子。

谢谢你。

import tkinter as tk
from tkinter import ttk

DATA = [('180518-23', '23/06/18'),
        ('180618_24', '27/06/18')]
def invoice_selected(event):
    row_selected = event.widget.focus()
    values = event.widget.item(row_selected)['values']
    invoicenumber = values[0]
    print('invoice number', invoicenumber)

ROOT = tk.Tk()
header = ('Invoice', 'Due')
tree = ttk.Treeview(columns=header,
                    show="headings",
                    height=5)
tree.grid()
for col, text in enumerate(header):
    tree.heading(col, text=text)
tree.bind('<<TreeviewSelect>>', invoice_selected)

for record in DATA:
    tree.insert('', 'end', values=record)
ROOT.mainloop()

标签: pythontkinter

解决方案


tl; dr:与其做item(row_selected)['values'],不如做item(row_selected, option='values')


我认为这实际上是 tkinter 中的一个错误,解决方法实际上是依赖于另一个错误,所以我将两者都归档为bpo #34447。但是让我们看看那边的 tkinter 专家怎么说。


同时,您希望了解为什么会有所作为,对吗?

如果您查看以下文档item

查询或修改指定项的选项。

如果没有给出选项,则返回一个带有项目选项/值的字典。如果指定了选项,则返回该选项的值。否则,将选项设置为kw给出的相应值。

因此,如果您要求该values选项,您将获得该values选项的价值。

但是,如果您不要求任何东西,tkinter 会尝试变得聪明,并为您提供包含所有选项的 dict。

问题在于,在幕后,tkinter 是 Tcl/Tk 的包装器。在 Tcl 中,一切都是字符串(在这方面它更像是 bash,而不是 Python);123number和 string之间没有区别'123'。在TreeView项目中存储整数是完全合法的,但它们的存储方式与字符串完全相同。

Tcl 代码为获取项目的所有选项返回的是一个 Tcl 键值对的 Tcl 列表,其中所有值都是 Tcl 字符串。Tkinter 不知道哪些应该是字符串,哪些应该是整数。2所以它试图猜测:任何可以使用int构造函数转换为 int 的字符串都是 int,其他任何字符串都是字符串。1你的字符串可以转换为int3,就是这样。

当然,这很 hacky,但它通常会做你想做的事,而且这样做会让事情变得更方便,而“相当 hacky 但通常可以方便地做你想做的事”几乎是 tkinter 的定义。

然而,我认为它应该认识到,虽然'123_456'它是一个完全有效的 Python 整数文字,但它不是Tcl 可以为整数创建的字符串,所以它不应该尝试解析它。

如果您想查看执行此操作的代码:ttk.TreeView.itemcalls ttk._val_or_dict,它调用tkinter._splitdictwithttk._tclobj_to_py作为值转换器。


但是为什么不在_val_or_dict单个键值对上运行转换器呢?老实说,我看不出有什么好的理由。但事实并非如此,因此我们可以利用这一事实来解决问题。


1. 如果一个值应该是一个浮点数怎么办?好吧,这在 s 中并不经常出现TreeView,因此 tkinter 不会打扰那个;你只是得到你的浮点数的字符串表示。但是在其他类型中,例如LabeledScale,其中浮点数更有用/更常见,它使用不同的函数来尝试float而不是字符串中int是否存在 a .

2. 如果你好奇这是什么样子,即使在 Tcl 列表已经被解析之后,尝试打印tree.tk.call(tree._w, 'item', row_selected)vs.的结果tree.tk.call(tree._w, 'item', row_selected, '-values')

3. 在早期版本的 Python 中,180618_24不是一个有效的 int 字面量,所以你仍然会得到一个字符串。但是在 3.6 中,允许使用下划线作为组分隔符,因此180618_24拼写 是一种完全有效的方式18061824,所以这就是你得到的。


推荐阅读