Я новичок в Tkinter. Попытка записать пользовательские входные данные из моего множественного графического интерфейса tkinter в файл Excel, используя приведенное ниже, все же последнее значение переопределяется. Я не могу сохранить предыдущие входные значения от пользователя в Excel. Запрос вашей помощи здесь. Я использовал numofvm() для создания количества окон tkinter, соответственно, GUI будет создан, а затем после того, как пользователь введет значения через GUI.
from tkinter import *
import xlwt
# designing window for vmdetails
def Vmdetails():
global vmdetails_screen
for i in range(1,N+1):
t=i
numb=str(t)
vmdetails_screen = Toplevel(numofvm_screen)
vmdetails_screen.title("VM_Details_"+ numb)
vmdetails_screen.geometry("400x950")
global cluster_name
global vm_template
global clustername_entry
# Set text variables
cluster_name = StringVar()
vm_template = StringVar()
# Set label for user instruction
Label(vmdetails_screen, text="Please enter details below", bg="blue").pack()
Label(vmdetails_screen, text="").pack()
Cluster_Name_lable = Label(vmdetails_screen, text="Cluster_Name "+ numb +"* ")
Cluster_Name_lable.pack()
# Set textvariables entry
clustername_entry = Entry(vmdetails_screen, textvariable=cluster_name)
clustername_entry.pack()
Button(vmdetails_screen, text="Submit", width=10, height=1, command=check).pack()
def check():
# Retrieve the value from the entry and store it to a variable
global var
if cluster_name.get() == '':
invalid_value()
else:
write_to_xls()
def invalid_value():
global invalid_value_screen
invalid_value_screen = Toplevel(vmdetails_screen)
invalid_value_screen.title("Invalid Entry")
invalid_value_screen.geometry("250x100")
Label(invalid_value_screen, text="Enter valid values for all the required fields").pack()
Button(invalid_value_screen, text="OK", command=delete_invalid_value).pack()
def delete_invalid_value():
invalid_value_screen.destroy()
# designing window to provide the number of vm to be created
def numofvm():
global numofvm_screen
numofvm_screen = Toplevel(main_screen)
numofvm_screen.title("VM_NUM")
numofvm_screen.geometry("300x250")
global vmnumber
global vmnumber_entry
vmnumber = StringVar()
Label(numofvm_screen, text="Please enter the Number of VM you wishes to create ", bg="blue").pack()
Label(numofvm_screen, text="").pack()
vmnumber_lable = Label(numofvm_screen, text="Number of VM to be created * ")
vmnumber_lable.pack()
vmnumber_entry = Entry(numofvm_screen, textvariable=vmnumber)
vmnumber_entry.pack()
Button(numofvm_screen, text="Submit", width=10, height=1, command=screen_duplicate).pack()
def screen_duplicate():
global N
N = int(vmnumber.get())
if N > 0 :
Vmdetails()
#exporting the user inputs into an excel sheet
def write_to_xls():
# create new workbook
wb = xlwt.Workbook()
for i in range(1,N+1):
t=i
numb=str(t)
# add sheet using given name
ws = wb.add_sheet("VM_"+numb+"_DETAILS")
# write text to cell
ws.write(0, 0, "Cluster_Name")
ws.write(1, 0,cluster_name.get())
# save to given file name
wb.save('my_file.xls')
def main_account_screen():
global main_screen
main_screen = Tk()
main_screen.geometry("300x250")
main_screen.title("Welcome")
Label(text="Select Your Choice", bg="blue", width="300", height="2", font=("Calibri", 13)).pack()
Label(text="").pack()
Button(text="Enter", height="2", width="30", command=numofvm).pack()
Label(text="").pack()
main_screen.mainloop()
main_account_screen()
Как я объяснил в комментарии, проблема записи данных заключается в том, что вам нужно хранить StringVar
и связанную информацию в виде list
а не перезаписывать предыдущие значения, используя только переменные с одним значением.
Хотя исправление этого было бы возможно без этого, использование вами стольких глобальных переменных делает код сложным для понимания, отладки и изменения - и все это является причиной того, что общепринятым является то, что следует избегать их в максимально возможной степени.
Вот список тех, которые использует код в вашем вопросе:
cluster_name
, clustername_entry
, vm_template
, vmdetails_screen
, invalid_value_screen
, numofvm_screen
, vmnumber
, vmnumber_entry
, N
, main_screen
Так как это довольно много, я решил также исключить их в приведенном ниже коде, чтобы сделать дизайн "чище", кроме того, чтобы показать, как хранить данные в list
как это было предложено. Надеемся, что это даст вам лучшую основу для дальнейшей разработки вашего приложения.
Чтобы избежать global
s, большинство из них были превращены в атрибуты класса, представляющего все ваше приложение - это дизайн, основанный на этом ответе на tkinter
вопрос tkinter от tkinter guru @Bryan Oakley.
from tkinter import *
import tkinter.messagebox as tkMessageBox
import os
import xlwt
class MyApp(Tk):
LABEL_BG = "light blue"
def __init__(self):
Tk.__init__(self)
self.geometry("300x250")
self.title("Welcome")
Label(text="Select Your Choice", bg=self.LABEL_BG, width="300", height="2",
font=("Calibri", 13)).pack()
Label(text="").pack()
Button(text="Enter", height="2", width="30", command=self.numofvm).pack()
Label(text="").pack()
def numofvm(self):
""" Designing window to provide the number of VMs to be created. """
self.numofvm_screen = Toplevel(self)
self.numofvm_screen.title("VM_NUM")
self.numofvm_screen.geometry("300x250")
self.vmnumber = StringVar()
Label(self.numofvm_screen,
text="Please enter the Number of VMs you wishes to create",
bg=self.LABEL_BG).pack()
Label(self.numofvm_screen, text="").pack()
vmnumber_lable = Label(self.numofvm_screen,
text="Number of VMs to be created:")
vmnumber_lable.pack()
self.vmnumber_entry = Entry(self.numofvm_screen, textvariable=self.vmnumber)
self.vmnumber_entry.pack()
Button(self.numofvm_screen, text="Submit", width=10, height=1,
command=self.screen_duplicate).pack()
self.numofvm_screen.focus_set()
def screen_duplicate(self):
try:
self.N = int(self.vmnumber.get())
except ValueError:
self.N = 0
if self.N > 0:
self.vm_details()
def vm_details(self):
""" Create designing windows for VM details.
"""
# Preallocate and then create VM detail screens and data.
self.cluster_names = [None for _ in range(self.N)]
self.clustername_entries = [None for _ in range(self.N)]
self.vm_templates = [None for _ in range(self.N)]
self.vmdetails_screen = [None for _ in range(self.N)]
for i in range(self.N):
numb = str(i+1)
self.vmdetails_screen[i] = Toplevel()
self.vmdetails_screen[i].title("VM Details " + numb)
self.vmdetails_screen[i].geometry("400x950")
# Set text variables
self.cluster_names[i] = StringVar()
self.vm_templates[i] = StringVar()
# Set label for user instruction
Label(self.vmdetails_screen[i], text="Please enter details below:",
bg=self.LABEL_BG).pack()
Label(self.vmdetails_screen[i], text="").pack()
Cluster_Name_lable = Label(self.vmdetails_screen[i],
text="Cluster Name "+ numb + ":")
Cluster_Name_lable.pack()
# Set textvariables entry
self.clustername_entries[i] = Entry(self.vmdetails_screen[i],
textvariable=self.cluster_names[i])
self.clustername_entries[i].pack()
Button(self.vmdetails_screen[i], text="Submit", width=10, height=1,
command=self.validate).pack()
def validate(self):
""" Check values of ALL cluster name entries and save them to excel
file if they're all valid.
"""
if not all(cluster_name.get() for cluster_name in self.cluster_names):
self.invalid_value()
else:
self.write_to_xls()
tkMessageBox.showinfo("Info", '"%s" file written' % self.xls_filepath)
# Get rid of all data entry screens.
for i in range(self.N):
self.vmdetails_screen[i].destroy()
self.numofvm_screen.destroy()
def invalid_value(self):
""" Display error message screen.
"""
self.invalid_value_screen = Toplevel()
self.invalid_value_screen.title("Invalid Entry")
self.invalid_value_screen.geometry("400x100")
Label(self.invalid_value_screen,
text="Please enter valid values for the fields in ALL\n"
"VM Detail windows before clicking Submit button").pack()
Button(self.invalid_value_screen, text="OK",
command=lambda: self.invalid_value_screen.destroy()).pack()
def write_to_xls(self):
""" Export all user inputs to an excel sheet. """
# Create new workbook.
wb = xlwt.Workbook()
for i in range(self.N):
numb = str(i+1)
# Add sheet using given name.
ws = wb.add_sheet("VM_" + numb + "_DETAILS")
# Write text to cell.
ws.write(0, 0, "Cluster_Name")
ws.write(1, 0, self.cluster_names[i].get())
# Save excel file in same directory as script.
self.xls_filepath = os.path.join(os.path.dirname(__file__), 'my_file.xls')
wb.save(self.xls_filepath)
if __name__ == '__main__':
root = MyApp()
root.mainloop()
for
цикла вVmdetails()
функция делает , а именно: он создает и присваиваетN
другуюStringVar()
с доcluster_name
иvm_template
глобальных переменных, а это означает , что после этого, только последний из них остается. Это влияет на функциюcheck()
которая всегда извлекает значение последнего созданного, а не обязательно того, в которое пользователь, возможно, только что ввел значение. Из-за этой проблемы я не смог получить часть, которая пишет и сохраняет файл.xls
. Во всяком случае, я думаю, что проблема записи файла имеет ту же причину.