如何使用模型/视图/控制器方法制作 GUI? [英] How do I make a GUI using the model/view/controller method?

查看:15
本文介绍了如何使用模型/视图/控制器方法制作 GUI?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I need to understand the concept behind the model/view/controller method and how to write a GUI that way. Here's just a really basic, simple GUI. Can someone explain to me how to rewrite this code using 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()

推荐答案

ToyMVC "Toy MVC (Model View Controller)设计"在 Tkinter 文档中可能是您​​正在寻找的.我个人会设计一些不同的东西,但大体上是有道理的.

ToyMVC "Toy MVC (Model View Controller) design" in the Tkinter docs is probably what you're looking for. I would personally design things a bit differently, but it mostly makes sense.

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

The key is separating out the model and view, and the controller is then all the bits that connect up a model and a view.

因此,您将拥有这些类,而不是包含所有内容的 Application:

So, instead of having an Application with everything in it, you'd have these classes:

  • StoryModel:故事模型.
  • StoryView:您粘贴在框架内的窗口或其他小部件——尽管在 Tk 中,您也可以轻松地将其作为框架本身.
  • StoryController:一个类,给定一个 StoryModel 和一个 StoryView,会告诉它的 StoryView 创建适当的小部件来显示该故事,然后将监视模型和视图的更改并将它们从一个传输到另一个.
  • StoryModel: A model of a story.
  • StoryView: A window or other widget that you stick inside the frame—although in Tk, you can just as easily make it the frame itself.
  • StoryController: A class that, given a StoryModel and a StoryView, will tell its StoryView to create the appropriate widgets to display that story, and will then monitor both Model and View for changed and transmit them from one to the other.

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

Given that, you can create a simple Application that creates one StoryModel, one StoryView, one frame window to put the View in, and one StoryController to connect up the model and view.

例如,StoryModel 可能如下所示:

For example, StoryModel could look like this:

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 以创建每个视图中的一个,以及一个每个控制器,附加到相同的模型.例如,您可以创建一个不使用网格的视图,而是自动布局:

And then you can get fancy and create an AlternateStoryView that displays the same information in a different way, and change the Application to create one of each view, and a controller for each, attached to the same model. For example, you might create a view that didn't use a grid, and instead automatically laid things out:

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 方法,您可能会注意到 Observable 与使用 Tkinter.StringVar 并没有什么不同,等等. 但是优点(除了没有 trace 的笨拙语法之外)是这种方式没有任何 Tkinter 特定于模型的东西.

If you know about the trace method, you may notice that an Observable isn't really any different than using Tkinter.StringVar, etc. But the advantage (besides not having the clunky syntax of trace…) is that there's nothing Tkinter-specific about the model this way.

因此,您可以创建GtkStoryViewCursesStoryView,而无需更改ModelController<中的任何代码/代码>.(这对 ToyMVC 不太适用,因为像 addButton.config(command=self.addMoney) 之类的东西不会完全转换为 Gtk+ 或 curses,除非您构建了一个大的 Tk 仿真层……但是您不必在您的设计中犯那个错误.)

So, you can create a GtkStoryView or a CursesStoryView, without changing any of the code in the Model and Controller. (This doesn't quite work with ToyMVC, because things like addButton.config(command=self.addMoney) won't exactly translate to Gtk+ or curses unless you built a big Tk emulation layer… but you don't have to make that mistake in your design.)

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

Also, note that using Observable wrappers around all of your model variables is definitely not the only way to hook up a controller, or even necessarily the most Pythonic.

这篇关于如何使用模型/视图/控制器方法制作 GUI?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆