遇到问题,我希望能够按GUI上的"编辑"按钮,这将打开一个新的单独窗口,允许我更改值。但是我在让新窗口工作并将其分配给不同的编辑按钮时遇到了一些麻烦。谢谢
#Edit Function
def create_window():
window = tk.Toplevel(root)
root = tk.Tk()
b = tk.Button(root, text="Create new window", command=create_window)
b.pack()
#Tkinter Window
root = Tk()
#Labels
lblTitle = Label(text="Chelsea FC Player Statistics",font=('bold', 15), fg="blue",).grid(row=0, column=1)
#Player Names Labels
lblPlayerNames = Label(text="Player Names",font=('bold')).grid(columnspan=1,row=1, column=1)
lblDKName = Label(text="Daniel Keelagher").grid(columnspan=1,row=2, column=1)
lblJKName = Label(text="Joseph Keelagher").grid(columnspan=1,row=3, column=1)
lblBMName = Label(text="Benjamin Miller").grid(columnspan=1,row=4, column=1)
lblJTName = Label(text="Jordan Terlato").grid(columnspan=1,row=5, column=1)
#Matches Played Labels
lblMatchesPlayed = Label(text="Matches Played",font=('bold')).grid(columnspan=1,row=1, column=2)
lblDKMatches = Label(text="10").grid(columnspan=1,row=2, column=2)
lblJKMatches = Label(text="9").grid(columnspan=1,row=3, column=2)
lblBMMatches = Label(text="9").grid(columnspan=1,row=4, column=2)
lblJTMatches = Label(text="8").grid(columnspan=1,row=5, column=2)
#Goals Labels
lblGoals = Label(text="Goals",font=('bold')).grid(row=1, column=3)
lblDKGoals = Label(text="4").grid(columnspan=1,row=2, column=3)
lblJKGoals = Label(text="2").grid(columnspan=1,row=3, column=3)
lblBMGoals = Label(text="0").grid(columnspan=1,row=4, column=3)
lblJTGoals = Label(text="1").grid(columnspan=1,row=5, column=3)
#Assists Labels
lblAssists = Label(text="Assists",font=('bold')).grid(columnspan=1,row=1, column=4)
lblDKAssists = Label(text="4").grid(columnspan=1,row=2, column=4)
lblJKAssists = Label(text="2").grid(columnspan=1,row=3, column=4)
lblBMAssists = Label(text="0").grid(columnspan=1,row=4, column=4)
lblJTAssists = Label(text="1").grid(columnspan=1,row=5, column=4)
#YellowCards Labels
lblYellowCards = Label(text="YC",font=('bold')).grid(columnspan=1,row=1, column=5)
lblDKYellowCards = Label(text="0").grid(columnspan=1,row=2, column=5)
lblJKYellowCards = Label(text="1").grid(columnspan=1,row=3, column=5)
lblBMYellowCards = Label(text="1").grid(columnspan=1,row=4, column=5)
lblJTYellowCards = Label(text="3").grid(columnspan=1,row=5, column=5)
#RedCards Labels
lblYellowCards = Label(text="RC",font=('bold')).grid(columnspan=1,row=1, column=6)
lblDKRedCards = Label(text="0").grid(columnspan=1,row=2, column=6)
lblJKRedCards = Label(text="0").grid(columnspan=1,row=3, column=6)
lblBMRedCards = Label(text="0").grid(columnspan=1,row=4, column=6)
lblJTRedCards = Label(text="1").grid(columnspan=1,row=5, column=6)
#Buttons
btnDKEdit = Button(root, text="Edit",).grid(columnspan=1,row=2, column=7)
btnJKEdit = Button(root, text="Edit", ).grid(columnspan=1,row=3, column=7)
btnBMEdit = Button(root, text="Edit", ).grid(columnspan=1,row=4,column=7)
btbJTEdit = Button(root, text="Edit",).grid(columnspan=1,row=5, column=7)```
我想我已经回答了这个问题,但无论如何你去(你发布了两次相同的问题?
这是我的解决方案(很长,但我会尽力解释大部分部分(解释如下),但是在这种情况下,不会有新窗口,而且这更像是一个示例,说明如何做到这一点只是为了给你一个想法。
from tkinter import Tk, Button, Frame, Label, StringVar
from tkinter.ttk import Separator
from functools import partial
stored_data = {'Lionel Notmessi': {'Games Played': 340, 'Goals': 102, 'Assists': 223}, 'Firstname Lastname': {'Games Played': 279, 'Goals': 84, 'Assists': 56}}
class MainWindow(Tk):
def __init__(self):
Tk.__init__(self)
self.resizable(False, False)
self.players_frame = Frame(self)
self.players_frame.pack(fill='both', expand=True)
self.data_value_list = []
for index, player in enumerate(list(stored_data)):
player_frame = Frame(self.players_frame)
player_frame.pack(side='left')
Label(player_frame, text=player, height=2, width=30, anchor='n', font='default 11 bold').pack(side='top', pady=10)
var = StringVar()
self.data_value_list.append(var)
Label(player_frame, textvariable=self.data_value_list[index], height=8, width=30).pack(side='top', pady=10)
Button(player_frame, text='Edit', command=partial(self.select, player)).pack(side='bottom', pady=10, fill='x', expand=True)
self.refresh_data()
def select(self, key):
self.players_frame.pack_forget()
player_edit_frame = EditData(self, stored_data, key)
player_edit_frame.pack(fill='both', expand=True)
def refresh_data(self):
for var, player in zip(self.data_value_list, list(stored_data)):
data = ''
for name, value in stored_data[player].items():
data += f'{name}: {value}nn'
var.set(data)
class EditData(Frame):
def __init__(self, parent, data, key):
Frame.__init__(self, parent)
self.parent = parent
self.data = data
self.key = key
self.total_width = len(list(data[key].keys()))
name = Label(self, text=key, anchor='n', height=3)
name.grid(row=0, column=0, columnspan=self.total_width, sticky='nsew', pady=10)
self.value_list = []
index = 0
for key, value in data[self.key].items():
item_frame = Frame(self)
item_frame.grid(row=1, column=index, sticky='nsew', padx=5)
for i in range(3):
item_frame.columnconfigure(i, minsize=50)
var = StringVar()
var.set(value)
self.value_list.append(var)
Label(item_frame, text=key).grid(row=0, column=0, columnspan=3, sticky='nsew')
minus = Button(item_frame, text='-', command=partial(self.change, self.value_list[index], '-', key))
minus.grid(row=1, column=0, sticky='nsew')
value_label = Label(item_frame, textvariable=self.value_list[index])
value_label.grid(row=1, column=1, sticky='nsew')
plus = Button(item_frame, text='+', command=partial(self.change, self.value_list[index], '+', key))
plus.grid(row=1, column=2, sticky='nsew')
index += 1
Separator(self, orient='horizontal').grid(row=2, column=0, columnspan=self.total_width, sticky='nsew', pady=5)
Button(self, text='Done', command=self.done).grid(row=3, column=0, columnspan=self.total_width, sticky='nsew')
def change(self, var, operator, key):
current = var.get()
if operator == '-':
total = int(current) - 1
var.set(str(total))
self.data[self.key][key] = total
if operator == '+':
total = int(current) + 1
var.set(str(total))
self.data[self.key][key] = total
def done(self):
self.parent.refresh_data()
self.parent.players_frame.pack(expand=True, fill='both')
self.destroy()
root = MainWindow()
root.mainloop()
因此,第一件事是导入将使用的所有必要模块。
接下来,我将变量stored_data
到字典中,该字典将是存储有关玩家的所有数据的主要数据存储位置。
然后我创建了一个名为MainWindow
的类,它继承自 tkinter 的主窗口Tk
这样就可以获得Tk()
功能,例如.mainloop()
方法。
在MainWindow
构造函数方法(启动时将调用什么)中,首先我将窗口设置为 x 和 y 方向上不可调整大小,以免导致小部件不可见的问题。
然后,我创建了一个框架来组织所有播放器内容的显示位置,并创建了另一个用于存储 StringVar 值的列表,以便轻松更新当前数据标签(启动程序时看到的标签)。
然后,对于字典中的每个键,我创建了一个框架来再次组织显示的小部件。然后在框架中,我打包了所有相关的内容,我输入了玩家姓名,他们的统计数据和编辑按钮(因为我只关注该功能)。还附加了一个 StringVar 来列出每个玩家。这些 StringVar 设置将显示统计信息的标签的值。StringVar 由索引访问。
然后我调用了self.refresh_data()
它基本上将列表中的每个 StringVar 的值设置为相应的字典值。基本上显示统计信息。
然后还有定义的select()
方法(由按钮调用),该方法启动EditData
,然后在从几何管理器中删除self.players_frame
后将其放在屏幕上,使其不再可见,只有编辑帧可见。
EditData
类。启动后,它接受给定的参数并将它们设置为类属性,以便于跨类访问。
然后测量总宽度以计算网格的列跨度,并通过测量由stored_data
键创建的列表的长度来完成,因此基本上长度是玩家的数量。
然后将名称放在屏幕上。
再次创建了另一个用于存储 StringVar 的self.value_list
,索引设置为 0(因为我无法弄清楚如何在 for 循环中实现它(足够简单)(使用enumerate()
))。 并且索引每次迭代都会增加。
然后创建标签和按钮并将其网格化到从 Frame 继承的类内部的item_frame
,因此基本上该类是一个较大的 Frame,程序在其中创建较小的框架用于数据更改和布局组织目的。然后在item_frame
内,每列都设置为 minsize=50,以便它们的大小相同,因为无论如何都没有数据占用那么多空间。
然后再次设置一个 StringVar 并将其附加到列表中,以便稍后访问它。
整体
name
- data +
创建布局并将按钮设置为方法change()
并给定参数(partial()
将这些函数设置为始终使用相同的给定变量执行,以便可以轻松地在循环中创建按钮)。当调用 change 时,它会获取该数据部分的当前值,然后根据它是"-"还是"+",它会从当前值中添加或减去并将其设置为新值,并更改字典中的值,以便下次显示此帧时,它会显示新数据,以便"首页"上的统计信息显示更新的数据。
还有一个"完成"按钮,当按下该按钮时,它会调用done()
方法,该方法然后调用父方法(这是MainWindow
)方法refresh_data()
以显示新数据,然后打包回之前调用此类时删除的帧,然后自行销毁。
然后我们只是启动MainWindow
:
root = MainWindow()
root.mainloop()
仅此而已。
显然可以进行一些设计改进。
另外,如果要保存数据,以便每次启动时都显示更改的数据 您可以在关闭窗口之前将数据写入文件。
如果您有问题,请问他们。
关于该文件保存:
您可以添加以下内容(MainWindow
类):
self.protocol('WM_DELETE_WINDOW', lambda: self.save(stored_data))
到__init__
方法执行关闭窗口时给出的函数
还要添加这个:
with open('stored_data.json') as file:
stored_data = json.load(file)
在 You 文件的开头,但请确保您的目录中也有该文件,您必须:
import json
然后定义关闭窗口时调用的save()
方法(在MainWindow
类中):
def save(self, data):
with open('stored_data.json', 'w') as file_:
json.dump(data, file_, indent=2)
self.destroy()
以便它将更新的数据写入该文件,并记住在之后销毁窗口,否则它不会关闭。
现在,您可以在运行程序时加载数据,如果进行更改,它们将被保存到文件中,以便在下次运行程序时访问它们。
此外,如果您在屏幕上的空间不足以显示所有玩家,您可以使用滚动条使其可滚动。
再次,如果您有问题,请问他们。