【问题标题】:Store entry values from previous Tkinter session in a loop在循环中存储来自先前 Tkinter 会话的条目值
【发布时间】:2024-01-24 10:19:02
【问题描述】:

我正在尝试创建一个 Tkinter GUI,它将所有输入框值保存到一个文本文件中,然后从该文本文件中读回数据并在下一个会话开始时默认显示它们。假设我有一个包含以下数据的文本文件:

one
two
three

使用以下代码:

#!usr/bin/env python
from Tkinter import *

class Tracker(Tk):
    def __init__(self, var1, var2, var3):
        Tk.__init__(self)

        # Create label
        app_label = Label(self, text="Enter value")
        app_label.pack()

        self.entry1 = StringVar()
        self.entry1.set(var1)
        ent1 = Entry(self,textvariable=self.entry1)
        ent1.pack()
        self.entry2 = StringVar()
        self.entry2.set(var2)
        ent2 = Entry(self,textvariable=self.entry2)
        ent2.pack()
        self.entry3 = StringVar()
        self.entry3.set(var3)
        ent3 = Entry(self,textvariable=self.entry3)
        ent3.pack()

        # Track 'delete window' event
        self.protocol("WM_DELETE_WINDOW", self.handler)

    def handler(self):
        f = open("backup.txt", "w")
        f.write(self.entry1.get()+'\n'+self.entry2.get()+'\n'+self.entry3.get())
        f.close()
        self.destroy()

if __name__ == "__main__":

    t = open("backup.txt")
    var = t.readlines()
    Text1 = var[0]
    Text2 = var[1]
    Text3 = var[2]

    # Initialize GUI
    app = Tracker(Text1, Text2, Text3)  
    app.mainloop()

我得到以下框:

我的代码应该从文本文件中读取数据并显示带有文本文件中预定义值的输入框。但它的表现很有趣。它没有正确保存数据

  1. 我希望这个 GUI 能够正常工作,以便当我在上面显示的输入框中编辑数据时,它会被保存(在关闭会话时)并在我下次运行时自动显示。

  2. 有没有办法在循环中执行此操作,这样我就可以显示任意数量的输入框,而无需对输入小部件进行硬编码?

【问题讨论】:

    标签: python tkinter tkinter-entry


    【解决方案1】:

    您可以轻松地循环创建小部件。严格来说,您不需要为每个小部件创建 StringVars,除非您真的想要,因为您可以使用每个小部件对象上的方法获取和设置小部件值。

    例如:

    import Tkinter as tk
    
    class SampleApp(tk.Tk):
        def __init__(self, *args, **kwargs):
            tk.Tk.__init__(self, *args, **kwargs)
            button = tk.Button(text="Save", command=self.save)
            button.pack(side="top")
            self.widgets = []
            for line in ["one","two","three","four"]:
                widget = tk.Entry(self)
                widget.insert(0, line)
                widget.pack(side="top", fill="x")
                self.widgets.append(widget)
    
        def save(self):
            for widget in self.widgets:
                print widget.get()
    
    if __name__ == "__main__":
        app = SampleApp()
        app.mainloop()
    

    【讨论】:

    • 非常感谢。 StringVar() 声明的好处/用途是什么?我的印象是告诉 Tkinter 每次都更新给定的小部件是很重要的。
    • @prrao:您可以将跟踪添加到变量。这使得每当用户更改某些内容时调用函数变得容易。它还可以通过简单地设置关联小部件的值来轻松更新小部件。它不是必需的,但在许多情况下都很有用。
    【解决方案2】:

    将每个命令添加到列表中。为此,您可能需要将事件处理程序绑定到您的 Entry 小部件。

    无论如何,至于在启动时做事,在你的构造函数结束时,你可以做这样的事情(使用 Python 3.4 语法,因为这是我熟悉的)。

    from tkinter import *;
    …
    def __init__(self, etc.)
        self.commands=[];
        try:
            log=self.load_log();
            self.myTextWidget.replace("1.0", END, "\n".join(log)); #join here turns it into a string with list items separated by new lines.
        except IOError:
            self.save_log();
    def load_log(self):
        #load and return the log file
    def save_log(self):
        #save the log file; I recommend just pickling the list. Note: to save it, you'll want to load the list from the file and extend it with self.commands, and then save it again.
    def on_entry(self, event):
        self.commands.append(the_entry.get());
    

    关闭程序时调用 save_log。

    如果我是你,我会在你每次输入命令时保存日志,而不是在你关闭程序时保存日志(因为即使程序关闭不当也会起作用),但也许它会是一个您的情况下的性能问题。

    【讨论】: