【问题标题】:How to write from multiple Tkinter GUI windows to an Excel file at a time?如何一次从多个 Tkinter GUI 窗口写入 Excel 文件?
【发布时间】:2019-03-05 06:34:32
【问题描述】:

我是 Tkinter 的新手。尝试使用以下内容将用户输入从我的多个 tkinter GUI 写入 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's 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's 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's you wishes to create ", bg="blue").pack()
    Label(numofvm_screen, text="").pack()

    vmnumber_lable = Label(numofvm_screen, text="Number of VM's 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()

【问题讨论】:

  • 我相信问题源于Vmdetails()函数中的for循环:即它创建N并将不同的StringVar()s分配给cluster_namevm_template全局变量,这意味着之后,只剩下最后一个。这影响了check() 函数,该函数始终检索 last 创建的值,不一定是用户可能刚刚输入值的值。由于这个问题,我一直无法获得写入和保存.xls 文件的部分。无论如何,我认为文件写入问题的原因相同。
  • 谢谢,是的,我也是这么想的,还有关于如何解决这个问题的线索吗?
  • 是的,您需要将它们分别存储在一些可变大小的容器数据结构中,例如 list,并在创建后仅通过索引引用它们。

标签: python excel tkinter xlwt


【解决方案1】:

正如我在评论中解释的那样,数据写入问题是因为您需要存储StringVars 和相关信息是lists 而不是仅使用单值变量覆盖以前的值。

虽然不这样做也有可能解决这个问题,但您使用如此多的全局变量会使代码难以理解、调试和修改——这都是常识是尽可能避免它们的原因。

这是您问题中的代码使用的列表:

cluster_name, clustername_entry, vm_template, vmdetails_screen, invalid_value_screen, numofvm_screen, vmnumber, vmnumber_entry, N, main_screen

由于数量很多,我决定在下面的代码中也消除它们,以使设计“更简洁”,除了只显示如何按照建议将数据存储在 lists 中。希望这将为您的应用程序的持续开发提供更好的基础。

为了避免globals,它们中的大多数已被转换为代表整个应用程序的类的属性——这是基于this answer 到另一个tkinter 由tkinter 大师@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's 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's 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()

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2018-05-11
  • 2015-02-11
  • 1970-01-01
  • 2014-09-26
  • 1970-01-01
  • 1970-01-01
  • 2017-08-02
  • 1970-01-01
相关资源
最近更新 更多