Tkinter,自定义小部件和标签更新

时间:2016-05-29 10:21:17

标签: python tkinter

描述

我想为Tkinter制作一个自定义"Table Widget",到目前为止它几乎就像我想要的那样。

我遇到的问题是我希望该表格由"Labels"组成,我发现您必须使用"StringVar()'s"才能更新标签。

我真的不想1000个标签的1000个变量,所以我试图解决这个问题一个星期了。我发现的唯一解决方案是使用"Dicts",但我不认为这是一个很好的方法吗?我可能错了,但感觉它必须是这样做的一种方式:

myLabel = Label(root, text='myText')
myLabel.pack()
myLabel.setText('new text')

当前窗口小部件代码如下所示(This is my first custom widget so if this is horribly wrong or wrong in any way, please tell me)

来源

"""
Description:
        A TABLE WIDGET Extension for Tkinter
"""
try:
    #Python 3.X
    import tkinter #this is quite annoyng, without it (tkinter) wont be available....
    from tkinter import * # even with this
    from tkinter import ttk
    from tkinter.ttk import *

except ImportError:
    #python 2.X
    import tkinter
    from Tkinter import *
    from Tkinter import ttk
    from Tkinter.ttk import *



class ETable(tkinter.Frame):
    def __init__(self, parent, *args, **kwargs):
        tkinter.Frame.__init__(self, parent)
        self.init_table(parent, *args, **kwargs)

    def init_table(self, parent, *args, **kwargs):
        row_settings = {
                           'anchor': CENTER,
                           'background': '#C5FFFF',
                           'bitmap': None,
                           'borderwidth': 5,
                           'compound': None,
                           'cursor': None,
                           'font': None,
                           'foreground': '#000000',
                           'image': None,
                           'relief': FLAT,
                           'rows': 1,
                           'state': NORMAL,
                           'text': None,
                           'textvariable': None,
                           'underline': -1,
                           'width': 20,
                        }

        for kwarg in kwargs:
            if kwarg in row_settings:
                row_settings[kwarg] = kwargs[kwarg]

        self.table_rows = self.init_row(parent, *args, **row_settings)

    def init_row(self, parent, *args, **kwargs):
        text_list = kwargs.pop('text')
        row_list = []

        cols = []
        rows = kwargs.pop('rows')


        for row in range(rows):
            for col in range(len(text_list)):
                tempLabel = Label(parent, text = text_list[col], *args, **kwargs)
                tempLabel.grid(row=row, column=col)
                cols.append(tempLabel)

            row_list.append(cols)
        return row_list

目标

我希望能够做到这样的事情

table.getRow[0][0].setText('new text') #This would change col 1 in row 1 to "new text"

奖金问题

(please tell me if I should make a new question for this)

正如我所说的,我想为Tkinter制作一个"Table Widget",但我也希望在用户点击一行时向表中添加行为,我希望行展开"Downwards""Dropdown Menu"非常相似,但它只会在失去焦点时关闭,此处的目标是添加"Entry or Text boxes"以编辑列。

这里的问题是,Tkinter可以实现吗?

2 个答案:

答案 0 :(得分:1)

  

我发现你必须使用" StringVar()""为了更新标签。

这不是一个真实的陈述。您可以使用config / configure方法更新任何窗口小部件的属性。从您的第一个示例开始,它将如下所示:

myLabel = Label(root, text='myText')
myLabel.pack()
myLabel.configure(text='new text')

而且,在你的最后一个例子中:

table.getRow[0][0].configure(text='new text') 

至于奖金问题,是的,它是可能的。你可以将任何你想要的代码绑定到任何其他小部件,除了键和鼠标按钮上的绑定,你可以绑定关于获得和失去焦点。

答案 1 :(得分:0)

正如Bryan所说,你不需要使用StringVar作为Label .config()选项来更改其文本。但是,它可能更方便,特别是如果您希望能够从Label读取当前文本字符串。 FWIW,您可以通过调用不带参数的init_row方法来读取Tkinter小部件的选项,该方法返回所有当前选项值的字典。但我必须承认,如果你只想检查一个值,那就太麻烦了。

如果你想要使用StringVars,你不需要保留一个单独的列表或它们的字典:你可以将StringVar作为属性附加到Label对象。请注意,不要破坏Label的任何现有属性。 :)

我已经修改过你的代码了。虽然你的cols列表中的row_list方法确实存在一些小错误,但它还是相当不错的。您的代码只是在该列表中添加条目,然后将其复制到cols。因此,一个row_list列表最终会包含每一行中的每个标签,而cols最终会对该from tkinter import * 列表进行多次引用。

我需要提一件事:请避免做"明星"进口。当你这样做

row_settings

它将135个Tkinter名称放入您的命名空间;在Python 2中,你得到175个名字。这会在命名空间中造成不必要的混乱,并且可能导致名称冲突:如果您不小心使用导入神秘错误的导入名称之一命名其中一个变量。当你用多个模块进行星级导入时会更糟糕,因为他们可以互相攻击对方。名。此外,星型导入使代码更难以阅读,因为您必须记住在本地定义的名称和导入的名称。

我在代码中更改了其他一些内容。

您使用kwargs更新dict.update的方式很好,但使用生成器表达式和__getitem__方法更加紧凑,效率更高。< / p>

我明确地传递了列数,而不是从文本列表的长度计算它。并且我将列数和行数保存为类的实例属性,因为它们可能会派上用场。

我已经为您的班级添加了set_text方法,以便更轻松地访问标签行。

我为每个Label添加了一个ETable方法,以便更改其文本。语法与问题中的语法不同,但我认为您会喜欢它。 :)

我添加了一些代码来创建一个主要的Tkinter窗口来测试你的set_text类并调用config方法;我还在该窗口中放置了一个Button.Button回调首先打印出Label的""" Description: A TABLE WIDGET Extension for Tkinter Written by Estrobeda, with modifications by PM 2Ring 2016.05.30 """ from __future__ import print_function try: # Python2 import Tkinter as tk except ImportError: # Python3 import tkinter as tk class ETable(tk.Frame): def __init__(self, parent, *args, **kwargs): tk.Frame.__init__(self, parent) self.init_table(parent, *args, **kwargs) def init_table(self, parent, *args, **kwargs): row_settings = { 'anchor': 'center', 'background': '#C5FFFF', 'bitmap': None, 'borderwidth': 5, 'cols': 1, 'compound': None, 'cursor': None, 'font': None, 'foreground': '#000000', 'image': None, 'relief': 'flat', 'rows': 1, 'state': 'normal', 'texts': None, 'textvariable': None, 'underline': -1, 'width': 20, } # Update row_settings with valid entries in kwargs row_settings.update((k, v) for k, v in kwargs.items() if k in row_settings) self.rows = row_settings.pop('rows') self.cols = row_settings.pop('cols') self.table_rows = self.init_rows(parent, *args, **row_settings) def init_rows(self, parent, *args, **kwargs): texts = iter(kwargs.pop('texts')) row_list = [] for row in range(self.rows): col_list = [] for col in range(self.cols): tempLabel = tk.Label(parent, text=next(texts), *args, **kwargs) #Bind a function to the label to change its text tempLabel.set_text = lambda s, w=tempLabel: w.config(text=s) tempLabel.grid(row=row, column=col) col_list.append(tempLabel) row_list.append(col_list) return row_list def __getitem__(self, row): return self.table_rows[row] # Test root = tk.Tk() root.title("LabelTable Demo") texts = list('abcdefghijkl') table = ETable(root, rows=3, cols=4, texts=texts, relief='ridge', width=10) # Change the text of a label table[0][1].set_text('new text') def change_text(): widget = table[2][3] # Display the widget's current configuration cfg = widget.config() for k in sorted(cfg): print(k, '=', cfg[k]) # Change the text widget.set_text('hello') b = tk.Button(root, text='Change', command=change_text) b.grid(row=4, column=0) root.mainloop() 字典,然后更新其文本。

为了将来参考,发布MCVE是一个好主意,特别是对于Tkinter问题,以便想要回答的人可以运行和测试您的代码,而无需先写一堆东西

此代码已在Python 2.6.6和Python 3.6.0a0上进行了测试。

ALTER TABLE