【问题标题】:How to overwrite data in text file in tkinter如何在 tkinter 中覆盖文本文件中的数据
【发布时间】:2017-09-14 09:26:11
【问题描述】:

我正在使用 tkinter 创建一个程序,该程序带有存储在文本文件中的默认名称和密码。登录后,您需要打开Toplevel 窗口并输入您要在后续登录中使用的名称和密码。我已经定义了我的变量,但是如果我想覆盖文本文件,我会收到以下内容:

错误“NameError: name 'e1' is not defined”

我知道我已经定义了。

import sys
from tkinter import messagebox
from tkinter import *


now = open("pass.txt","w+")
now.write("user\n")
now.write("python3")
now.close()


def login_in():
    with open("pass.txt") as f:
        new = f.readlines()
        name = new[0].rstrip()
        password = new[1].rstrip()
    if entry1.get() == name and entry2.get() == password:
        root.deiconify()
        log.destroy()
    else:
        messagebox.showerror("error","login Failed")


def change_login():
    ch = Toplevel(root)
    ch.geometry('300x300')
    e1 = Entry(ch, width=20).pack()
    e2 = Entry(ch, width=20).pack()
    sb = Button(ch, text="save", command=save_changes).pack()

def save_changes():  # function to change data in the txt file
    data = e1.get() + "\n " + e2.get()
    with open("pass.txt", "w") as f:
        f.writelines(data)


root= Tk()
log = Toplevel()


root.geometry("350x350")
log.geometry("200x200")

entry1 = Entry(log)
entry2 = Entry(log)
button1 = Button(log, text="Login", command=login_in) #Login button

entry1.pack()
entry2.pack()
button1.pack()

label = Label(root, text="welcome").pack()
butt = Button(root, text="change data in file", command=change_login).pack()

root.withdraw()
root.mainloop()      

【问题讨论】:

  • e1change_login() 的本地变量,但是您在 save_changes() 中调用它,但它不存在。所以它抛出这个错误是为了告诉你该变量在那个本地空间中不存在。

标签: python tkinter tkinter-entry toplevel


【解决方案1】:

因此,您在这里有几个选择,但总的来说您有 2 个主要问题。

第一个问题是在创建e1e2 输入字段后使用.pack()。这是get() 方法的问题,因为如果您以这种方式打包,几何管理器将返回None。正确的方法是先用e1 = Entry(ch, width=20) 创建小部件,然后用e1.pack() 将其打包到下一行,这样get() 就可以在e1 上工作。

第二个问题是局部变量与全局变量的问题。您已经在函数 change_login() 内部创建了 e1e2 并且没有告诉 python e1e2 是全局变量,它会自动假定您希望它们作为局部变量。这意味着变量只能从创建它们的函数中访问。

你有几个选择,我会为你分解它们。

1) 快速而肮脏的选择是将e1e2 分配为全局变量。这可以通过使用global var_name, var2_name, and_so_on 来完成,因此在这种情况下,将此行添加到change_login():save_changes() 函数的顶部:

global e1, e2

这很好地告诉python将e1e2添加到全局命名空间,它将允许save_changes()使用全局命名空间中的变量。

2) 另一种方法是使用按钮命令将 2 个变量传递给save_changes()。为此,我们需要使用lambda,我们可以通过添加:

command = lambda e1=e1, e2=e2: save_changes(e1, e2)

添加到在change_login() 中创建的按钮并将两个参数添加到save_changes(),如下所示:

save_changes(e1, e2)

这与第一个选项一样有效,并且还避免了使用全局变量。

3) 第三种选择是将整个程序创建为一个类,并使用类属性来允许变量与类中的所有方法一起使用。

以下是使用第一个选项的代码示例:

import sys
from tkinter import messagebox
from tkinter import *

now = open("pass.txt","w+")
now.write("user\n")
now.write("python3")
now.close()

def login_in():
    with open("pass.txt") as f:
        new = f.readlines()
        name = new[0].rstrip()
        password = new[1].rstrip()
    if entry1.get() == name and entry2.get() == password:
        root.deiconify()
        log.destroy()
    else:
        messagebox.showerror("error","login Failed")

def change_login():
    global e1, e2
    ch = Toplevel(root)
    ch.geometry('300x300')
    e1 = Entry(ch, width=20)
    e1.pack()
    e2 = Entry(ch, width=20)
    e2.pack()
    sb = Button(ch, text="save", command=save_changes).pack()

def save_changes():  # function to change data in the txt file
    global e1, e2
    data = e1.get() + "\n" + e2.get() # removed space after \n
    with open("pass.txt", "w") as f:
        f.writelines(data)

root= Tk()
log = Toplevel()
root.geometry("350x350")
log.geometry("200x200")

entry1 = Entry(log)
entry2 = Entry(log)
button1 = Button(log, text="Login", command=login_in) #Login button

entry1.pack()
entry2.pack()
button1.pack()

label = Label(root, text="welcome").pack()
butt = Button(root, text="change data in file", command=change_login).pack()

root.withdraw()
root.mainloop()

下面是使用第二个选项的代码示例:

import sys
from tkinter import messagebox
from tkinter import *

now = open("pass.txt","w+")
now.write("user\n")
now.write("python3")
now.close()

def login_in():
    with open("pass.txt") as f:
        new = f.readlines()
        name = new[0].rstrip()
        password = new[1].rstrip()
    if entry1.get() == name and entry2.get() == password:
        root.deiconify()
        log.destroy()
    else:
        messagebox.showerror("error","login Failed")

def change_login():
    ch = Toplevel(root)
    ch.geometry('300x300')
    e1 = Entry(ch, width=20)
    e1.pack()
    e2 = Entry(ch, width=20)
    e2.pack()
    Button(ch, text="save", command=lambda e1=e1, e2=e2: save_changes(e1, e2)).pack()

def save_changes(e1, e2):  # function to change data in the txt file
    data = e1.get() + "\n" + e2.get() # removed space after \n
    with open("pass.txt", "w") as f:
        f.writelines(data)

root= Tk()
log = Toplevel()
root.geometry("350x350")
log.geometry("200x200")

entry1 = Entry(log)
entry2 = Entry(log)
button1 = Button(log, text="Login", command=login_in) #Login button

entry1.pack()
entry2.pack()
button1.pack()

label = Label(root, text="welcome").pack()
butt = Button(root, text="change data in file", command=change_login).pack()

root.withdraw()
root.mainloop()

以下是您的代码转换为类并使用类属性避免使用全局变量的示例。

import sys
from tkinter import messagebox
from tkinter import *


class MyApp(Frame):

    def __init__(self, master, *args, **kwargs):
        Frame.__init__(self, master, *args, **kwargs)

        self.master = master
        self.master.withdraw()

        self.log = Toplevel()
        self.master.geometry("350x350")
        self.log.geometry("200x200")

        self.entry1 = Entry(self.log)
        self.entry2 = Entry(self.log)
        self.button1 = Button(self.log, text="Login", command=self.login_in)

        self.entry1.pack()
        self.entry2.pack()
        self.button1.pack()

        Label(root, text="welcome").pack()
        Button(root, text="change data in file", command=self.change_login).pack()

    def login_in(self):
        with open("pass.txt") as f:
            new = f.readlines()
            name = new[0].rstrip()
            password = new[1].rstrip()
        if self.entry1.get() == name and self.entry2.get() == password:
            self.master.deiconify()
            self.log.destroy()
        else:
            messagebox.showerror("error","login Failed")

    def change_login(self):
        ch = Toplevel(self.master)
        ch.geometry('300x300')
        self.e1 = Entry(ch, width=20)
        self.e1.pack()
        self.e2 = Entry(ch, width=20)
        self.e2.pack()
        Button(ch, text="save", command=self.save_changes).pack()

    def save_changes(self):
        data = "{}\n{}".format(self.e1.get(), self.e2.get())
        with open("pass.txt", "w") as f:
            f.writelines(data)


if __name__ == "__main__":
    now = open("pass.txt","w+")
    now.write("user\n")
    now.write("python3")
    now.close()

    root = Tk()
    app = MyApp(root)
    root.mainloop()

【讨论】:

  • 感谢@Sierra Mountain Tech 的更正,当@Ethan Field 指出时我意识到我的变量不是全局的,所以我一直在解决它,直到你发布你的答案。一切正常。再次感谢。
  • 这是一个问题,但您也遇到了 pack() 的问题,即使您将 e11 and e2` 设置为全局变量,它也会导致您的程序失败。那就是快乐的编码!
  • 输入字段的新数据确实会覆盖旧数据,但是当我再次运行程序并在登录阶段输入新数据时,我无法登录,直到我使用文件中的旧数据:"用户”和“python3”。如何让它只接受在登录阶段输入到文本文件中的新数据,并忽略我在创建文件时写入文件的初始数据。
  • 您需要删除代码中的 now = open("pass.txt", "w+")、now.write()` 和 now.close() 部分。这将在每次程序开始时运行。
  • 是的,它在声明全局变量后无法正常工作,直到我应用了你的 pack() 的使用方式。非常感谢 @Mountain Tech
猜你喜欢
  • 2013-07-10
  • 2017-12-11
  • 1970-01-01
  • 2017-09-14
  • 1970-01-01
  • 1970-01-01
  • 2011-06-29
  • 2017-12-04
  • 2015-09-20
相关资源
最近更新 更多