# Python Tkinter 开发应用

GUI开发的一个重要工作就是学习如何对GUI组件进行合理的组装，一种比较现代的GUI组装方式是使用Stack的方式把GUI组件进行入栈、出栈，从而控制显示、隐藏、前进、后退逻辑。

Component 抽象类具有三个接口：

* `def component_did_mount(self, *args)`
* `def component_did_unmount(self)`
* `def render(self)`

分别表示加载组件，卸载组件，渲染组件事件，App内部将多个Component的子类组装成一个 Stack

* 前进到一个组件(`navigate_to`)的时候，调用它的`component_did_mount`方法，然后调用它的 `render` 方法
* 回退组件(`go_back`)的时候，调用它的`component_did_unmount`方法

```python
# -*- coding: UTF-8 -*-
from tkinter import Tk, Button
from tkinter import messagebox
from abc import ABC, abstractclassmethod

class Component:
    def __init__(self, app) -> None:
        self.app = app

    @abstractclassmethod
    def component_did_mount(self, *args):
        pass

    @abstractclassmethod
    def component_did_unmount(self):
        pass

    @abstractclassmethod
    def render(self):
        pass


class About(Component):
    def __init__(self, app) -> None:
        super().__init__(app)
        self.root = None
        self.btn = None

    def component_did_mount(self, root):
        self.root = root

    def component_did_unmount(self):
        self.root = None

    def render(self):
        messagebox.showinfo("关于我", "python.csdn.net")


class Home(Component):
    def __init__(self, app) -> None:
        super().__init__(app)
        self.app = app
        self.root = None
        self.btn = None

    def component_did_mount(self):
        self.text = "关于我"

    def component_did_unmount(self):
        self.root = None

    def render(self):
        self.root = Tk()
        self.btn = Button(
            self.root,
            text=self.text,
            command=lambda: self.app.navigate_to('About')
        )
        self.btn.pack()
        self.root.mainloop()


class App:
    def __init__(self, component_constructors) -> None:
        self.root = None
        self.component_constructors = component_constructors
        self.components = {}
        self.stack = []

    def init(self):
        for name in self.component_constructors:
            component_constructor = self.component_constructors[name]
            self.components[name] = component_constructor(self)

    def navigate_to(self, name, *args):
        # TODO(You): 请正确实现代码

    def go_back(self):
        # TODO(You): 请正确实现代码

    def render(self):
        if len(self.stack) > 0:
            return
        self.navigate_to("Home", self.root)

if __name__ == '__main__':
    app = App({
        "Home": Home,
        "About": About,
    })
    app.init()
    app.render()
```

请选出下列能**正确**实现这一功能的选项。

## template

```python

from tkinter import Tk, Button
from tkinter import messagebox
from abc import ABC, abstractclassmethod

class Component:
    def __init__(self, app) -> None:
        self.app = app

    @abstractclassmethod
    def component_did_mount(self, *args):
        pass

    @abstractclassmethod
    def component_did_unmount(self):
        pass

    @abstractclassmethod
    def render(self):
        pass

class About(Component):
    def __init__(self, app) -> None:
        super().__init__(app)
        self.root = None
        self.btn = None

    def component_did_mount(self, root):
        self.root = root

    def component_did_unmount(self):
        self.root = None

    def render(self):
        messagebox.showinfo("关于我", "python.csdn.net")


class Home(Component):
    def __init__(self, app) -> None:
        super().__init__(app)
        self.app = app
        self.root = None
        self.btn = None

    def component_did_mount(self, root):
        self.text = "关于我"

    def component_did_unmount(self):
        self.root = None

    def render(self):
        self.root = Tk()
        self.btn = Button(
            self.root,
            text=self.text,
            command=lambda: self.app.navigate_to('About')
        )
        self.btn.pack()
        self.root.mainloop()


class App:
    def __init__(self, component_constructors) -> None:
        self.root = None
        self.component_constructors = component_constructors
        self.components = {}
        self.stack = []

    def init(self):
        for name in self.component_constructors:
            component_constructor = self.component_constructors[name]
            self.components[name] = component_constructor(self)

    def navigate_to(self, name, *args):
        if self.components.get(name) is None:
            return
        c = self.components[name]
        self.stack.append(c)
        c.component_did_mount(self.root)
        c.render()

    def go_back(self):
        if len(self.stack) == 0:
            return
        c = self.stack.pop()
        c.component_did_unmount()

    def render(self):
        if len(self.stack) > 0:
            return
        self.navigate_to("Home", self.root)

if __name__ == '__main__':
    app = App({
        "Home": Home,
        "About": About,
    })
    app.init()
    app.render()
```

## 答案

```python
class App:
    ...
    def navigate_to(self, name, *args):
        if self.components.get(name) is None:
            return
        
        c = self.components[name]
        self.stack.append(c)
        c.component_did_mount(self.root)
        c.render()

    def go_back(self):
        if len(self.stack) == 0:
            return
        c = self.stack.pop()
        c.component_did_unmount()
```

## 选项

### A

```python
class App:
    ...
    def navigate_to(self, name, *args):
        if self.components.get(name) is None:
            return
        
        c = self.components[name]
        self.stack.append(c)
        c.component_did_unmount(self.root)
        c.render()

    def go_back(self):
        if len(self.stack) == 0:
            return
        c = self.stack.pop()
        c.component_did_mount()
```

### B

```python
class App:
    ...
    def navigate_to(self, name, *args):
        c = self.components[name]
        self.stack.append(c)
        c.component_did_mount(self.root)
        c.render()

    def go_back(self):
        if len(self.stack) == 0:
            return
        c = self.stack.pop()
        c.component_did_unmount()
```

### C

```python
class App:
    ...
    def navigate_to(self, name, *args):
        if self.components.get(name) is None:
            return
        
        c = self.components[name]
        self.stack.append(c)
        c.component_did_mount(self.root)
        c.render()

    def go_back(self):
        c = self.stack.pop()
        c.component_did_unmount()
```
