如何处理 Tkinter 中的标签覆盖



我是Python和tkinter的新手,我正在尝试使用它创建一个GUI。我正在尝试根据第一个组合框的选择创建新的标签和组合框。我已经完成了第一个可选组合框的创建,并根据第一个组合框中选择的选项绑定了新标签和组合框的创建。

但是,由于不同的选择会创建不同数量的标签和组合框,并且其中一些位于框架的相同位置,因此标签和组合框可能会覆盖其他标签和组合框,从而导致用户阅读混乱。主要问题在于"def createSystem(self,event("函数,因为这里使用了两个for循环,我不知道如何在程序满足第二个"if条件"时创建新标签/组合框之前清除第一个"if条件"创建的旧标签/组合框。

到目前为止,我尝试了两种解决方案,但都没有成功。

  1. 尝试创建一个全局列表,并将私有函数中创建的所有标签推送到其中,以便我可以使用 label.destory(( 清除所有标签并创建新标签。但是,这样做的问题是我不知道如何将正在创建的标签添加到列表中以及如何在第二个 for 循环开始创建新标签之前删除。

  2. 我想过直接修改特定行处现有标签的文本,但由于标签是使用函数'ttk创建的。Label((' 直接没有分配给任何变量,所以我无法解决它们并对它们进行一些修改。如果我想将它们分配给不同的变量,我需要在 for 循环中同时创建变量,我用谷歌搜索据说这是一件坏事,尽管它在 Python 中是可行的。

import tkinter as tk
from tkinter import ttk

cc_category = {'zxcv': ["vzxcv"], 'qeqL': ["safx"]}
ab_type = ["sfda", "fsdf"]
bbbbList = {
'sddd':["1","2","3","4"],
'ssss sdddd':["1", "2", "3", "4", "5", "6", "2500", "4500"], 
'assss sssaz':["BA", "BB", "BC", "BD", "BE", "BF", "BWD", "BWA"], 
'asdf Cfsdfsddf':["1"], 
'asdf fasdfs' :["1"], 
'asdf zxxxxxx':["1"], 
'cccc xxxxxxx':["1"], 
'cccc saddddL':["1","2","4","42","2"], 
'zxxx xvzzzzL':["1","2","3"], 
'cvcv cccxxxc':["2","2","EPDM","3","3","4","4","82","122","333"], 
}
aaaaLabelList = {'wwww':[], 
'qqqq':[], 
'hjfgjhk':[], 
'xzvxzcvx':[],
'qweaddddz':[], 
'qweasd':[],
'utyiuiufturt':[],
'zxcvxzbvc':[],
'fdass':[],
'ffdasdd':[], 
'fsdfaL':[],
'fdasfzxAL':[],
'fdsafdL':[],
'Dasdfszxd':[], 
'dasfsdfsadE':[],
'FIRE SAFE':[], 
'rrrr':[], 
'eeee':[]}
framelist = []
frames = 1
labellist = [20]
class Root (tk.Tk):
def __init__(self):
super(Root, self).__init__()
self.title("sssssss")
self.minsize(640, 400)
self.InitUI()

def getUpdateData(self, event):
self.cb['values'] = cc_category[self.ValveTypeCombo.get()]

def add_frame(self):
global frames
framelist.append(tk.Frame(root))
framelist[-1].grid()
frames += 1
def delete_frame(self):
global frames
framelist.remove(tk.Frame(root))
framelist[-1].detory()
frames -= 1
def createSystem(self, event):
if self.labelCombo.get() == "zxcv":
for labelname in bbbbList:   
ttk.Label(self, text = labelname + ":     ").grid(column = 0, row = list(bbbbList).index(labelname) + 2) 
ttk.Combobox(self, width = 10, state = 'readonly', values = bbbbList.get(labelname)).grid(column = 1, row = list(bbbbList).index(labelname) + 2)


if self.labelCombo.get() == "qeqL":
for labelname in aaaaLabelList:   
ttk.Label(self, text = labelname + ":     ").grid(column = 0, row = list(aaaaLabelList).index(labelname) + 2) 
ttk.Combobox(self, width = 10, state = 'readonly', values = aaaaLabelList.get(labelname)).grid(column = 1, row = list(aaaaLabelList).index(labelname) + 2)

def InitUI(self):
self.label_1 = ttk.Label(self,text = "asss dddd:    ")
self.label_1.grid(column = 0, row = 0)

self.labelCombo = ttk.Combobox(self, width = 5, state = 'readonly', values = list(cc_category.keys()))
self.labelCombo.bind('<<ComboboxSelected>>', self.createSystem)
self.labelCombo.grid(column = 1, row = 0)


if __name__== '__main__':
root = Root()
root.mainloop()

下面是我编写的代码,用于将在 for 循环中创建的标签传递到全局列表。但它有一个编译错误:

line 77, in createSystem
labellist[i].grid(column = 0, row = list(bbbbList).index(labelname) + 2)
AttributeError: 'int' object has no attribute 'grid' 

我不知道如何处理它。

以下是我第一个想法的完整代码,但不起作用:

import tkinter as tk
from tkinter import ttk

cc_category = {'zxcv': ["vzxcv"], 'qeqL': ["safx"]}
ab_type = ["sfda", "fsdf"]
bbbbList = {
'sddd':["1","2","3","4"],
'ssss sdddd':["1", "2", "3", "4", "5", "6", "2500", "4500"], 
'assss sssaz':["BA", "BB", "BC", "BD", "BE", "BF", "BWD", "BWA"], 
'asdf Cfsdfsddf':["1"], 
'asdf fasdfs' :["1"], 
'asdf zxxxxxx':["1"], 
'cccc xxxxxxx':["1"], 
'cccc saddddL':["1","2","4","42","2"], 
'zxxx xvzzzzL':["1","2","3"], 
'cvcv cccxxxc':["2","2","EPDM","3","3","4","4","82","122","333"], 
}
aaaaLabelList = {'wwww':[], 
'qqqq':[], 
'hjfgjhk':[], 
'xzvxzcvx':[],
'qweaddddz':[], 
'qweasd':[],
'utyiuiufturt':[],
'zxcvxzbvc':[],
'fdass':[],
'ffdasdd':[], 
'fsdfaL':[],
'fdasfzxAL':[],
'fdsafdL':[],
'Dasdfszxd':[], 
'dasfsdfsadE':[],
'FIRE SAFE':[], 
'rrrr':[], 
'eeee':[]}
framelist = []
frames = 1
labellist = [20]
class Root (tk.Tk):
def __init__(self):
super(Root, self).__init__()
self.title("sssssss")
self.minsize(640, 400)
self.InitUI()

def getUpdateData(self, event):
self.cb['values'] = cc_category[self.ValveTypeCombo.get()]

def add_frame(self):
global frames
framelist.append(tk.Frame(root))
framelist[-1].grid()
frames += 1
def delete_frame(self):
global frames
framelist.remove(tk.Frame(root))
framelist[-1].detory()
frames -= 1
def createSystem(self, event):
if self.labelCombo.get() == "zxcv":
for i, labelname in zip(range(20),bbbbList):
root.add_frame()
labellist.append(tk.Frame(root))
ttk.Label(framelist[i], text = labelname + ":     ")
labellist[i].grid(column = 0, row = list(bbbbList).index(labelname) + 2) 
ttk.Combobox(self, width = 10, state = 'readonly', values = bbbbList.get(labelname)).grid(column = 1, row = list(bbbbList).index(labelname) + 2)
i += 1

if self.labelCombo.get() == "qeqL":
for labelname in aaaaLabelList:   
ttk.Label(self, text = labelname + ":     ").grid(column = 0, row = list(aaaaLabelList).index(labelname) + 2) 
ttk.Combobox(self, width = 10, state = 'readonly', values = aaaaLabelList.get(labelname)).grid(column = 1, row = list(aaaaLabelList).index(labelname) + 2)

def InitUI(self):
self.label_1 = ttk.Label(self,text = "asss dddd:    ")
self.label_1.grid(column = 0, row = 0)

self.labelCombo = ttk.Combobox(self, width = 5, state = 'readonly', values = list(cc_category.keys()))
self.labelCombo.bind('<<ComboboxSelected>>', self.createSystem)
self.labelCombo.grid(column = 1, row = 0)


if __name__== '__main__':
root = Root()
root.mainloop()

我希望看到标签和组合框在同时切换第一个组合框中选择的值时不会相互重叠,从而能够访问所有新创建的组合框中选择的值以供进一步使用。例如,我可以创建一个提交按钮来提交在选择第一个组合框后创建的组合框中选择的所有值。

编辑

我已经编辑了createSystem函数,现在可以编译它,但问题是似乎一直在向"框架列表[]"添加标签,我试图在for循环中添加"framelist[i].destroy((以破坏当前标签,但它返回

AttributeError: '_tkinter.tkapp' object has no attribute 'framelist'

以下是新的"createSystem"函数的代码:

def createSystem(self, event):
if self.labelCombo.get() == "zxcv":
for i, labelname in zip(range(len(bbbbList)),bbbbList):
root.add_frame()
#labellist.append(tk.Frame(root))
ttk.Label(framelist[i], text = labelname).grid()
ttk.Combobox(self, width = 10, state = 'readonly', values = bbbbList.get(labelname)).grid(column = 1, row = i + 1)

if self.labelCombo.get() == "qeqL":
for i, labelname in zip(range(len(aaaaLabelList)),aaaaLabelList):  
ttk.Label(self, text = labelname + ":     ").grid(column = 0, row = list(aaaaLabelList).index(labelname) + 2) 
ttk.Combobox(self, width = 10, state = 'readonly', values = aaaaLabelList.get(labelname)).grid(column = 1, row = list(aaaaLabelList).index(labelname) + 2)

最好先在InitUI(...)的单个帧内创建label+combo列表(aaaaListbbbbLabelList(,然后在createSystem(...)中的帧之间切换。

以下是修改后的InitUI()createSystem()

def createSystem(self, event):
# get the frame based on selection of labelCombo
frame = self.frames[self.labelCombo.get()]
# show the frame
frame.grid(row=1, column=0, columnspan=2, sticky='nsew')
frame.tkraise()
def InitUI(self):
self.label_1 = ttk.Label(self,text = "asss dddd:    ")
self.label_1.grid(column = 0, row = 0)
self.labelCombo = ttk.Combobox(self, width = 5, state = 'readonly', values = list(cc_category.keys()))
self.labelCombo.bind('<<ComboboxSelected>>', self.createSystem)
self.labelCombo.grid(column = 1, row = 0)
self.frames = {} # hold the frames containing the label+combo list
self.comboboxes = {} # hold the comboboxes in the frames
for category in cc_category.keys():
frame = tk.Frame(self)
selectedList = bbbbList if category == "zxcv" else aaaaLabelList
for row, labelname in enumerate(selectedList):
ttk.Label(frame, text=labelname+":     ").grid(column=0, row=row) 
combobox = ttk.Combobox(frame, width=10, state='readonly', values=selectedList.get(labelname))
combobox.grid(column=1, row=row)
self.comboboxes[labelname] = combobox
self.frames[category] = frame

主要问题是您在创建新小部件之前没有销毁以前的小部件(因此重叠(。我已经让你的代码满足了你的需要(希望如此(。 希望这会有所帮助

def delete_frames(self):
# By using [2:] we are sparing the first combobox
# Though I recommend creating these comboboxes in seperate frame
if self.winfo_children()[2:] != []:
for widget in self.winfo_children()[2:]:
widget.destroy()
# Fully Removing by calling destroy can also use hide
def createSystem(self, event):
self.delete_frames()
to_use = bbbbList if self.labelCombo.get() == "zxcv" else aaaaLabelList
global framelist
i = 1
for item in to_use.items():
tk.Label(self, text=item[0]).grid(column=0, row=i)
ttk.Combobox(self, width=10, state='readonly',
values=item[1]).grid(column=1, row=i)
i += 1

最新更新