【问题标题】:Returning variables in tkinter when using classes? [duplicate]使用类时在 tkinter 中返回变量? [复制]
【发布时间】:2021-09-15 06:59:12
【问题描述】:

我正在寻找有关如何解决我的问题的建议。我需要一种方法来将条目列表保存在我的saveInput() 方法中,以便稍后在课堂外使用不同的函数访问它。我想出的唯一解决方案是一个全局变量,但我被告知它们是魔鬼,当它们不恒定时我应该尽量避免它们。如果有人能给我一个解决方案,我将不胜感激。我的代码如下,包括 CSV 文件。

from tkinter import font as tkfont  # python 3
import tkinter as tk
import csv


class SampleApp(tk.Tk):

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

        self.title_font = tkfont.Font(family='Helvetica', size=18, weight="bold", slant="italic")

        # the container is where we'll stack a bunch of frames
        # on top of each other, then the one we want visible
        # will be raised above the others
        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand=True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.frames = {}
        for F in (StartPage, PageOne, PageTwo, PageThree, PageFour):
            page_name = F.__name__
            frame = F(parent=container, controller=self)
            self.frames[page_name] = frame

            # put all of the pages in the same location;
            # the one on the top of the stacking order
            # will be the one that is visible.
            frame.grid(row=0, column=0, sticky="nsew")

        self.show_frame("StartPage")

    def show_frame(self, page_name):
        '''Show a frame for the given page name'''
        frame = self.frames[page_name]
        frame.tkraise()


class StartPage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(self, text="This is the start page", font=controller.title_font)
        label.pack(side="top", fill="x", pady=10)

        button1 = tk.Button(self, text="Enter airport details",
                            command=lambda: controller.show_frame("PageOne"))
        button2 = tk.Button(self, text="Enter flight details",
                            command=lambda: controller.show_frame("PageTwo"))
        button3 = tk.Button(self, text="Enter price plan and calculate profit",
                            command=lambda: controller.show_frame("PageThree"))
        button4 = tk.Button(self, text="Clear data",
                            command=lambda: controller.show_frame("PageFour"))
        button1.pack()
        button2.pack()
        button3.pack()
        button4.pack()


class PageOne(tk.Frame):

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

        ukAirportOptionList = [
            "LPL",
            "BOH"
        ]

        foreignAirportList = []

        with open('Airports.csv', 'r') as fd:
            reader = csv.reader(fd)
            for row in reader:
                foreignAirportList.append(row)

        tk.Label(self, text="Airport Details", font=controller.title_font).grid()

        ukAirportTracker = tk.StringVar()
        ukAirportTracker.set("Select the UK Airport")
        tk.OptionMenu(self, ukAirportTracker, *ukAirportOptionList).grid()

        foreignAirportTracker = tk.StringVar()
        foreignAirportTracker.set("Select the Oversea Airport")
        tk.OptionMenu(self, foreignAirportTracker, *[airport[0] for airport in foreignAirportList]).grid()

        saveButton = tk.Button(self, text="Save",
                               command=lambda: [controller.show_frame("StartPage"),
                                                self.saveInput(ukAirportTracker, foreignAirportTracker)])
        saveButton.grid(row=3, column=1)

    def saveInput(self, *args):
        enteries = []

        for arg in args:
            enteries.append(arg.get())

        print(enteries)

class PageTwo(tk.Frame):

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

        aircraftTypesList = [['medium narrow body', 8, 2650, 180, 8],
                             ['large narrow body', 7, 5600, 220, 10],
                             ['medium wide body', 5, 4050, 406, 14]]

        label = tk.Label(self, text="Flight Details", font=controller.title_font)
        label.grid()

        aircraftTypeTracker = tk.StringVar()
        aircraftTypeTracker.set("Aircraft Type")
        tk.OptionMenu(self, aircraftTypeTracker, *[aircraft[0] for aircraft in aircraftTypesList]).grid()

        saveButton = tk.Button(self, text="Save",
                               command=lambda: [controller.show_frame("StartPage"), self.saveInput(aircraftTypeTracker)])
        saveButton.grid()

    def saveInput(self, *args):
        enteries = []

        for arg in args:
            enteries.append(arg.get())

        print(enteries)


class PageThree(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        tk.Label(self, text="This is page 3", font=controller.title_font).grid(row=0, column=0)

        tk.Label(self, text="Price of Standard Seat").grid(row=1)
        tk.Label(self, text="Price of First Class Seat").grid(row=2)

        e1 = tk.Entry(self)
        e2 = tk.Entry(self)

        e1.grid(row=1, column=1)
        e2.grid(row=2, column=1)

        saveButton = tk.Button(self, text="Save",
                               command=lambda: [controller.show_frame("StartPage"), self.saveInput(e1, e2)])

        saveButton.grid(row=3, column=1)

    def saveInput(self, *args):
        enteries = []

        for arg in args:
            enteries.append(arg.get())

        print(enteries)


class PageFour(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(self, text="This is page 4", font=controller.title_font)
        label.pack(side="top", fill="x", pady=10)
        button = tk.Button(self, text="Go to the start page",
                           command=lambda: controller.show_frame("StartPage"))
        button.pack()


if __name__ == "__main__":
    app = SampleApp()
    app.mainloop()

csv 文件:

JFK,John F Kennedy International,5326,5486
ORY,Paris-Orly,629,379
MAD,Adolfo Suarez Madrid-Barajas,1428,1151
AMS,Amsterdam Schiphol,526,489
CAI,Cairo International,3779,3584

【问题讨论】:

  • 请阅读来自this answer的问题链接。有一个问题几乎完全符合您的要求。

标签: python variables tkinter


【解决方案1】:

在这种情况下,一种主要避免全局变量的方法是使局部变量enteries成为某个类的实例属性。在这种情况下,我选择了这个 tkinter 应用程序架构定义的SampleApp“控制器”。 (注意我在下面的修改代码中也把它的名字改成了entries。)

我这么说是因为很难没有任何

免责声明:我不太了解您想要或计划在代码的每个 Page 类中放入 enteries 列表中的内容,因此下面的结果与您的代码中的结果相同。我也不确定“返回变量”是什么意思,因为类是对象并且本身不返回任何内容。它们可以是数据的容器,并具有返回值的方法——但您的问题代码中没有任何示例。为了纠正这一点,我添加了一个 Quit 按钮来演示如何检索数据。

无论如何,我在下面的代码中进行了必要的修改。此外,我注意到每个Page 类中有很多重复的/非常相似的代码,因此我定义了一个名为_BasePage 的私有基类,并从它派生了所有其他基类。这使我可以将通用代码放在那里,并且是应用 DRY principle 的示例,这是使用类的另一个好处。

from tkinter import font as tkfont  # python 3
import tkinter as tk
import csv


class SampleApp(tk.Tk):

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

        self.title_font = tkfont.Font(family='Helvetica', size=18, weight="bold", 
                                      slant="italic")
        self.entries = []  # Accumulated entries.

        # the container is where we'll stack a bunch of frames
        # on top of each other, then the one we want visible
        # will be raised above the others
        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand=True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.frames = {}
        for F in (StartPage, PageOne, PageTwo, PageThree, PageFour):
            page_name = F.__name__
            frame = F(parent=container, controller=self)
            self.frames[page_name] = frame

            # put all of the pages in the same location;
            # the one on the top of the stacking order
            # will be the one that is visible.
            frame.grid(row=0, column=0, sticky="nsew")

        self.show_frame("StartPage")

    def show_frame(self, page_name):
        '''Show a frame for the given page name.'''
        frame = self.frames[page_name]
        frame.tkraise()


class _BasePage(tk.Frame):

    def __init__(self, parent, controller):
        super().__init__(parent)
        self.controller = controller

    def saveInput(self, *string_vars):
        strings = [var.get() for var in string_vars]
        print(f'adding entries: {strings}')
        self.controller.entries.extend(strings)


class StartPage(_BasePage):

    def __init__(self, parent, controller):
        super().__init__(parent, controller)

        label = tk.Label(self, text="This is the start page", font=controller.title_font)
        label.pack(side="top", fill="x", pady=10)

        tk.Button(self, text="Enter airport details",
                   command=lambda: controller.show_frame("PageOne")).pack()
        tk.Button(self, text="Enter flight details",
                  command=lambda: controller.show_frame("PageTwo")).pack()
        tk.Button(self, text="Enter price plan and calculate profit",
                  command=lambda: controller.show_frame("PageThree")).pack()
        tk.Button(self, text="Clear data",
                  command=lambda: controller.show_frame("PageFour")).pack()
        tk.Button(self, text="Quit",
                  command=self.quit).pack()  # Terminate mainloop().

class PageOne(_BasePage):

    def __init__(self, parent, controller):
        super().__init__(parent, controller)

        ukAirportOptionList = [
            "LPL",
            "BOH"
        ]

        foreignAirportList = []

        with open('Airports.csv', 'r') as fd:
            reader = csv.reader(fd)
            for row in reader:
                foreignAirportList.append(row)

        tk.Label(self, text="Airport Details", font=controller.title_font).grid()

        ukAirportTracker = tk.StringVar()
        ukAirportTracker.set("Select the UK Airport")
        tk.OptionMenu(self, ukAirportTracker, *ukAirportOptionList).grid()

        foreignAirportTracker = tk.StringVar()
        foreignAirportTracker.set("Select the Oversea Airport")
        tk.OptionMenu(self, foreignAirportTracker,
                      *[airport[0] for airport in foreignAirportList]).grid()

        saveButton = tk.Button(self, text="Save", command=lambda:
                          [controller.show_frame("StartPage"),
                           self.saveInput(ukAirportTracker, foreignAirportTracker)])
        saveButton.grid(row=3, column=1)


class PageTwo(_BasePage):

    def __init__(self, parent, controller):
        super().__init__(parent, controller)

        aircraftTypesList = [['medium narrow body', 8, 2650, 180, 8],
                             ['large narrow body', 7, 5600, 220, 10],
                             ['medium wide body', 5, 4050, 406, 14]]

        label = tk.Label(self, text="Flight Details", font=controller.title_font)
        label.grid()

        aircraftTypeTracker = tk.StringVar()
        aircraftTypeTracker.set("Aircraft Type")
        tk.OptionMenu(self, aircraftTypeTracker,
                      *[aircraft[0] for aircraft in aircraftTypesList]).grid()

        saveButton = tk.Button(self, text="Save", command=lambda:
                                            [controller.show_frame("StartPage"),
                                             self.saveInput(aircraftTypeTracker)])
        saveButton.grid()


class PageThree(_BasePage):

    def __init__(self, parent, controller):
        super().__init__(parent, controller)

        tk.Label(self, text="This is page 3",
                 font=controller.title_font).grid(row=0, column=0)

        tk.Label(self, text="Price of Standard Seat").grid(row=1)
        tk.Label(self, text="Price of First Class Seat").grid(row=2)

        e1 = tk.Entry(self)
        e2 = tk.Entry(self)

        e1.grid(row=1, column=1)
        e2.grid(row=2, column=1)

        saveButton = tk.Button(self, text="Save",
                               command=lambda: [controller.show_frame("StartPage"),
                                                self.saveInput(e1, e2)])
        saveButton.grid(row=3, column=1)


class PageFour(_BasePage):

    def __init__(self, parent, controller):
        super().__init__(parent, controller)

        label = tk.Label(self, text="This is page 4", font=controller.title_font)
        label.pack(side="top", fill="x", pady=10)
        button = tk.Button(self, text="Go to the start page",
                           command=lambda: controller.show_frame("StartPage"))
        button.pack()


if __name__ == "__main__":
    app = SampleApp()
    app.mainloop()

    print('Final entries:')
    for entry in app.entries:
        print(f'  {entry}')

【讨论】:

    猜你喜欢
    • 2020-02-19
    • 1970-01-01
    • 1970-01-01
    • 2021-05-21
    • 2012-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多