描述
我想为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可以实现吗?
答案 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