3

我需要了解模型/视图/控制器方法背后的概念以及如何以这种方式编写 GUI。这只是一个非常基本、简单的 GUI。有人可以向我解释如何使用 MVC 重写此代码吗?

from tkinter import *

class Application(Frame):
    """ GUI application that creates a story based on user input. """
    def __init__(self, master):
        """ Initialize Frame. """
        super(Application, self).__init__(master)  
        self.grid()
        self.create_widgets()

    def create_widgets(self):
        """ Create widgets to get story information and to display story. """
        # create instruction label
        Label(self,
              text = "Enter information for a new story"
              ).grid(row = 0, column = 0, columnspan = 2, sticky = W)

        # create a label and text entry for the name of a person
        Label(self,
              text = "Person: "
              ).grid(row = 1, column = 0, sticky = W)
        self.person_ent = Entry(self)
        self.person_ent.grid(row = 1, column = 1, sticky = W)

        # create a label and text entry for a plural noun
        Label(self,
              text = "Plural Noun:"
              ).grid(row = 2, column = 0, sticky = W)
        self.noun_ent = Entry(self)
        self.noun_ent.grid(row = 2, column = 1, sticky = W)

        # create a label and text entry for a verb
        Label(self,
              text = "Verb:"
              ).grid(row = 3, column = 0, sticky = W)
        self.verb_ent = Entry(self)
        self.verb_ent.grid(row = 3, column = 1, sticky = W)

        # create a label for adjectives check buttons
        Label(self,
              text = "Adjective(s):"
              ).grid(row = 4, column = 0, sticky = W)

        # create itchy check button
        self.is_itchy = BooleanVar()
        Checkbutton(self,
                    text = "itchy",
                    variable = self.is_itchy
                    ).grid(row = 4, column = 1, sticky = W)

        # create joyous check button
        self.is_joyous = BooleanVar()
        Checkbutton(self,
                    text = "joyous",
                    variable = self.is_joyous
                    ).grid(row = 4, column = 2, sticky = W)

        # create electric check button
        self.is_electric = BooleanVar()
        Checkbutton(self,
                    text = "electric",
                    variable = self.is_electric
                    ).grid(row = 4, column = 3, sticky = W)

        # create a label for body parts radio buttons
        Label(self,
              text = "Body Part:"
              ).grid(row = 5, column = 0, sticky = W)

        # create variable for single, body part
        self.body_part = StringVar()
        self.body_part.set(None)

        # create body part radio buttons
        body_parts = ["bellybutton", "big toe", "medulla oblongata"]
        column = 1
        for part in body_parts:
            Radiobutton(self,
                        text = part,
                        variable = self.body_part,
                        value = part
                        ).grid(row = 5, column = column, sticky = W)
            column += 1

        # create a submit button
        Button(self,
               text = "Click for story",
               command = self.tell_story
               ).grid(row = 6, column = 0, sticky = W)

        self.story_txt = Text(self, width = 75, height = 10, wrap = WORD)
        self.story_txt.grid(row = 7, column = 0, columnspan = 4)

    def tell_story(self):
        """ Fill text box with new story based on user input. """
        # get values from the GUI
        person = self.person_ent.get()
        noun = self.noun_ent.get()
        verb = self.verb_ent.get()
        adjectives = ""
        if self.is_itchy.get():
            adjectives += "itchy, "
        if self.is_joyous.get():
            adjectives += "joyous, "
        if self.is_electric.get():
            adjectives += "electric, "
        body_part = self.body_part.get()

        # create the story
        story = "The famous explorer "
        story += person
        story += " had nearly given up a life-long quest to find The Lost City of "
        story += noun.title()
        story += " when one day, the "
        story += noun
        story += " found "
        story += person + ". "
        story += "A strong, "
        story += adjectives
        story += "peculiar feeling overwhelmed the explorer. "
        story += "After all this time, the quest was finally over. A tear came to "
        story += person + "'s "
        story += body_part + ". "
        story += "And then, the "
        story += noun
        story += " promptly devoured "
        story += person + ". "
        story += "The moral of the story? Be careful what you "
        story += verb
        story += " for."

        # display the story                                
        self.story_txt.delete(0.0, END)
        self.story_txt.insert(0.0, story)

# main
def main():
    root = Tk()
    root.title("Mad Lib")
    app = Application(root)
    root.mainloop()

main()
4

2 回答 2

8

Tkinter 文档中的ToyMVC “Toy MVC(模型视图控制器)设计”可能是您正在寻找的。我个人会设计一些不同的东西,但它主要是有道理的。

关键是分离模型和视图,然后控制器就是连接模型和视图的所有位。

Application因此,您将拥有以下类,而不是其中的所有内容:

  • StoryModel: 一个故事的模型。
  • StoryView: 粘贴在框架内的窗口或其他小部件——尽管在 Tk 中,您可以轻松地将其设置为框架本身。
  • StoryController: 一个类,给定 aStoryModel和 a StoryView,将告诉它StoryView创建适当的小部件来显示该故事,然后将监视模型和视图的更改并将它们从一个传输到另一个。

鉴于此,您可以创建一个简单Application的创建一个StoryModel、一个StoryView、一个框架窗口来放置视图,以及一个StoryController用于连接模型和视图的框架窗口。

例如,StoryModel可能看起来像这样:

class StoryModel(object):
    body_parts = ['bellybutton', 'big toe', 'medulla oblongato']
    def __init__(self):
        self.person = ObservableStr('')
        # ...
        self.is_itchy = ObservableBool(False)
        # ...
    def tell(self):
        story = "The famous explorer "
        # ...
        return story

然后,您可以花哨并创建一个AlternateStoryView以不同方式显示相同信息的视图,并更改Application为每个视图创建一个,并为每个视图创建一个控制器,附加到同一模型。例如,您可能会创建一个不使用网格的视图,而是自动布局:

class AlternateStoryView(Frame):
    def __init__(self, master):
        super(StoryView, self).__init__(master)
    def add_label(label):
        label = Label(self, text=label)
        label.pack()
        return label

如果您了解该trace方法,您可能会注意到 anObservable与 using 等并没有什么不同Tkinter.StringVar。但是优点(除了没有trace...的笨拙语法之外)是这种方式没有任何Tkinter特定的模型。

因此,您可以创建 aGtkStoryView或 a CursesStoryView,而无需更改Modeland中的任何代码Controller。(这对 ToyMVC 不太适用,因为addButton.config(command=self.addMoney)除非你构建了一个大的 Tk 仿真层,否则不会完全转化为 Gtk+ 或 curses 之类的东西……但你不必在设计中犯这个错误。)

另外,请注意,Observable在所有模型变量周围使用包装器绝对不是连接控制器的唯一方法,甚至不一定是最 Pythonic 的方法。

于 2013-05-08T22:50:44.083 回答
-4

如果您想使用 python 语言开始/学习 MVC Web 开发,我建议您开始使用Django 框架

于 2013-05-08T22:17:26.933 回答