【问题标题】:Tkinter/class variable/method/widget.get() from another class issue in python 2.7Tkinter/class variable/method/widget.get() from another class issue in python 2.7
【发布时间】:2015-10-18 01:03:54
【问题描述】:

我正在尝试编写一个利用 Tkinter 窗口切换 OOP 类的 python 程序。在起始页面上,有一个输入表单,用户可以在其中填写相关字段。填写表格后点击“to tests”按钮,用户可以在切换框架/窗口后选择测试,输入的用户信息同时保存为.txt文件,因为这个按钮运行了几个Startpage 类中的方法。通过单击测试 1 页面中的是或否按钮接收数据时会出现问题。

此页面在不同的类中运行,但需要 Startpage 类中定义的方法 get_info() 的返回值,以获取输入的用户信息(文件名),以创建第二个 .txt 文件以存储原始数据,存储附加的 ' yes' 或 'no' 字符串取决于在测试 1 的 GUI 窗口中单击的按钮。

但是,由于 Test1 没有从 Startpage 类/窗口接收任何条目数据,因此从未创建此文件,因此无法为第二个 .txt 文件分配文件名(调用包含 widget.get() 函数的 get_info() )。

通过类中的方法正确获取信息,一切正常。然而,当 Test1 要求从 Startpage 接收 widget.get() 变量/方法时,问题就出现了。

抛出的错误如下IndexError:

    Exception in Tkinter callback
    Traceback (most recent call last):
      File "C:\Users\Rylan\Anaconda\lib\lib-tk\Tkinter.py", line 1532, in     __call__
return self.func(*args)
      File "C:/Users/Rylan/Documents/Python/Basel Summerintern files/code to help with question.py", line 280, in update_countyes
directory = "C:\Users\Rylan\Documents\Python\Basel Summerintern files\{}".format(self.get_t_info())
      File "C:/Users/Rylan/Documents/Python/Basel Summerintern files/code to help with        question.py", line 304, in get_t_info
        self.gettheinfo = Startpage(app, self.controller).get_info()
      File "C:/Users/Rylan/Documents/Python/Basel Summerintern files/code to help with question.py", line 170, in get_info
        str(Day) + "_" + str(Month) + "_" +

    IndexError: string index out of range

我对 OOP 编程非常陌生,据我所知,这可能是由以下原因引起的:

  • 未正确引用/调用 Startpage 实例,因此 Test1 未接收到变量,因此调用 get_info() 方法会导致 get_info() 方法中的嵌套 widget.get() 函数/变量没有收到任何内容.

基本上,这个 IndexError 的原因是什么?如何修复它以获取从 Startpage 类中的 get_info() 方法创建/返回的文件名,该方法发送到/由类 Test1 调用?

我已经看到与从不同类调用类变量和方法有关的类似问题,但是没有一个考虑窗口/框架切换 Tkinter 应用程序的情况。

下面是可以运行的简化代码(可能看起来不像)(您可能存在目录路径存在问题,只需将路径更改为可以轻松找到的任何内容以保存 .txt 文件)

import Tkinter as tk
import ttk
import os

LARGE_FONT = ("Verdana", 12)
NORM_FONT = ("Verdana", 10)
SMALL_FONT = ("Verdana", 8)


def center(win):
    """
    centers a tkinter window
    param win: the window to center on the screen
    """
    win.update_idletasks()
    width = win.winfo_width()
    frm_width = win.winfo_rootx() - win.winfo_x()
    win_width = width + 2 * frm_width
    height = win.winfo_height()
    titlebar_height = win.winfo_rooty() - win.winfo_y()
    win_height = height + titlebar_height + frm_width
    x = win.winfo_screenwidth() // 2 - win_width // 2
    y = win.winfo_screenheight() // 2 - win_height // 2
    win.geometry('{}x{}+{}+{}'.format(width, height, x, y))
    win.deiconify()


def popupmsg(msg):
    popup1 = tk.Tk()
    center(popup1)
    popup1.minsize(width=60, height=70)
    popup1.maxsize(width=60, height=70)
    popup1.wm_title("Attention!")
    label = ttk.Label(popup1, text=msg, font=NORM_FONT, anchor="center")
    label.pack(side="top", fill="x", pady=10)
    b1 = ttk.Button(popup1, text="Ok", command=lambda: popup1.destroy())
    b1.pack()
    popup1.mainloop()


class Testapp(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)

        tk.Tk.iconbitmap(self, default="testappicon2.ico")
        tk.Tk.wm_title(self, "Psychoacoustic Tests")

        container = ttk.Frame(self)
        container.pack(side="top", fill="both", expand=True)
        container.grid_columnconfigure(0, weight=1)
        container.grid_rowconfigure(0, weight=1)

        menubar = tk.Menu(container)
        filemenu = tk.Menu(menubar, tearoff=0)
        filemenu.add_separator()
        filemenu.add_command(label="Exit", command=lambda: self.destroy())
        menubar.add_cascade(label="File", menu=filemenu)

        tk.Tk.config(self, menu=menubar)
        self.frames = {}

        for F in (Startpage, TestSelect, Test1):
            frame = F(container, self)
            self.frames[F] = frame
            self.minsize(width=900, height=500)
            frame.grid(row=0, column=0, sticky="nsew")

        self.show_frame(Startpage)

    def show_frame(self, cont):
        frame = self.frames[cont]
        frame.tkraise()


class Startpage(ttk.Frame):

    def __init__(self, parent, controller):
        ttk.Frame.__init__(self, parent)
        self.controller = controller

        self.titlelabel = ttk.Label(self, text="User Information", font = LARGE_FONT)
        self.titlelabel.grid(row=0, column=0, columnspan=4, padx = 10, pady = 10)

        self.firstnamelabel = ttk.Label(self, text="First Name: ", font = NORM_FONT)
        self.firstnamelabel.grid(row=1, column=0, sticky = 'w', padx = 15, pady = 10)

        self.lastnamelabel = ttk.Label(self, text="Last Name: ", font = NORM_FONT)
        self.lastnamelabel.grid(row=2, column=0, sticky = 'w', padx = 15, pady = 10)

        self.firstnameentry = ttk.Entry(self)
        self.firstnameentry.grid(row=1, column=1, padx=5, sticky = 'we', columnspan = 3)
        self.lastnameentry = ttk.Entry(self)
        self.lastnameentry.grid(row=2, column=1, padx=5, sticky = 'we', columnspan = 3)

        self.birthdaylabel = ttk.Label(self, text="Birthday: ", font = NORM_FONT)
        self.birthdaylabel.grid(row=3, column=0, sticky = 'w', padx = 15, pady = 10)

        self.daydropdown = ttk.Combobox(self, justify='center', height=20, width=2,
                                   values = (1,2,3,4,5,6,7,8,9,10,11,12,13,14,
                                             15,16,17,18,19,20,21,22,23,24,25,
                                             26,27,28,29,30,31),
                                   state='readonly')
        self.daydropdown.grid(row=3, column=1, padx = 3, sticky = 'ew')

        self.monthdropdown = ttk.Combobox(self, justify='center', height=12, width=10,
                                     values = ('January','Feburary','March',
                                               'April','May','June','July',
                                               'August','September','October',
                                               'November','December'),
                                     state='readonly')
        self.monthdropdown.grid(row=3, column=2, padx=3, sticky = 'ew')            

        self.yeardropdown = ttk.Combobox(self, justify='center', height=20, width=4,
                                    values = (1980, 1981, 1982, 1983, 1984,
                                              1985, 1986, 1987, 1988, 1989,
                                              1990, 1991, 1992, 1993, 1994,
                                              1995, 1996, 1997, 1998, 1999),
                                    state = 'readonly')
        self.yeardropdown.grid(row=3, column=3, padx = 3, sticky = 'ew')

        self.genderlabel = ttk.Label(self, text="Gender: ", font = NORM_FONT)
        self.genderlabel.grid(row=4, column=0, sticky = 'w', padx = 15, pady = 10)

        self.var = tk.IntVar()

        self.Maleradio = ttk.Radiobutton(self, text='Male', variable=self.var, value = 1)
        self.Maleradio.grid(row=4, column=1, sticky = 'w')

        self.Femaleradio = ttk.Radiobutton(self, text='Female', variable=self.var, value = 2)
        self.Femaleradio.grid(row=5, column=1, sticky = 'w')

        self.emaillabel = ttk.Label(self, text="Email: ", font = NORM_FONT)
        self.emaillabel.grid(row=6, column=0, sticky = 'w', padx = 15, pady = 10)

        self.emailentry = ttk.Entry(self)
        self.emailentry.grid(row=6, column=1, columnspan=3, sticky='ew')

        self.experiencelabel = ttk.Label(self, text="Musical Experience: ", font = NORM_FONT)
        self.experiencelabel.grid(row=7, column=0, sticky = 'w', padx = 15, pady = 10)

        self.expdropdown = ttk.Combobox(self, justify='center', height=3, width=17,
                                   values = ('No experience', 'Some experience',
                                             'Musician level'), state='readonly')
        self.expdropdown.grid(row=7, column=1, columnspan=3, sticky = 'w')

        self.button1 = ttk.Button(self, text="To Tests", command= lambda: self.checkempty())
        self.button1.grid(row=8, column=3)


        def shortcut():
            controller.show_frame(TestSelect)

        buttonshort = ttk.Button(self, text="To Tests shortcut", command= lambda: shortcut())
        buttonshort.grid(row=9, column=3)


    def get_info(self):
        Name = self.firstnameentry.get()
        Surname = self.lastnameentry.get()
        Day = self.daydropdown.get()
        Month = self.monthdropdown.get()
        Year = self.yeardropdown.get()
        foldername = (str(Name[0]) + str(Surname[0]) +
                      str(Day) + "_" + str(Month) + "_" +
                      str(Year))
        return foldername

    def create_directory(self):
        if not os.path.isdir(self.get_info()):
            directory = "C:\Users\Rylan\Documents\Python\Basel Summerintern files\{}".format(self.get_info())
            os.makedirs(directory)
            datafile = "{}_userinfo.txt".format(self.get_info())
            entirefile = os.path.join(directory, datafile)
            myfile = open(entirefile, 'w')
            myfile.write(self.userinfo())
            myfile.close()
            self.controller.show_frame(TestSelect)
        else:
            popupmsg("Folder already exists")

    def userinfo(self):
        Name = self.firstnameentry.get()
        Surname = self.lastnameentry.get()
        Day = self.daydropdown.get()
        Month = self.monthdropdown.get()
        Year = self.yeardropdown.get()
        Email = self.emailentry.get()
        Experience = self.expdropdown.get()
        def genderget():
            Gender = self.var.get()
            if Gender == 1:
                UserGender = "Male"
            elif Gender == 2:
                UserGender = "Female"
            return UserGender
        user_info = ("Participant Name: " + str(Name) + " " +
                     str(Surname) + "\nBirthday: " + str(Day) + "_" +
                     str(Month) + "_" + str(Year) + "\nGender: " +
                     str(genderget()) + "\nEmail: " + str(Email) +
                     "\nMusical Experience: " + str(Experience) +
                     "\nDirectory Name: " + str(self.get_info()))
        return user_info

    def checkempty(self):
        Name = self.firstnameentry.get()
        Surname = self.lastnameentry.get()
        Day = self.daydropdown.get()
        Month = self.monthdropdown.get()
        Year = self.yeardropdown.get()
        Email = self.emailentry.get()
        Experience = self.expdropdown.get()
        if len(Name) == 0:
            popupmsg("Please complete the user information form")
        elif len(Surname) == 0:
            popupmsg("Please complete the user information form")
        elif Day == None:
            popupmsg("Please complete the user information form")
        elif Month == None:
            popupmsg("Please complete the user information form")
        elif Year == None:
            popupmsg("Please complete the user information form")
        elif self.var.get() == 0:
            popupmsg("Please complete the user information form")
        elif len(Email) == 0:
            popupmsg("Please complete the user information form")
        elif Experience == None:
            popupmsg("Please complete the user information form")
        else:
            self.create_directory()


class TestSelect(ttk.Frame):

    def __init__(self, parent, controller):
        ttk.Frame.__init__(self, parent)
        self.controller = controller

        label = ttk.Label(self, text="Select tests", font = LARGE_FONT)
        label.grid(row=0, column=0, columnspan=3)

        Test1Button = ttk.Button(self, text="Do test 1", command=lambda: controller.show_frame(Test1))
        Test1Button.grid(row=1, column=0, padx = 20, pady = 15, sticky = 'nsew')

        button2 = ttk.Button(self, text="Home", command=lambda: controller.show_frame(Startpage))
        button2.grid(row=3, column=2)


class Test1(ttk.Frame):
    def __init__(self, parent, controller):
        ttk.Frame.__init__(self, parent)
        self.controller = controller

        label = ttk.Label(self, text="Test 1", font = LARGE_FONT)
        label.grid(row=0, column=0, columnspan=2)

        button2 = ttk.Button(self, text="Page one", command=lambda: controller.show_frame(TestSelect))
        button2.grid(row=1, column=0, sticky = "w")

        yesbutt1 = ttk.Button(self)
        yesbutt1.grid(row=2, column=0)
        nobutt1 = ttk.Button(self)
        nobutt1.grid(row=2, column=1)
        yesbutt1['text'] = "Yes: 0"
        nobutt1['text'] = "No: 0"
        self.nobttn_clicks = 0
        self.yesbttn_clicks = 0

        def update_countyes():
            if self.yesbttn_clicks >= 1 or self.nobttn_clicks >= 1:
                popupmsg("Only one answer allowed!")
            else:
                self.yesbttn_clicks += 1
                yesbutt1['text'] = "Yes: " + str(self.yesbttn_clicks)
                directory = "C:\Users\Rylan\Documents\Python\Basel Summerintern files\{}".format(self.get_t_info())
                datafile = "{}_test1data.txt".format(self.get_t_info())
                entirefile = os.path.join(directory, datafile)
                myfile = open(entirefile, 'a')
                myfile.write('\nyes')
                myfile.close()

        def update_countno():
            if self.yesbttn_clicks >= 1 or self.nobttn_clicks >= 1:
                popupmsg("Only one answer allowed!")
            else:
                self.nobttn_clicks += 1
                nobutt1['text'] = "No: " + str(self.nobttn_clicks)
                directory = "C:\Users\Rylan\Documents\Python\Basel Summerintern files\{}".format(self.get_t_info())
                datafile = "{}_test1data.txt".format(self.get_t_info())
                entirefile = os.path.join(directory, datafile)
                myfile = open(entirefile, 'a')
                myfile.write('\nno')
                myfile.close()

        yesbutt1['command'] = update_countyes
        nobutt1['command'] = update_countno

    def get_t_info(self):
        self.gettheinfo = Startpage(app, self.controller).get_info()
        return self.gettheinfo

app = Testapp()
app.mainloop()

【问题讨论】:

    标签: python class user-interface oop tkinter


    【解决方案1】:

    你的问题是当你写的时候:

    def get_t_info(self):
        self.gettheinfo = Startpage(app, self.controller).get_info()
        return self.gettheinfo
    

    您创建一个新的起始页,其中条目为空。 那么

        Name = self.firstnameentry.get()
        ...
        foldername = (str(Name[0])
    

    尝试获取空字符串的第一个字符。

    我认为解决方案应该是这样的:

    def get_t_info(self):
        return self.controller.frames[Startpage]
    

    【讨论】:

    • 啊,它有效!厉害了,谢谢大佬!就这么简单的一行:)
    • 'def get_t_info(self):' 'self.gettheinfo = self.controller.frames[Startpage].get_info()' 'return self.gettheinfo' @Eric Levieil
    猜你喜欢
    • 2022-12-01
    • 2022-12-27
    • 1970-01-01
    • 2022-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-02
    • 2016-12-08
    相关资源
    最近更新 更多