From 5875cc06048ef66b69508a0106802bb4abcc2ee6 Mon Sep 17 00:00:00 2001 From: feilong Date: Tue, 28 Dec 2021 23:49:08 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=88=B0=E7=AC=AC8=E7=AB=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../1.Tkinter/app.json" | 21 +- .../1.Tkinter/app.md" | 296 ++++++++++++++++++ .../1.Tkinter/basic.json" | 18 +- .../1.Tkinter/basic.md" | 124 ++++++++ .../2.PyQT/for_each_month.json" | 17 +- .../2.PyQT/for_each_month.md" | 182 +++++++++++ .../2.PyQT/for_each_month.png" | Bin 0 -> 22441 bytes .../2.PyQT/for_each_month.py" | 4 +- .../2.PyQT/q_progress_bar.json" | 20 +- .../2.PyQT/q_progress_bar.md" | 251 +++++++++++++++ .../2.PyQT/q_progress_bar.png" | Bin 0 -> 26623 bytes .../2.PyQT/q_progress_bar.py" | 32 +- .../2.PyQT/q_progress_thread.json" | 23 +- .../2.PyQT/q_progress_thread.md" | 156 +++++++++ .../2.PyQT/q_progress_thread.py" | 30 +- .../3.WxPython/config.json" | 3 +- .../3.WxPython/create_panel.json" | 8 + .../3.WxPython/create_panel.md" | 159 ++++++++++ .../3.WxPython/create_panel.py" | 40 +++ .../3.WxPython/create_window.json" | 8 + .../3.WxPython/create_window.md" | 179 +++++++++++ .../3.WxPython/create_window.py" | 55 ++++ .../3.WxPython/event.json" | 20 -- .../3.WxPython/event.py" | 63 ---- main.py | 4 +- 25 files changed, 1519 insertions(+), 194 deletions(-) create mode 100644 "data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/1.Tkinter/app.md" create mode 100644 "data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/1.Tkinter/basic.md" create mode 100644 "data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/for_each_month.md" create mode 100644 "data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/for_each_month.png" create mode 100644 "data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/q_progress_bar.md" create mode 100644 "data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/q_progress_bar.png" create mode 100644 "data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/q_progress_thread.md" create mode 100644 "data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/3.WxPython/create_panel.json" create mode 100644 "data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/3.WxPython/create_panel.md" create mode 100644 "data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/3.WxPython/create_panel.py" create mode 100644 "data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/3.WxPython/create_window.json" create mode 100644 "data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/3.WxPython/create_window.md" create mode 100644 "data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/3.WxPython/create_window.py" delete mode 100644 "data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/3.WxPython/event.json" delete mode 100644 "data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/3.WxPython/event.py" diff --git "a/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/1.Tkinter/app.json" "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/1.Tkinter/app.json" index 1179b9d..fa4e0b7 100644 --- "a/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/1.Tkinter/app.json" +++ "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/1.Tkinter/app.json" @@ -1,21 +1,8 @@ { - "one_line": { - "if len(self.stack) == 0": [ - "if len(self.stack) > 0", - "if len(self.stack) >= 0" - ], - "if len(self.stack) > 0": [ - "if len(self.stack) == 0" - ], - "c.component_did_unmount()": [ - "c.component_did_mount()" - ], - "c.component_did_mount(*args)": [ - "c.component_did_unmount(*args)" - ] - }, - "source": "app.py", + "source": "app.md", "depends": [], "exercise_id": 2, - "type": "code_options" + "type": "code_options", + "author": "huanhuilong", + "notebook_enable": true } \ No newline at end of file diff --git "a/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/1.Tkinter/app.md" "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/1.Tkinter/app.md" new file mode 100644 index 0000000..69dda17 --- /dev/null +++ "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/1.Tkinter/app.md" @@ -0,0 +1,296 @@ +# 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() +``` diff --git "a/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/1.Tkinter/basic.json" "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/1.Tkinter/basic.json" index 57f871f..94f0371 100644 --- "a/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/1.Tkinter/basic.json" +++ "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/1.Tkinter/basic.json" @@ -1,18 +1,8 @@ { - "multiline": [ - { - "show.pack()": "", - "number.pack()": "" - }, - { - "command=self.on_show": "command=self.on_show()" - }, - { - "lambda: self.on_click(i)": "self.on_click(i)" - } - ], - "source": "basic.py", + "source": "basic.md", "depends": [], "exercise_id": 1, - "type": "code_options" + "type": "code_options", + "author": "huanhuilong", + "notebook_enable": true } \ No newline at end of file diff --git "a/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/1.Tkinter/basic.md" "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/1.Tkinter/basic.md" new file mode 100644 index 0000000..6d39435 --- /dev/null +++ "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/1.Tkinter/basic.md" @@ -0,0 +1,124 @@ +# Python Tkinter 开发应用基础 + +基本的控件组装,组装一个数字记录窗口,添加必要的事件绑定 + +```python +# -*- coding: UTF-8 -*- +from tkinter import Tk, Button, messagebox + +class NumberRecorder: + def __init__(self) -> None: + self.numbers = [] + + def render(self): + self.main_window = Tk() + show = Button( + self.main_window, + text=f"查看结果", + command=self.on_show + ) + show.pack() + + # TODO(You): 请在此组装1-9数字按钮 + + self.main_window.mainloop() + + def on_show(self): + messagebox.showinfo("输入数字", f"{','.join(self.numbers)}") + + def on_click(self, i): + self.numbers.append(i) + +if __name__ == '__main__': + app = NumberRecorder() + app.render() +``` + +请选出下列能**正确**实现这一功能的选项。 + +## template + +```python +from tkinter import Tk, Button, messagebox + + +class NumberRecorder: + def __init__(self) -> None: + self.numbers = [] + + def render(self): + self.main_window = Tk() + show = Button( + self.main_window, + text=f"查看结果", + command=self.on_show + ) + show.pack() + + for i in range(0, 9): + number = Button( + self.main_window, + text=f"{i}", + command=lambda: self.on_click(i) + ) + number.pack() + + self.main_window.mainloop() + + def on_show(self): + messagebox.showinfo("输入数字", f"{','.join(self.numbers)}") + + def on_click(self, i): + self.numbers.append(i) + +if __name__ == '__main__': + app = NumberRecorder() + app.render() +``` + +## 答案 + +```python +for i in range(0, 9): + number = Button( + self.main_window, + text=f"{i}", + command=lambda: self.on_click(i) + ) + number.pack() +``` + +## 选项 + +### A + +```python +for i in range(0, 9): + number = Button( + self.main_window, + text=f"{i}", + command=lambda: self.on_click(i) + ) +``` + +### B + +```python +for i in range(0, 9): + number = Button( + text=f"{i}", + command=lambda: self.on_click(i) + ) + number.pack() +``` + +### C + +```python +for i in range(0, 9): + number = Button( + self.main_window, + text=f"{i}", + ) + number.pack() +``` diff --git "a/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/for_each_month.json" "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/for_each_month.json" index 238beb6..9093cc9 100644 --- "a/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/for_each_month.json" +++ "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/for_each_month.json" @@ -1,20 +1,11 @@ { - "one_line": { - "self.__month_count()": [ - "self.__month_count" - ], - "self.__for_each_month": [ - "self.__for_each_month()" - ], - "sys.exit(app.exec_())": [ - "sys.exit()" - ] - }, - "source": "for_each_month.py", + "source": "for_each_month.md", "depends": [ "q_progress_thread.py", "q_progress_bar.py" ], "exercise_id": 205, - "type": "code_options" + "type": "code_options", + "author": "huanhuilong", + "notebook_enable": true } \ No newline at end of file diff --git "a/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/for_each_month.md" "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/for_each_month.md" new file mode 100644 index 0000000..fc657fd --- /dev/null +++ "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/for_each_month.md" @@ -0,0 +1,182 @@ +# Python PyQt 进度条(3) + +![](./for_each_month.png) + +请先完成上一题。使用封装好的 PyQT 进度条显示2008年1月到本月的每个月1号进度。经过层层封装,到这里主要是上层的组合逻辑了。 + +```python +# -*- coding: UTF-8 -*- +import sys +import time +from datetime import date, timedelta +from calendar import monthrange +from datetime import timedelta +from PyQt5.QtWidgets import QApplication +from q_progress_bar import QRunnerProgressBar + +class MonthProgress: + def __init__(self, start_month, finish_month): + self.start = start_month + self.finish = finish_month + + def __month_count(self): + # 统计开始和结束时间之间的月份 + count = 0 + d1 = self.start + d2 = self.finish + while True: + mdays = monthrange(d1.year, d1.month)[1] + d1 += timedelta(days=mdays) + if d1 <= d2: + count += 1 + else: + break + return count + + def __for_each_month(self, emit_progress): + # TODO(You): 请在此触发每个月的进度条 + + def run(self): + # 运行程序 + app = QApplication(sys.argv) + bar = QRunnerProgressBar( + self.__month_count(), + "如果每个月都有技能树进度条...", + self.__for_each_month + ) + bar.show() + sys.exit(app.exec_()) + + +if __name__ == "__main__": + month_progress = MonthProgress( + date(2008, 1, 1), + date.today(), + ) + month_progress.run() +``` + +请选出下列能**正确**实现这一功能的选项。 + +## template + +```python +from datetime import date, timedelta +from calendar import monthrange +from datetime import timedelta +import sys +import time + +from PyQt5.QtWidgets import QApplication +from q_progress_bar import QRunnerProgressBar + + +class MonthProgress: + def __init__(self, start_month, finish_month): + self.start = start_month + self.finish = finish_month + + def __month_count(self): + count = 0 + d1 = self.start + d2 = self.finish + while True: + mdays = monthrange(d1.year, d1.month)[1] + d1 += timedelta(days=mdays) + if d1 <= d2: + count += 1 + else: + break + return count + + def __for_each_month(self, emit_progress): + d = self.start + finish = self.finish + progress = 0 + while d < finish: + time.sleep(0.1) + emit_progress(progress, d.__str__()) + d = d+timedelta(monthrange(d.year, d.month)[1]) + progress += 1 + + def run(self): + app = QApplication(sys.argv) + bar = QRunnerProgressBar( + self.__month_count(), + "如果每个月都有技能树进度条...", + self.__for_each_month + ) + bar.show() + sys.exit(app.exec_()) + + +if __name__ == "__main__": + month_progress = MonthProgress( + date(2008, 1, 1), + date.today(), + ) + month_progress.run() +``` + +## 答案 + +```python +class MonthProgress: + ... + def __for_each_month(self, emit_progress): + d = self.start + finish = self.finish + progress = 0 + while d < finish: + time.sleep(0.1) + emit_progress(progress, d.__str__()) + d = d+timedelta(monthrange(d.year, d.month)[1]) + progress += 1 +``` + +## 选项 + +### A + +```python +class MonthProgress: + ... + def __for_each_month(self, emit_progress): + d = self.start + finish = self.finish + progress = 0 + while d < finish: + time.sleep(0.1) + emit_progress(progress, d.__str__()) + progress += 1 +``` + +### B + +```python +class MonthProgress: + ... + def __for_each_month(self, emit_progress): + d = self.start + finish = self.finish + progress = 0 + while d < finish: + time.sleep(0.1) + emit_progress(progress, d.__str__()) + progress += 1 +``` + +### C + +```python +class MonthProgress: + ... + def __for_each_month(self, emit_progress): + d = self.start + finish = self.finish + progress = 0 + while d < finish: + time.sleep(0.1) + d = d+timedelta(monthrange(d.year, d.month)[1]) + progress += 1 +``` diff --git "a/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/for_each_month.png" "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/for_each_month.png" new file mode 100644 index 0000000000000000000000000000000000000000..aa973f46b9558d0080193721cb278adbe48cbbca GIT binary patch literal 22441 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 literal 0 HcmV?d00001 diff --git "a/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/for_each_month.py" "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/for_each_month.py" index f443261..f0e2d10 100644 --- "a/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/for_each_month.py" +++ "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/for_each_month.py" @@ -31,13 +31,13 @@ class MonthProgress: break return count - def __for_each_month(self, on_progress): + def __for_each_month(self, emit_progress): d = self.start finish = self.finish progress = 0 while d < finish: time.sleep(0.1) - on_progress(progress, d.__str__()) + emit_progress(progress, d.__str__()) d = d+timedelta(monthrange(d.year, d.month)[1]) progress += 1 diff --git "a/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/q_progress_bar.json" "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/q_progress_bar.json" index c698982..ce707d8 100644 --- "a/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/q_progress_bar.json" +++ "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/q_progress_bar.json" @@ -1,22 +1,10 @@ { - "one_line": { - "self.thread = None": [ - "pass" - ], - "self.setLayout(self.vbox)": [ - "self.setLayout()" - ], - "self.vbox.addWidget(self.pbar)": [ - "self.vbox.addWidget()" - ], - "self.vbox.addWidget(self.btn)": [ - "self.vbox.addWidget()" - ] - }, - "source": "q_progress_bar.py", + "source": "q_progress_bar.md", "depends": [ "q_progress_thread.py" ], "exercise_id": 228, - "type": "code_options" + "type": "code_options", + "author": "huanhuilong", + "notebook_enable": true } \ No newline at end of file diff --git "a/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/q_progress_bar.md" "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/q_progress_bar.md" new file mode 100644 index 0000000..be8d3b7 --- /dev/null +++ "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/q_progress_bar.md" @@ -0,0 +1,251 @@ +# Python PyQt 进度条(2) + +![](./q_progress_bar.png) + +请先完成上一题。封装一个能显示进度条的 PyQT GUI 对话框, 对话框功能如下: + +1. 点击按钮“看资料+做题,就有技能树进度” 进度条开始步进 +2. 每次步进,进度条往前走1步,标题显示“Python技能树->PyQT:{i}/5” +3. 一共5步,运行过程中按钮不能点击,运行结束可以重新点击 + +```python +# -*- coding: UTF-8 -*- +import sys +import time +import math +from PyQt5.QtWidgets import QApplication, QWidget +from PyQt5.QtWidgets import QPushButton, QProgressBar +from PyQt5.QtWidgets import QVBoxLayout, QMessageBox +from q_progress_thread import QProgressThread + +class QRunnerProgressBar(QWidget): + def __init__(self, count, tip, runner): + super(QRunnerProgressBar, self).__init__() + self.setWindowTitle('QRunnerProgressBar') + + self.vbox = QVBoxLayout() + + self.btn = QPushButton(tip) + self.btn.clicked.connect(self.on_btn_click) + self.vbox.addWidget(self.btn) + + self.pbar = QProgressBar(self) + self.pbar.setValue(0) + self.vbox.addWidget(self.pbar) + + self.setLayout(self.vbox) + self.resize(300, 100) + self.show() + + self.count = count + self.runner = runner + + def on_btn_click(self): + # 复用上一题的 QProgressThread + self.thread = QProgressThread(self.runner) + self.thread.connect(self.on_progress) + self.thread.start() + self.btn.setEnabled(False) + + def on_progress(self, info): + percent_value = int(math.floor(info.progress*100/self.count)) + self.pbar.setValue(int(percent_value)) + self.setWindowTitle(info.msg) + if self.pbar.value() == self.count: + self.pbar.setValue(0) + self.btn.setEnabled(True) + + def closeEvent(self, event): + self.thread = None + + +if __name__ == "__main__": + app = QApplication(sys.argv) + + def on_run(emit_progress): + for i in range(0, 5): + time.sleep(1) + emit_progress(i+1, f'Python技能树->PyQT:{i+1}/5') + + p = QRunnerProgressBar( + count=5, + tip='看资料+做题,就有技能树进度', + runner=on_run + ) + sys.exit(app.exec_()) +``` + +请选出下列能**正确**实现这一功能的选项。 + +## template + +```python +import sys +import time +import math +from PyQt5.QtWidgets import QApplication, QWidget +from PyQt5.QtWidgets import QPushButton, QProgressBar +from PyQt5.QtWidgets import QVBoxLayout, QMessageBox +from q_progress_thread import QProgressThread + +class QRunnerProgressBar(QWidget): + def __init__(self, count, tip, runner): + super(QRunnerProgressBar, self).__init__() + self.setWindowTitle('QRunnerProgressBar') + + self.vbox = QVBoxLayout() + + self.btn = QPushButton(tip) + self.btn.clicked.connect(self.on_btn_click) + self.vbox.addWidget(self.btn) + + self.pbar = QProgressBar(self) + self.pbar.setValue(0) + self.vbox.addWidget(self.pbar) + + self.setLayout(self.vbox) + self.resize(300, 100) + self.show() + + self.count = count + self.runner = runner + + def on_btn_click(self): + self.thread = QProgressThread(self.runner) + self.thread.connect(self.on_progress) + self.thread.start() + self.btn.setEnabled(False) + + def on_progress(self, info): + percent_value = int(math.floor(info.progress*100/self.count)) + self.pbar.setValue(int(percent_value)) + self.setWindowTitle(info.msg) + if self.pbar.value() == 100: + self.pbar.setValue(0) + self.btn.setEnabled(True) + self.setWindowTitle('QRunnerProgressBar') + + def closeEvent(self, event): + self.thread = None + + +if __name__ == "__main__": + app = QApplication(sys.argv) + + def on_run(emit_progress): + for i in range(0, 5): + time.sleep(1) + emit_progress(i+1, f'Python技能树->PyQT:{i+1}/5') + + p = QRunnerProgressBar( + count=5, + tip='看资料+做题,就有技能树进度', + runner=on_run + ) + sys.exit(app.exec_()) +``` + +## 答案 + +```python +class QRunnerProgressBar(QWidget): + ... + def on_btn_click(self): + # 复用上一题的 QProgressThread + self.thread = QProgressThread(self.runner) + self.thread.connect(self.on_progress) + self.thread.start() + self.btn.setEnabled(False) + + def on_progress(self, info): + percent_value = int(math.floor(info.progress*100/self.count)) + self.pbar.setValue(int(percent_value)) + self.setWindowTitle(info.msg) + if self.pbar.value() == 100: + self.pbar.setValue(0) + self.btn.setEnabled(True) + self.setWindowTitle('QRunnerProgressBar') +``` + +## 选项 + +### A + +```python +class QRunnerProgressBar(QWidget): + ... + def on_btn_click(self): + # 复用上一题的 QProgressThread + self.thread = QProgressThread(self.runner) + self.thread.connect(self.on_progress) + self.thread.start() + self.btn.setEnabled(False) + + def on_progress(self, info): + percent_value = int(math.floor(info.progress*100/self.count)) + self.pbar.setValue(int(percent_value)) + self.setWindowTitle(info.msg) +``` + +### B + +```python +class QRunnerProgressBar(QWidget): + ... + def on_btn_click(self): + # 复用上一题的 QProgressThread + self.thread = QProgressThread(self.runner) + self.thread.connect(self.on_progress) + self.thread.start() + self.btn.setEnabled(False) + + def on_progress(self, info): + percent_value = int(math.floor(info.progress*100/self.count)) + self.pbar.setValue(int(percent_value)) + self.setWindowTitle(info.msg) + if self.pbar.value() == self.count: + self.pbar.setValue(0) + self.btn.setEnabled(True) + self.setWindowTitle('QRunnerProgressBar') +``` + +### C + +```python +class QRunnerProgressBar(QWidget): + ... + def on_btn_click(self): + # 复用上一题的 QProgressThread + self.thread = QProgressThread(self.runner) + self.thread.connect(self.on_progress) + self.thread.start() + self.btn.setEnabled(False) + + def on_progress(self, info): + self.pbar.setValue(info.progress) + self.setWindowTitle(info.msg) + if self.pbar.value() == 100: + self.pbar.setValue(0) + self.btn.setEnabled(True) + self.setWindowTitle('QRunnerProgressBar') +``` + +### D + +```python +class QRunnerProgressBar(QWidget): + ... + def on_btn_click(self): + # 复用上一题的 QProgressThread + self.thread = QProgressThread(self.runner) + self.thread.connect(self.on_progress) + self.thread.start() + + def on_progress(self, info): + percent_value = int(math.floor(info.progress*100/self.count)) + self.pbar.setValue(int(percent_value)) + self.setWindowTitle(info.msg) + if self.pbar.value() == 100: + self.pbar.setValue(0) + self.setWindowTitle('QRunnerProgressBar') +``` diff --git "a/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/q_progress_bar.png" "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/q_progress_bar.png" new file mode 100644 index 0000000000000000000000000000000000000000..82510b86b699f128186915fd6e8c142f404e4d16 GIT binary patch literal 26623 zcmZs>1ymeM*YAx7cXuaPaCi3*90qr{U^BS8dmy-ba2wo%Ly+K3aCiGS@B5r{p8MU) zs-}C@s_xqRzjs%4)%+s9e3n5$Bt(ROfIyLxl~jd*fC4~3KtjR8z1Pq>fKDJFkS(nx zB)-T=NRWT|>S$qYXAS`&8*L0fGEH(NI`K7I-cBOcQes}M_69-cYSU%f|K77BqT zG&t8p1`kKCJ={b}OUkZ-k=$17_$TG!lZlv=4xXC|b_x##r2bvXS(dlU{-lWI=TXH| zWQe5>!7@&~IY@G4Rr07fc;i?FCDTNH2m*X){d?n!`>*r@pFRznqhJqUe6RikQCP+~)nEn873}uK~_FD`P zNG-Vq%EYUbB?NyETAN^faqKbkC7R+%&|n^2bC-*pFwdlwGmYovjcNQX6|6Uqi>A9+ zN~vQ8X7|(X)8$jkPfka4PNSxx)zq;K_ZooGScMd&r<5{Flqcib9Oe7r>knC5;g3fM zTZ_=YnYfZ}#g&slkGe08tcAp{q}Qz!yokOfB@WUK1XxDd$%B{h0GagLKjxl6*>>GE zGYimCpD}gq-(qBkHI|1OA|)f}(bdSCK4H@hiB`haMhVhU$X9Wc%l1bQ{7RtTO1aRL zAZAIH3@$x34f$4g4s7(b&h}%AuW%!*g3@zIzLWeMZw zkQCY;C3PZtQrJerA0){qsy4YT|Q$WHU$#CryqZ z4plg5>ho_9k=i!rAacZ=-m}O6okR-9 zkqrd1{7Z?b7YNSk`)q>uqd=R)$b{~PXC;9^alb^x(Mb0p z;We%Zx-x15)oYkY_EJe*;@1Vjh0hDh<+V_o4N$v-+lmRF(<166VHLT(1>nEwA*`Fj z%&yL@qCo7nOW)kxq_Ul(is9pReSL_5xK9;lKVlrJhuRocgZOjS`Bl?#qe%y~yH>MP zT(fk`X*USsjizDqGY6DKH{xQS_eucI`G+2I5Ba*V=2xgS3%TPDnn7}62;0x-Y8 zr3P^s2`wTw1?U^G@WLN z9;YhyTZT`fRR&a1R%TsxP{F6ER>`MTFMj2}2O1B{AS?A$mthFw4=B(5RCHR%t?H<@ zK4ZnH3t(lA(G=B{uPDyS7s|b{nQqi;XaPV~@c~i*jR36%1M8$l`-b03NexjAqm5|R zhV!R06i17PPOd=ydN&5Q*gq@34yKEa+71Q}_YOWyuU2`9-L;a+O=_|zD(5zfI%clX zcMQ2kJ4o$MJzPIrpImcXqx$4`W(jMF=yoak)%ZsFHV0$}l!(>!a0bZ-nZlhQM;niB zuzw{O#s5ISgHIOr4b>D43sqOpZv6*i-x?7r4>C74VJhJ%57^;;I@}uDBH6T|w{+r9 zC!52umEb(E{DO9yV^F{EChQ4qAB}~?*Xf=F>sS9Y^_p4e2zQc25~&);EWBFT0spL8 zvAzXzy-~eg{hY|Z+l}C4C}lfi#F3H)0Wnj z-^_IETGuZ-aRwsIQ>+`8%16qVmsUKZZxoLRj|8~Qh*D#QEvm-(GVhw)o9LU6?2qhn zmI;=ePa=3)qY%N;jNm)XM@ z2cN-@gqLIRWR*?W?Thad?uUIsPP0lgN#jq`qNmt#Wp;G&`d9r*-5i6>rrxdO^H~wq|loc#ZwcXDv&3 zUid(m$lIarTF1GPrt+#2W*vQ}f1#eAGu8tQ%?>vJmVc1C$yIw~D5gl$NRv2aj;=UbfDyoK6cDSjGsG zNX5v91ITVZF0lb{S6SgmI6TM7+3rm2OsLu1YROZH+8J(rzw7JyuGE-Dm~Ibh#`+MR z;fip)>Olz^f9*XD_K2W}7{xrJ{Y^)on333+L`SVf*QJc0r1Nb?*kPwdXZuqTVM(Og z(X6cXh_%3s=U`ZjAxEca;6iXB0uSwy(s%BQUg~YR)}&aa`RuVw?~hsW*@>M3FIX(8 zS_4NT8y0rMfA(DNZ68=*djjVIKO6fy6`ku?i0=Iy+t-2Asi@+1(#Kia4mE@Hd5FzLQBtz|)NIY^tZ=qJKWSzt>r%-tE;QL^E*>0{R&u-#~Lfa$FrEPiBTeLFWMKTZ!=>>%%k8m zd%$PCPddJ)Qd5!ojBZ-ERo-BmvGS$4vALp(Hvk7{Jml--<+v@qEspInV?N{If=-QY z=jp8H^y5(qMamOTx}7$7^F_L6kTElm=VaNgt<~;oh4ut8d7w$-vXd%h#j>*$W}Y`HC` zw(A&zH<$N(YyUdOkvN)v(KX!7YMq6<%Z^u3L=O=4>vPRXHP&3?LdkqH34u>xSx?vI zdCjM;Q$ZW&hRgJxTJs_LAw1$U5f#_`5|yPzH}<2Q?cxz759JsEx0CC|S!T=piSHsr zzPG>lZd&&t#{HaQJDyth_u-Pn=K8<82$df|EOs zj~E^#?&45tjtyTfEzfhtSGU^)3`Py^x^yn*|C~&83BK7JMjV08Kb`5XKg}2vtm%_! zlTG+2KHOJ29@5Q}L{6gS5OqrWv@YZ5%hAajd)>!HETDuWfL zfzW}ar!~;<&vcb-EU4i;5CTDvvKdICoPq^*f#Yx{496)l_x(oxol+S(MSkzo&9UB9aLf=;&cIMi07D`GG4DZ+Q5HOI05U}r8kne{uB+)&M``fx8hk#`xn%{ljoz}={*W2r%N7s|S+kTdZ<_8id(VOTJ zk&g0ImYP%LoH;3f`Wwt%+h>KFlkZD~hHnt((_$6OI;vH&cc(&UUWPYi ze$PWT)A>>)KEIUcikza#Qy8^0?^axtZw6R=YdxP$$#h9>8%i{y61&SaEB{Eci?(@( zBc%KPr;K?)@fK*Vc^EbVW)vI+_RR2mmGei1E5j#_XpNxW3sPuzp_eP|%VXHsux!OZMUBDB>3`+p#1geTX?VGv zyFwN5j*N{ov27%(Y2AB8nb%(kTF>P3jQbyvyTvJ45A-dQd|#+0M#HO)9NWtHcMz0i z>rI4sX;KGmnCpfK*_>r8|5Ed>!pa7dPH7vZ#8Xu=lt@=`s;M^@(jpsaYZ87h{vW;m zl1vh2N`*10)Fj_SGHuX?{&DWK#m3=UgYUvQmg%>&DO2k_etZZXcLy^X~FNQ z`LMeEw45|!5G1@Cq09t(&~_4K`1;lDhHF9Hwz}2g=8-Dyn6RngYU!xDVk404_t&lk zoygf`TL11sk1VCfn@Lez8N1aa0|swx23ylRiV^@j^u9~-yQ3VU8(|`kDsH1y&6)yC z`b%n77ao8&_n-7`4C!<=hLD$4YRXleFRN$sIUQuL=Z7Tk)(kK{_KLi@ta>h+Hm|~A z0`^}HwdNl1^uAQpPw)@id)b4xV+G1Nd@qyu7f=3e){vRSrou5w>-91c52EO~o9(-J6pwy>4im|u3N=zP4XSqQK$dKrl_)T?>>(=c1^ zGAU5=II0CUSqk=Mv(VcgO-wt~!ZXnJLtXKEJB$xPixq3DetR4ws#tdH@&TkbE*P{g zc~(>v+uw!uz&~?GTyQOD7XXCDp&R0lu?|H3oSJ_gHp`?_KDwG+HsZ!gM}fL4sdH@B zcQ2bzbg?lGXZbmmfLJxk(go(f8sn&_pOO2B{ZQGw=GoZ2Rp=^1-d5dlyL1>P@@(8V zDg31VblUFN*oP|c!)tK-fQa})#P`%??rerEc3Y$8{Ht9C+}p^D*+U`E@-?F%&qqJ?u>gEjjg}RGiET(fGvq?odVb9+3&(l-WrA zBnnzoFud=z=|kbh-;BBCtv*WWNyCna@N3ZJw(xSP;{jO(ox5u{^ z!+npMl)l#uG{VW*Bki*sJ*efv!Q4SBiaKqwZ&QyKaejJPsQ_@4+Gf_PNNqNSMyUqE zmoJxM-YU6<&I34eMI%@779};Prv(EQz$YDkpO>i&(o}f~95^ow4jL*`p;za)3WF3d z=}w3WA-|-Kd%&O-3N!V7&A5%ABW%=8`6VThXelk{=&UEp+a!4x3wGd}y zxAS!FajBsS@x^@O=V^uBpfG+^kl4_d!?{G_7klL*Dv zqvHb84xq!or4S}fU#_>&5ji%fxLvErXtWono-5*SOIdxCg2bG>%3Oag=Fe32EbfYj z;j$hfqFsOMK`V}Uz?W&h>C1UJ?hL_ogM&f}P<|{RNfscjI~GGGvLl(22i~#?lCPX zg!&%2{Vu4t@35?|fDcvAA_L|rTL{5jlDv1a$q}8%la5=D6rS6Rn1?#OngzGC27Zo@@wJR^@lQDS9NJ~hMGCJ5$KEgg1G7#+mSi95vrTaUnyY<-+x9% zqSY)st-qYomsnWroTySoQ9vp@P}lU`TDPirP89fDW96i4Zmxb4bePnkIeh)-cC!JS zFl`=@+pqT6iRM%KsPkyZro*Hrd>6u^ZutCDt2~a>&%06Q^2Y?8M0lrAZ7>hZr|22< zLr0O*mNukjB`~lJ{nYPekY}Dntbwn1oi+SsRQ2qGDar^(>uUNQ)#INb5ra*fYsh3_($r=qn{h*icB_HEW<^3ot zbMpJ^W5yq}W}z1X(5lk#OXowX?jalBMRtzwAb}g>Z3>IugA-lGc>yS@D07xV6pkQ9`e6X+r4j`E#ohZ~t$Z#CYi+<)dh4<`W&a>Y-k8 zI-dQg){3>` zFpm_XKH+qn^C83{$x|j{SgRqxx(rE8UvZokJIkzKXC`O#1zc-zZ|R^NpU;a~!fS6Q zb7QB+=j~cEppbAnqAY{dZ$H|}`6$Elz_!tFsM~C>)9GqYy`Q)T1K}&56iFE+1EZm` zTj-xn#YSGESXw1}%EO9yggy$k6Qm%nQblX@EQ^cj%1cCVSF1yAiHWh26Q}PP)sJ&m z=suMPn*itK@StPN!$TX@r~=F2C;0cjKYHS)_33_XIBfr2fXZLm_t5aGR7~amcSyf504^hM0RQ_cA!zcpyPK(>mnJari*1)OvTB z$jP+Pa@SFlZ+m=GLAL`s?zG)y?>bdVw z_I;e4dn>%u3Wb*hcG13|eR3CnWNBXMylkw|Fnm1J637JA-;^$NHeIzh1m?<^8GjF2 zzi0yr7Yr}436b%XICr=@-m?FMCxl>+jiF>g)Xjb~C0Z+-yD-QQ?SlE3iOUS&Jo%9q zj0?R^PhPh1Rauh>d0VG3D=^3{f_aPl(-v{c)YnJKhj02ayu>$c3mP(=n(o7zB;JtfET&x)(?&fe*<5g~$AXAZ03IgewO zhmlG{HX{&58njEryY%a??gQ7bD&#g~pp>3Ezvp~BYcmFcjqn3n`)*^o#d|#0*S)P%wmA3`gEgmGZ~p6 zx#!5HzTch4+^*c0u217$A$XztE&cG*ftwFs9=aXfJPhImnK1$C;d)qiq|WXtm=$CX z-5+ekeEZ6Q=l+6ct&=p7u@qx*zRSyp>xFMRlR#<9b#lhSZ{W)};ium=UDtJ}+l%Ps z@VhF64`FzSK-$;4>sbMnBLXq%j;oHd6FbXY)3RmGv((&7VNXg7yrGh(pckXLD8`#O z4Z|9*xr*X&CT^FmIPYD?qkw&t6^diShq^Qr8oljSojA(Kb)_|>!w?bg`Fe)7g!SZL zW1_r}jY8xEwhwv@i(jZ5mlcg@;p07Ah_tQPq@Wz}*w6L1=nePiqPl46wh{xAdC_F6 zn~h6+ogSN_S}e_dDwvxq8TYk6&JYfi{!ouN&rD@Zaa4ahj-!lfO({JNZFKb87ibJC z#74uJqb-XfM8IMsx+k3aUE`s*uL6s|N$EII}(`cQB&_cj3e1}%Az9F7=Lyl&knLb z7Itu1((XhT_G>kYoRUXDi1z+$8js)$LQ;QdUOQmH!uJ=&ewyKdMq=I@F?obzkY`Y& z>~FA35~dL!LdSE)y!#sizvQl5%~?DWwforg6VAD{$oOr3>=H@b+uEcnkwvD;J#1|M{Ib{0+1^|AvSAP zPY*uwBizAbH`V#dwS`8~!881jD$*#AXpCgG`*B>PZ#Dvn)T@eGP`9@)4OZXq4F@$pQ0*!&ZlV>RD`*_CQNA)>n}l8!6}*B z(B5SZ+3YkqHZ}6%Y+Gn2$et05+tP_rqjnYO92eet{52%3+4cKpW<_|p6?ipr;VU|t z$)^S&NMewKtR3|L_to15!iQ0a=&tCAv7i>{)Yiob4((`;oE;sZ?5<}_@~}0^8!#&j z&sQP(OXR(46onse+ZZ3!<)_u-Rq5GrshYaKNs}WoD>3G7qv_A_`z@4L=b6r^Zac$Y zmH%3up5J!c$$10a1aqFiQ~`?V!%el&!=kP8pRgcBc`P~MJUKY{#bcbwhjM@>LL!O1 z-h43{Ab?F7kCI_`kPP0(t({QLwLdv;yN3Mw7X1M-;jWE0i(ib%Mbk+)c3FI^SE~qN zOJ{J>9$ue4kSlKVh}jU#Dl6gde$k1v-g@uibZ+Htd0vz^BQ(a)Y<}AnCJd@Fe&Vr4 z7tW@ZwDu+;Q+ZkH$JiF0-sQJhW*a{Uvy9`>+jWcCCs%@35RMk=Q;RBLL~V=RY_Cd6 zyF3+o{V6LAREpmYqk2$x)Sc1KBytSAW$*3x(upk5BJQ~5FnS$P28y%c zn|OYSg5D(9r^D^X8&bT?v@GEyhGhBVr$6A<#UG=rCN;vwjb$a_Ul*a=5D=4|e z$4Ozhn?Y;jKhnhm0*HMQ`8-$X-qBCpqgdB4Jrp^ zxy6?SQBu9E${cHWlDMJg-o7@qwswiViH2SX%tD4h29svupd5@Ac<3xDvYcLbT14D! z15)Ty4dEf&t?dr7XCog}pXo!(Tp=b?h1i#sKJDKJ_^HoB#+6el!?mD*i(xd-AtCi2*X8$0%Drmt@=(n1WJml*JOR2~TR?8Sx zrOaDP=mai*s%dGgSvP+r1FA2%KJ~k-bsWYF+s-bBOruA^|FH6WV)opqw#A?9cYb(? z!0HL{P>^occTlec7lns!Cwbwy%dg?BeeXv)e^T~Ty(zKI;(H~2nT z*xH0%aA|beMDY;t3D8dp3g_$cd}%}@E%<|@O1PCMc2_Hw>*I`Zf2knXD(h{9&?*GPKbTlX$ngS%ADPQ$55ZT-P8 zQ1D~BA$pBzCPl>Mff%5-U^{!&tJ{vB|0r?r5PpY&))Ar^Gi2z4o_j&BU-;-~ls7j7 zB6017|3dLPcVuXYQ~^9_AbwaEh#9Bg$j%Ce3DIw!2SuC4-^>t67uok$X-&Fid!N@f zsToV9 z|C8z^j~Ryv$k+-JI{;d=knUX^a-DuGc20K_JW(|4{xBUv{%fbYpAl^&ci(?fcSh9J z4T*uY_+mH&*Ridask735BUZn|HEWl)#=cYNHP(@&&Zl@UG0?c#IfYHhejcN4`ttcD z{yI^bSZ1XD;#>oixQ#w1Q{r&YB|EFOQg;{0gqUpn6kE0GV)nuv3P3KpI5;@C@kSRNTt=SqZhu69#{a7WGu* z_&|AqLO%_@%}Vg>VZ;8Uix$+)Ysp-lI8{)gIJhE>2>{kpqo*%zDOigu5x68@gv|jt zYRR7O{A{&WvqnXIiXDLy9635&3Bw&f+t>I%L<2*PirM^SqE7pti$cF^WX`I&Za2fi_h8fVTw+;AUPVl6*yg1qU7q)h+nf0G7Ru!ma^ifVF`)5=8Vk|iL}!B^N=XG zD>eDh0$#(ZgJE%|sgmeI_b&rHRB-Wj7346ZN)3d6NtW{%ASFt1hF>lQBA4j5uwXVYUxT zbvwUJZm(!1#;m>d)bJTL6WNL*9mEH%rpdpgdC=R{d{Vr8)_wob5D5F~h@oQNHe^i6 zLXHuSE6o0LYSDh!y@^eZ!8$D~W3W-^Aws!Q$WV`nDq z2pT@;M!=DjG6Q^yL{g<*&6SI#)ax z@Sb@VUoD;Ng~>Z}U{ZS7zqp>Ary&=y+Bfm}*ndPJg>#Hx822^Fo0FBAWPHSD{^O0T zMEpzlgU$VxQjd!68m9CjIo$SgjO)1mcMGAoCW-P=i(b$1>6Dx+9P2>28JPhIno&QR z@+Xv<(ac%D#m2G~jIOa~5@t;cXD_||S4zDo9=O`x@3&C z3a=y!#8@jaWUzZc%@h~2jrb*qn*fk4A7M;~OZ}Uc9p>f*Z%w8sHTozrUk)5DK!Db9 z5KYZohtQZz85=A9-Lrv2G-ry2a4&6_$50wxmm!W*N%5$9?>mvVdKY#<3D<8a$Sk6q zgMYp_bA&*^ZhZtBssC&^H7yFV4FA1-pebr};X&i9h*@7+VartP_-P)4Kb#(}Os!Vl zECKhGw8)+ZepT_X+Qx;1)k`5GHQ=dapYV(`B~3DQYqM(7VO7d?oWhkA&bNy`=FUqh zqdT!$ZLP^{X4IfpdjHTvZozWa+o(Te0Uc6;^z>F4<|VsX7kElA8T?xR#q`8AdT(OJ zk(mHGY=IBa42F@TYF20zpGHt#={CQ&fmq3S*}=~{!-Pgy_tL0Is1y5BjtFB;X|k!& z^|z$Yhw%GnMeJeDI+Kc|rUnk1XZgaZ2HoNMz2F31S<|{?X-8dAn8)+4s3+4V;?q7e zOd}0n@YM?7x9f-iID^h|chJtL0y^~jZjWu#Im;D;EsUcbwgxUNShRo*ie%s4J#+H9%Q(BB*ERv*ZmIn7cz0zZ|oB##L!B46XMG z>}MM*IGu$+3y7->Mb^-~q173Jf_MAl)~{@WBF`yNg8VdbK@+2lkMOz#q(ThhgE`Y& zay-+`pM@H;MHG!KJmn0EY~w$T@}4a#=I{(EYgGqpu6*7W->%+rpKlF&R+=H2^<$Eb zQzpWQNuOJe0fGCT_k<}mL9y1~qw{Uq@c_>GszoW_I4%B84O!oWOAUn*~S6t9f= z=k-$ASZ>l&kJHVq|OweT=Wle)WJKUcQ3id=lJnYDb@b6xgbAIU{YiH|d44FnKY@nfBHR{UQSocW~8Y8bU^)#pTw(08RhCC zqHZvFl#7H;v1A5ZUCU~Vd&2nLA2OVdAn{C5jSmwyWRH!K%!{6VdQn_$^2%L)UAaeT z>+D$@@@70o);tOGVTf-Mp8N+OoT*wKAgeX(B9J__HJL+}1OSZnex|6w>W2!rxsRaJ z%75P}{6~ybj!D+q*_T8jed<*P4u+UJT4gLpuEE*>?D^X6*rV?SoVgkx4eMdQq}b+? z)8=ALq3yWzldOdom(lH?eptfmn(|be=jZ3exPIN00p|w^IVNDCL73bcMXZWT4?#`< zD-4wy9P39yiDXudZbr3`zI#TcT%EJyOQ|%Hp_wY$s7c;s;8A?7U11U$X%ugn%`7KD zWE@SPq5%<@bZqLADKe&M{e7DMJ+0m`A;~~yPT|!bYITvj5#@P~AeXl*uOiNydSY(W zVt6t2-T7bk_E2m9vR=O%_L;bHEqZY+F9yLwV8aWg5%2t&bka2& zAKUk33P*?A@^$LRhgd&at3Iy5lN(sY+@fwwNW$ppLxWB)$9DTey$d$U(HpY!G;C`y zGW661FFIR}1MP)Wk^iu#Y6i#tMHy5Ug3F^t;GvUq_WM4o+L|XNH!W`wyOph(6%0gn z>^Dw}sxCH^r6I<8%|ps4q}3L5E*yi# z2aEih3J^%Rvp%c3D+e7?tAlK;%>wFe`iyL0uc#UKSZnzhhB8$G#J_c&jmT*U?2DB^fTYXOQ4MY^ zOWD>`sswxrDEagRpVt>}toPj3AhtAKtkelzQEp9lxDX4)`DjW3tk2}WPyX3 z{SSq}34BIs(;xN0xNorc$=8p<;!I>rv3T(#!URdZ-s+rAz<}J$4+$>k#M?CCj;$*6 zRCTOySR5>ggY|PneRw8+LJrW{O+o1H%DTH%a)ZQfSc=GnB`e{SNGy1!J-8Wc9q^6| z>*oSVu{N!%gwN_@sU{|1ZEpxeRgy8fqFkC6HzI0HImNC92E8xj>dq#qDH zguyz)VF72+1%&1v6xQ_L{#tFdFL!2wvt8{|j?X!bO@;52=vNBu3v5+Uu=`1&J-2ze z`sruUe`N8rw6W~~+t$xrDO!M6OzzFoQUz>G%VBS&g%z;IQvB$?&JY~?lHF{dLkHD3 z2T|Du%XOucn)fWqdUZKcu<)(D6$#^hjsFpk@{+Tl>R^ALy!X8}hKOYfe;ES6jm>5(K+c&DXlI$fIq^xnbF}0Q) zVD3zQy;%<#o1f@Ub!B6J>HWC&X>4+JuX%PMbmmVV>lXn$0FWP8AN|vtLNmFb_)oTU^e$mZZk+L$-(}`6e@cHYwhjTJx#>SeCd>0Uwqtc;dh~--)t2D zBp#fSeI{Wc)fxZTY_xv{BSuO|(e?5Hqsq4jd!X(gO$!5>wj6w5w2ayOpw!qi%_A}` zt11*2rkgC*G2^wu@#vZzo-(QoFQ4vfA>DVGgbSH-=dI=ExWfJEBHprXQ6m`2sL_w0 zbIbk$F4VE_aQ^`|K4Rjl6ak{!$ECd*mcC?kuu_eoxso_!t;xrcRvlzT)O%P9C;dxc zFyTXaKCl?XhiDdVy8Y)7tN|kwtm2NiQ@`BsVben9cg*Mv%l^3qK3dxhgPFzJ=wkO1 zQWarD*I&PK|8Ftkg}OAW{nZvS@1*F{@b?|v-c+p6YfR{p%Bk_%RuREz{~-5ZIj z$`Fz5duCx3w_0Tl4$)zm+zTbLR`Ar2+}1rNwEhB8=tX_rw0sy1~CaK)!E* zb`#oGvYnLD=sL9SHpHy`FIw@x|EI_T2BPqk1&l@>k7`8h3wZvaVcsv0mAg$FLM{K` z|0`*{rpE13xCn?%A?}8a1a9W ze|r-!LWSOr>~@0-pxi9_J3jBdiiwIVDCE~o5ki%sas49|B*v6(m@A3AosLyR?7vZ? zWrcx6V2)t=f3(-`^lsG@P(Z3eMXdSPt?mt&>!!TaezQC-US%@tzil>xB7r(&|CLCB z3m_3RVEd=rfF1-Zbg&=*{yn{VK##J28~+|n^msZ21(>uD%@1)}|0-nU1f`J5RJJot ziR;w>XL&&Nj|PfHhym|JlKbA|460XyWbZqh@^?4*f&OjCrr7U^6#9QAQWPFbwtHd7 zJSX*khwTMRyVhi&A&9A=nBwB^ckTUQe{%fWQJ*aLsQxu47boC;Fc0;Ii~{w4XEX-Z zk10a7FaJf_e1pMd&iGVO?D$QQyVK^sOyh$@s!E`83;rkQNwVERn{*e|PZ|HXW)b2a zGGA$QEB8;wvAW_R$enMaK#S@>f{K-^^LMKfJ8f?*bZ1gMX{K z!{M0>JG}vl3dQ!{=!o(G-|6Js+5gen6Fq#@K`1bG)uAYhhCgH%j0I4Fs<3`qT!p0@ z{#(Xe3DGS{BK4g89{u9X+^l(b*V*eAMpS(h^O4rdMaD}&8 zA*!D``Gh0JmJw{<(JsQ+)n=xK~6Bpsfw=3vPSq zd^)W-?YLX>%;Gn26Bv@(WS;=1GJX3i7YPa&<7G|Ch#=2z77V)p?|9PC$D+@X{}@6J zgRbFSy0D;QnFVlqIrZqO00yDe4s=#K%E}*%c#A4O-adXt%GkZOZ8PCD=F-Kxg|v;+Y>{|Fq?Vgg$8l1+tmC1s{ zy`pWu7$iD+f)DfkiAa*e0&+KYU(ol^c<0RY|AMP_#h$$+VG5zQUSt?KI|g|3XHl`0 z=#@t^n!e$oR05~y7dVEc~~Zu>GA7<#Z!Nm z!+kt{yVMQ?4twUEMteyvh4-75!ke>R_E`5RIc9u`@BVl)+ceIz4#stCUiWS1cGFkQ zvwvsf^!whw;}qVRxQT-AHJQAdos^2`SMbQ`NqBc_UT4`jt_J|1#c*?fO4O$6J@<0{ z)K+I2;vPPlqoKaQ$DL=`R+mW;gm7guGQc3}#rExto4iCaRvS&v4d)7+G|V<=QU;jCNEwWXTe`wJ!Wou}CfSc;G^5l#TkpBRR zYM@f|0&&TTn16VH#R&Ma{0<^6uB7!u2?nE3etqQsjSQ2T7G8=0C8%{S>beQC=}V|f zw~U?C6Ou_52$wnxzM2rI`7E$Isz`w2nYj;h5i=#;ePbdgTx@Jf6b&)SVNOgulC;gx zH2gt6bA~TfT%kEYvTgYbC!8*&D>^YYoEe1AFg&27NCq-=H2Y_8Zx9+Yys*7p*UN1M zEUE!>KS>C-0qlg|#Q@$yNW<2qw|(VK?Aw8|A3!TR&huA6BqgzmRKRn5m|&rUevZ%W zZ?}P7K9BcQ<{MGQUQ%DwE-NxH5i1I9!~sMW?Bul{*Nq-NDdPj~TP;I1`PLL?aPP)7 zs6H6G?0vI5Ogt=t5k7bxQTAo8QuXSmB4wiy6d7*!I&HO-A|)5OBo@5RL(9TMJtNI8 z7|935#Do-|I}7aFdUb6(7XbFZX?l>ZnhVC^3mPdtw7mnO|7$eH@Iv<^fWWk4-Vs4O8RafeqW z#56d`%>WEud}n5t_-H}|Lq4Ku$eFQzhGPqH8evqTOrV3G#IVjM3clyvtE`_W|F}_* z{^vUoPRsShHK?yJE#Zu&VI!a=T>3Fn5b1p6jABhXn0v5u#`jjmdYqeRB9jQDaxi{( zA+Vn}Z%WUU@9!NZEAHxaQhPB7I`?m?ZQ3-^dx2*rq~DocaqZZFy>uD@4qnw=_9C%V z5(xnz&QV9t?WT)alA$Uvdl{4<*88w9;^xfqXJ&WJ#m~6F zQd%L{1bdnjg00s^;6Wd%VeOkwPs4%EXyEO$+@pOE)`r0sZq!5%I1$@7nY{z5xY(Pl zNvxGOny2tghqf}c(qyYIWo5R(xC9|SJbl}96_>f}1?R(eIrKo+S?aOAzmZ9T3m=# zU>-|BICogGA;Uy}md4-#c05aE*ukT=P<*tL2g5f?U<;(J()xbX|f^nU_c6e$d95g!?h?gFRiSiJpEL4OoHSxjNC}C_L$9QXtaKx8O@3pxh7aHZSiZCc*!uZ6V2vy$4 zI1+3v?t`CGv(Y9-8hhev1Dd8W!XM0CYh$^KRSAaxRx!7ibR67>TpE8m;2Y@sH7H!8 zq5?w$6C(*7ad3QykAl)?TG1)Oc@WJJSrDR%dzIJHRqv?wDUxJ1rTH%?DXJ&<_P@8q z%S3-MnhbUJv6-W4P?sHY=@S<$UAfNf1q6Z0f?M_+D5H20N)Q>dsj6K*fnK-VHH4Q! zSwCq|FNvrroTA_eq?BoMW<~wjaVEr0XE11qqF*j+xR{Uc%BO266QGNnD>@h#JzZs$ zUi%~zCQr2xu@K?9H|Pwc89^(g;ptb$&V;v!Ky8`@=Cc(koBibO@2W-%NRFbKpsPMk zb5^pEwI)*7WftTGX?-JfTj3Epy3n4#V84vmk2L0Wf1k{2!r*1YReXneMb;`;f{48L!>#+-x*oclT)A#BxgRxni6sVPH)X}- z^9YonsPF*6d5j6R{kAe8v}fXio#XtJF}4MDry8`x9yquL}L*VUJeR9~WBTRhs zPvJ<4V2(SzI})*xJ{G3I3K0?Un%my>baJ7r(u6VN zXG9=An?FUeI=lKVd977)lruOGL9F2FP^pk0q>nV3gUc7@nh+uD%=l6 ze8TIxm#UHAe>wY7L#-u-+>ku#CqJ>-+DBfVKnSXc%qn= zsoUZj8SQh==DEa~6qrQX3ba&v_||ZKytlgEul%~d=uLLf#I>9G3|J=32}@dFTPLmI zTOV@N9xzQQkvHzBB7t08cF)_VRc8_z2`U6thRm-R0eCG3GV|rzmo=sncV^>MzLh#j zOI~otBVsZL0V?|CYzZ!ke7-}YK~@>CQyZ6^mmSkzW9S!VMnWmW;uJH;F??*CC?nR^ zG9FT06$E&h^a~a zU(aeL=#5K5ako;y=s7sCTFqbW`ahzkdVbQ8(VNayF&OX~x~k-Cz-aHsin)@R&i4U! zx{}(@3JntxFRf2viVY)iPVW?L#c1;GOM^Z@<4dDyR{CF=K6`DVe|g=G{3wF1iwi*7 zfBoE!2}mfC!ffS_>PZwkIOghI_DJ6HpPb#X0LevC}!^bh^oc4gdf^k_>=tH=0 zXkc+*8Oa8e2qTnJY_ly8H?`4ccWISz#RCtZ9({@gMP!!O8_c+VeDCG*glroSdn`Nu zg&9USgc%0r0Tt!nmqK_U6agn)SHuCm@|7RT%r1&cE41|fEG31{Hq9i427()lUOJkb z&twIHO8>t$?m8~2rf(QH-OUoxjdV-6bO}p?(nv^2NeW2I(v1s9tkNJ#E+K++BS;8J zcZdSJsIUU^9PanIgzJ9Z&xgN;vu9`K%$eVuo$vYilgeov!$U@8dKLy}hb87>Ww>

zJUhBwEv%`we{?EF8P&sL-KNfY7r7_s$Cv%w+wf{c1hGm(oC_Ok_mR)4l-<>eA0?tz%xPCS_dXLg%3CClj3RH5sZwK@kRBSq!OlLUV7p$dZ z0r~jpi+8cV@#E*~ckO#5MhdK;a?zboEpg5x&uz93tr|pb{CsPL_8HFNsAO-_d2WVv zhGu^p4Nodo?{`h<*}s3XtdKgAkjLOZYdJB9&*q;Bw3)%D3}6}v&7w_~EuktCZ3c<~=RKoKvg4{z_u^l*>ufL&4w%m2V8RP;GXoz5R=aK-f~&CX z-}OHfC#(9P$Z8PN+eR+2=#`@;OcnZ!^clCf2e11NxfPFfYF+zg%jf>;3=9Ut&d7W* zy&8QyOa|Sc;#n0p@%_-nsFLnf+_(H$O$79(6F+j_S-|{0ZDOZGgeE+R8~SUXNgjdh%lgDYh>ae%XX=yW65(>~(7^agTw&gc)PO*HZejnjbj$as9w_TRTkG#p4qvot^o;3Mr*J{>+(YJ5gqiGp_ai4XA^}tlHDLDB%VIOIvpJrxFr@E+^DGr}LZ$J)Zk^?$JDG(x#oQ^ye3~(WUFtz@#eRTArH*tH3j#p!-z`zhp&=~ zvh}y8l^*eT-ej`JRW%da2$QTc%x`$hC1m0<%vq9Ir)mzZ@`BY> z*O^h>Oo$~()r{A+bTFtuxOg1p4J%(1XjC;ngMYSG+RU)Dtcy}wVXDuk>7cw9CtFP@ zklbi@d$py;X!9h;?H8l>y)2(2wz7OqP5c-WSvB;Dx+(KGfmdl34h?ucl)ta%7D~TaBWfRidj)=zRehCeean3F#^(EsX4ow_ zJ4zvD(5MZtGI|R91=y>dywWI)+3wiwXi=~iYP5el3z5!3zd25{U4q%!uJn>kO>F-L ziy#9A7~2XvnFkeQ8JS;h-VtxP%_pBnH0w0<(}4=bu>EE0GnnK!73`j;g9SDQg4vIy z0dHOe3*V2M&-j?$BKdcmk5I(}JOSt*nRrCu{al6>Ym^Bb6yyvnY~2PcMzRgnWu3%mm`z+j4)O}XUXm_$+!{m-hrG3#z z!f>=UB~sb!t~e6h@OG>*6MnNE7|L?9UG17y83EOr_AeRB!RLV~6yy>f3v@V)SUBEA zA=7>~{LXN@eO5HH2un9bO$}H@cfHv@zji%rE9P^$ZQ|)la-7hOO@eLO`|{(u;|UCS zR`}!0yW0xv`;^WLs@0f0lC;_^9Y%7wP2S*L-sM|C;dv<^ntcm$hWXlT-7~jIX%}(Y z;R0)eM+};cF*0xqIlQX-TtN@LduQj?96`sB%+C z8;F$#WFNr|m7sA4Sy<7{YICb#e)-YFimSld%K&3t&myQ%Y4qEF`?>7N9qvz6YiW;F z;N+#!!NRNRr4XB!D&0r;kTBz2!%AP_mWfi_;HjvtLm;#YHom*W3adPoenprW@LDezh(ok04_rB9LuBg+?>8hy2z)p#!$WV ze$o4Qq0Arkw8bsHWf=FVTIhRgWUZQ+mJ-s3fJGY|4lWK18U!3kKoWqI1EoBZPv^Jb zQhj{^o6?ICAMEwb?>y!kC*Lk)O3+Ygy?}_f8 zw0&gf-0;E+c<0BzVwlq=5wtpe%d^cJ6agCZ=I9Irvk-xAA({xw6Qa1GJP>}o*2J9* z&JYD9aKCi+-UK!;`(17FV`FP(6Wh9~M1OuKk_lZi9Q-8`=BKJ4^ya?|dX#nE;-D7^BK5OmL(5lyGu z*G@s6;#@5k1PktqrNgV6nV~S(U6+2_KN$7Ic$gJwb*M3o97X0+vJ|Sb^yYo~C1;NoM7bD+6;BL!frB3@f1IqHsI&6gO&)LBebj>1ViO@A zWTdq?IZD#9{Xmlx zgMeYnEoQp6x1cv3ykj7K)%MmoZmp@mF^l0=Z@J8TulgTVvz5XL2otztF`72Wa4|C} zoU4QFmliqvtw6?O0kf6&uq;BG$yXGIkY86$^(XAEi_x zS)kMd9G$>MBTbr`X1mxahp<`(|EQIpL8Jkiy}p715|wotZx~@PBpF}$ZTe04T7e44 zTfQ_wj}o~>znxVM!knCLS)m8hn2qNBj1fC8^6vJm% z2!@YgVe2;%;c%mzmSoAyjv-EP%~vNbk|N^5Pv4jNTh`>p)!n&_Zl&L9Wk)KIigU5| zkGH~E;f*}&3^zx1oXQJ}_sxfe83YzlcE``f zv+c&3Otch5HE+0Uetq(h78Sd|+p-FTYDOFn?g zKTSLtnbKuBaM}ou7p%@Z8wwh{Sa4`PjLZ9u3`w9q5N0|GUAXPBK6lp!296}KMll`V z(E%w!QU=~>EtLwYKH%S{AKN3&#vsiI93Q$5{K(ltDpp5)+%)mi}&}8P(5aoJvckm_>gw$Z$d6<9taICV zC+M+Nx#Lai^K26bel!T%b&18@jQ0+M*w*Vs#@y^1*aoLhl} zEJz2TPprkwP^0WwTqk#8hh^WRy^TC-xVMs)VmxGmd;y%rB%-%+uw&l+IB-2q^KCW_(&bw@HX|0|o*tQ?TIoN|trdZ%(=y@eW*SyZd?@TT zTdla`VrN8X)VZO-9-X$*6X9+V&oH9CssUBC%XVG>!_hzT+|;=?tpi%|Xf_VxYCaer za_XU%Wn_$R7%0aDkq|#_y|5jOjk*ux9?>5bEaM#I@1v-VaAKy2q)fI>9Y9C5F2uX7W|-V}*y&#d-Hh zaXrSf*u>NR28xv8!#0j&bc8do_-@spVQA^jdQG>ExNwz{~6(%9Xux=locbr2#4;!ai4;)`5L13fD>)i zw(y3e7iA8%U78w8F^oY(-UIV*HvGrttH4G~78ztH5%2EC7e1!mf+gHR;RfqAD+Q*{ z)vS7YrCsELnKg5F+S&E_LLEd96*ze;Z8mhHVJwos_BTKS47~Hb`)~X_pse-%pX9u?+Sh~ylW)*B``woRD&unvh{f<%WKi-#YB44WV74P){YYN|_7IJ!azKJlSA%dr+h5VCNT@D` zJ}q!KTL5Fq(cP)LaV-hAnp7aKXj)p4a{o{>oy{zNq~}8TJEY@A zE7{e*Y4I>+BiBBSDt1`uv|l$wIt0&xzX&4wH@0MM{2dfWc@Z(v-ZWI!z#{S#F8A~A zKO9sdI#$vv87EXAYS+CGJAq4-zj~x8Amb$eUB1$n!JFt}*8G3Dmeq^jA0|}sDVxjcIzx~^ZqoD&lCG{#X7yNUw&IeS3 z%W~0C(3uBYxc3|X7RM2?AtX7$hEG`DP+|x8{cTz%ge`pUgLlbzD+PtRghn^ zca)t^VTnTe2W)az-X^D$0*Asp=(rF%L!lH}@lUlQ2;(|4xFLu+a|;)LgTTIj1{Og3 zcx!z&wI4H+rHpG{At5D+$dC|P_U{u9w>GbCcAk&9oojuG@)}iALipDJqXNNev$}5U z*w8~CgR4Gv(e3nNZqnF{xN08Y0Ye_*r~IOS^M_vUFPe-Xl%yKO@3nN1DngN6`@Fs_ zkZsEtujjObY`($wx{cFf3r3hVYgX}!<6qIJ$R!*w{d;N7*lR_R1ZrMc9RJPJ*a3n? ziaCDGNdd23!j}penGYoXQ8bq<^Khn6r)aNBXm0%)Ak0x(#yKHodEQDXgi!1KJHG)E zG72M{pZUX)i#o$KAqkx3atuQzJ{NOS{rfsy+Du2MKsA7!{@1m-1Z5r&g!tIVrD?W=PQb3ipZo{AS%U0^;5sva>_G4cr90C%UdEE5?n8{rQ1>1Yn>zV(V@CgV--@E?& zWLh(0^W=N5Yct=?6K_MBM;KWJ^C97-uo}vZFEA@5T>GXT^3lXgVxyu>q#dmr6`7(~!7E&nTv$dKn`OjKAgqjlw5vo#I z?B#gtB4MUB=BmuIKV+?WM5}RjRQ_LZRN;*H*a`@mf#3Ca93=G*C@$qIEkWexTno1B zjgia26q(!ElI=wx)C+TeEpL$|79W4Ns2v#pJ9@U~KW7hEI-gwD(w2oviCT2AM`j+i zIa2P&oYJW2*1Q<7*EZwYB{lYC*p*Ql%hId;XAAex?j`<ni%evJ~}GIUNbFE5YL>f zZ(r`brVpx;$(G0gUglL*&HL7XzCx0t#E*S}u2`9RO4M1Xd;`({gjibz>X+}gRfA$W zbIE%+wB;OMJI9#f+3CF@7H)aj`sepv)n#_6ymraRc;4CvLm3YX{AViLJLWy#y;+_v zIAOBG;Hj+zUVH%%)tkEG2kKve!=E@8`A5$Jo)3xD=J`+H0ag@uBKi-;ZXYaAT9kNy zjV52ud00MlHS26)Vz$bzQ}BW8U@&7ZdXGnj^ z$IKf4bpwkc?-vPg4?9~d%#$KC&Sa1UO40tAfuF!r*UW-*aFTJpkB7xJ%E`^_@ zHCV5K>nXw${nBy?B<)q*=m{~~%uo;bRQ`_%?i_{*>^)zVQW)`KCi{1faJ}q0L_I{m z>A5p-wRYkW<-kHce7pBZO^G@ADzIz-8rz5C&$Y&=QW;#vpES16maD^*fcJ*|A2X|T zIbF4ylY;`9HS>LffznFT;h$pBFE~GD3fs&-)_%5#Gtj9N(+2?^^HIDm8@d~8$Am@DQdFX{d0O-tSN$u5d#R8nTu}E#^ucP zzkeSUF@x$5TzJH9{>c6&xazmPPZ&+?XN8zYA5Jm*M|`*yJc6mVH5AJAOyo zc5@gu^=rOZiZuQj{8hTZnYOOr76Y%We^nH|ULl^^1dL4B!)_z;n8!`mf)^!KXQKa{ zYq|f{xY6{!9EkAxnm`FFY5a2f-gfb41!8*IzhXLPCu8iam9OqVap}G)Aj<=P-@Izj z4n^lv=*Qs?DgwM~%h%e^iy1vrnr&n81Oe#s1WBbOiz@vrvTOG=GZx^*tM>uK`4zC3 zyY5rNMHQ`xiEANHG%^6^-fJ_%(1Rz-Rr`SN7^4?re(QopZ5CXtPiS1LewOwH6j*_4MS>Vc8HMA_LNuI3S)m-3ix z=A$p5Sw*p;bmqN?9meGo4f((-M8kO{)3tksClO;V9`kVdY)iVl-Qy-z;-M3>@2D6{ z`M+#5aC7E1uI>QI%bws-S_iiHR4vPa5894iJ#OE#Mk`zyTi_}U60lV~GGTta;Qa|` z=seO17K~3<17z15s9(?b9jlzNe!Teb;`~^Izy2H3pTFGK7K>UFcx(}&1abhrs8T@2 z>rZj`>UfP2z971)o7nC>&xwy ze8pxxQ3~B%RHMa|V-X5_bm&@MaBneq@6D&nT$;#X`^t{=+JDlU0(H&-VNI&~(S@C@ zv(|`MlJN;a1k27Y$h4C?f%JTIuQ*d=idt8qhy@Ya(`|oy8CVu5SrsPk@Na~ZkSm@Y ze%;8_uWr_|a{Yqi&?wZrP%oio^Dvp4l_Ts|!wYNXppEoTGnQV~>D)LZl>=nv;zY%Zy`BW0Ixtb7qkJr8eSxx1CPo!3p-Tqel6@ZF9 zjr|O6)4c2?yqqK>fr6**R|6J^;U(5P6RK)r4~W(ki93!84ou4PeYE9Ez5?cZk0jVx zaiFoWS|#xg7o5WQHIOef_mkf3?O|)t}Zs z&tLxr@;B+%c(x(?AAYHK{B+mU`mVL#gu1^pyL}=mqFy<-h?chMz4kon+}~#S9hpDd z?c&|XR{cNe@9oX$=UV_7xF9JbspH|z$yKH@1yy`j@9%dsPJ93UK$W=b$ZVX`0{5!I zE~^Oy&!d*T^M1MBICd>?3=@VrSDydW{yq7=Y}ws3C*-oUbo@f;eTtwD&$pi5ACdQ` z!Usf&svH-}{j<<-LGaRFvjV%2)7-EIYdh3`N)+5xCpA}2cUq!!hcy>>SCV(dkjrOILEAMt43MkF?XD&bYW<7%9}Oa_35c>$C|^J5zvL`?6My`ud@6!6HLFy{iQ`>SjK7U^nl@MOPHQ-dcBSi`!6B1}r6h-cJW8 zK9UaKB+nYAdo8f+dcAzR1Dbi^r~h^t$V+$8=)sdcY-!;mJo!mLv02NQ#ktwxH(^!a zT$w~ima7*tzlxB9J>t!5{dX~Ko%zG|v8rdD#|7jrt!{uLi*Y literal 0 HcmV?d00001 diff --git "a/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/q_progress_bar.py" "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/q_progress_bar.py" index b4d9408..fd73976 100644 --- "a/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/q_progress_bar.py" +++ "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/q_progress_bar.py" @@ -1,10 +1,9 @@ -# -*- coding: UTF-8 -*- -# 作者:huanhuilong -# 标题:Python PyQt 进度条(2) -# 描述:请先完成上一题。封装一个能显示进度条的 PyQT GUI 对话框 import sys +import time import math -from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QProgressBar, QVBoxLayout, QMessageBox +from PyQt5.QtWidgets import QApplication, QWidget +from PyQt5.QtWidgets import QPushButton, QProgressBar +from PyQt5.QtWidgets import QVBoxLayout, QMessageBox from q_progress_thread import QProgressThread @@ -16,7 +15,7 @@ class QRunnerProgressBar(QWidget): self.vbox = QVBoxLayout() self.btn = QPushButton(tip) - self.btn.clicked.connect(self.btnFunc) + self.btn.clicked.connect(self.on_btn_click) self.vbox.addWidget(self.btn) self.pbar = QProgressBar(self) @@ -30,19 +29,20 @@ class QRunnerProgressBar(QWidget): self.count = count self.runner = runner - def btnFunc(self): + def on_btn_click(self): self.thread = QProgressThread(self.runner) - self.thread._signal.connect(self.signal_accept) + self.thread.connect(self.on_progress) self.thread.start() self.btn.setEnabled(False) - def signal_accept(self, info): + def on_progress(self, info): percent_value = int(math.floor(info.progress*100/self.count)) self.pbar.setValue(int(percent_value)) self.setWindowTitle(info.msg) - if self.pbar.value() == 99: + if self.pbar.value() == 100: self.pbar.setValue(0) self.btn.setEnabled(True) + self.setWindowTitle('QRunnerProgressBar') def closeEvent(self, event): self.thread = None @@ -50,9 +50,15 @@ class QRunnerProgressBar(QWidget): if __name__ == "__main__": app = QApplication(sys.argv) + + def on_run(emit_progress): + for i in range(0, 5): + time.sleep(1) + emit_progress(i+1, f'Python技能树->PyQT:{i+1}/5') + p = QRunnerProgressBar( - 100, - '看资料+做题,就有技能树进度', - lambda on_progress: on_progress(50, 'Python技能树->PyQT') + count=5, + tip='看资料+做题,就有技能树进度', + runner=on_run ) sys.exit(app.exec_()) diff --git "a/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/q_progress_thread.json" "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/q_progress_thread.json" index 007ac82..e91769d 100644 --- "a/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/q_progress_thread.json" +++ "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/q_progress_thread.json" @@ -1,23 +1,8 @@ { - "one_line": { - "self._signal.emit": [ - "self.emit" - ], - "QProgressThread, self": [ - "self" - ], - "sys.exit(app.exec_())": [ - "" - ], - "QApplication.quit()": [ - "sys.exit()" - ], - "p._signal.connect(on_signal)": [ - "p.connect(on_signal)" - ] - }, - "source": "q_progress_thread.py", + "source": "q_progress_thread.md", "depends": [], "exercise_id": 233, - "type": "code_options" + "type": "code_options", + "author": "huanhuilong", + "notebook_enable": true } \ No newline at end of file diff --git "a/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/q_progress_thread.md" "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/q_progress_thread.md" new file mode 100644 index 0000000..114143e --- /dev/null +++ "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/q_progress_thread.md" @@ -0,0 +1,156 @@ +# Python PyQt 进度条(1) + +使用 QThread 发送信号,接收信号一方打印并结束程序。程序的打印结果如下: + +accept info from signal: Hello PyQT world:0.0! +accept info from signal: Hello PyQT world:0.2! +accept info from signal: Hello PyQT world:0.4! +accept info from signal: Hello PyQT world:0.6! +accept info from signal: Hello PyQT world:0.8! + +使用 QThread 和 pyqtSignal 完成该功能: + +```python +# -*- coding: UTF-8 -*- +class QProgressThread(QThread): + _signal = pyqtSignal(ProgressInfo) + + def __init__(self, runner): + super(QProgressThread, self).__init__() + self.runner = runner + + def run(self): + # TODO(You): 请在此实现运行代码 + + def connect(self, on_signal): + # TODO(You): 请在此实现绑定信号事件代码 + + def __del__(self): + self.wait() + + +if __name__ == "__main__": + app = QApplication(sys.argv) + + def on_run(emit_progress): + for i in range(0, 5): + msg = f"Hello PyQT world:{i/5}!" + emit_progress(i, msg) + + p = QProgressThread(on_run) + + def on_signal(info): + print("accept info from signal:", info.msg) + QApplication.quit() + p.connect(on_signal) + + p.start() + sys.exit(app.exec_()) +``` + +请选出下列能**正确**实现这一功能的选项。 + +## template + +```python +class QProgressThread(QThread): + _signal = pyqtSignal(ProgressInfo) + + def __init__(self, runner): + super(QProgressThread, self).__init__() + self.runner = runner + + def run(self): + def emit_progress(progress, msg): + info = ProgressInfo(progress, msg) + self._signal.emit(info) + self.runner(emit_progress) + + def connect(self, on_signal): + self._signal.connect(on_signal) + + def __del__(self): + self.wait() + + +if __name__ == "__main__": + app = QApplication(sys.argv) + + def on_run(emit_progress): + for i in range(0, 5): + msg = f"Hello PyQT world:{i/5}!" + emit_progress(i, msg) + + p = QProgressThread(on_run) + + def on_signal(info): + print("accept info from signal:", info.msg) + QApplication.quit() + p.connect(on_signal) + + p.start() + sys.exit(app.exec_()) +``` + +## 答案 + +```python +class QProgressThread(QThread): + _signal = pyqtSignal(ProgressInfo) + ... + def run(self): + def emit_progress(progress, msg): + info = ProgressInfo(progress, msg) + self._signal.emit(info) + self.runner(emit_progress) + + def connect(self, on_signal): + self._signal.connect(on_signal) +``` + +## 选项 + +### A + +```python +class QProgressThread(QThread): + _signal = pyqtSignal(ProgressInfo) + ... + def run(self): + def emit_progress(progress, msg): + info = ProgressInfo(progress, msg) + self._signal.emit(info) + + self.runner(emit_progress) + + def connect(self, on_signal): + self._signal.Bind(on_signal) +``` + +### B + +```python +class QProgressThread(QThread): + _signal = pyqtSignal(ProgressInfo) + ... + def run(self): + self._signal.emit(self.runner) + + def connect(self, on_signal): + self._signal.connect(on_signal) +``` + +### C + +```python +class QProgressThread(QThread): + _signal = pyqtSignal(ProgressInfo) + ... + def run(self): + progress, msg = self.runner() + info = ProgressInfo(progress, msg) + self._signal.emit(info) + + def connect(self, on_signal): + self._signal.connect(on_signal) +``` diff --git "a/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/q_progress_thread.py" "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/q_progress_thread.py" index 5eb7590..dab3f9a 100644 --- "a/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/q_progress_thread.py" +++ "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/2.PyQT/q_progress_thread.py" @@ -1,7 +1,3 @@ -# -*- coding: UTF-8 -*- -# 作者:huanhuilong -# 标题:Python PyQt 进度条(1) -# 描述:使用 QThread 发送信号,接收信号一方打印并结束程序 import sys from PyQt5.QtCore import QThread, pyqtSignal from PyQt5.QtWidgets import QApplication @@ -20,27 +16,33 @@ class QProgressThread(QThread): super(QProgressThread, self).__init__() self.runner = runner - def __del__(self): - self.wait() - def run(self): - def on_progress(progress, info): - info = ProgressInfo(progress, info) + def emit_progress(progress, msg): + info = ProgressInfo(progress, msg) self._signal.emit(info) + self.runner(emit_progress) + + def connect(self, on_signal): + self._signal.connect(on_signal) - self.runner(on_progress) + def __del__(self): + self.wait() if __name__ == "__main__": app = QApplication(sys.argv) - p = QProgressThread( - lambda on_progress: on_progress(0, "hello PyQT world!") - ) + + def on_run(emit_progress): + for i in range(0, 5): + msg = f"Hello PyQT world:{i/5}!" + emit_progress(i, msg) + + p = QProgressThread(on_run) def on_signal(info): print("accept info from signal:", info.msg) QApplication.quit() + p.connect(on_signal) - p._signal.connect(on_signal) p.start() sys.exit(app.exec_()) diff --git "a/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/3.WxPython/config.json" "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/3.WxPython/config.json" index d6f93ab..dfdbde2 100644 --- "a/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/3.WxPython/config.json" +++ "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/3.WxPython/config.json" @@ -1,6 +1,7 @@ { "export": [ - "event.json" + "create_window.json", + "create_panel.json" ], "keywords": [], "children": [ diff --git "a/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/3.WxPython/create_panel.json" "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/3.WxPython/create_panel.json" new file mode 100644 index 0000000..8222359 --- /dev/null +++ "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/3.WxPython/create_panel.json" @@ -0,0 +1,8 @@ +{ + "source": "create_panel.md", + "depends": [], + "exercise_id": "bad097def1a54b009ee7f5b0f73b3b1f", + "type": "code_options", + "author": "huanhuilong", + "notebook_enable": true +} \ No newline at end of file diff --git "a/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/3.WxPython/create_panel.md" "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/3.WxPython/create_panel.md" new file mode 100644 index 0000000..5efbb73 --- /dev/null +++ "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/3.WxPython/create_panel.md" @@ -0,0 +1,159 @@ +# Python WxPython 例子 + +继承上一题的 BasicFrame 增加功能 + +1. 创建面板 +2. 添加 “Hello World” 文本 +3. 添加一个 “Close” 按钮 +4. 绑定关闭事件 + +```python +# -*- coding: UTF-8 -*- +import wx +from create_window import BasicFrame + +class PanelFrame(BasicFrame): + def __init__(self, title, pos, size): + super().__init__(title, pos, size) + self.init_panel() + + def init_panel(self): + # TODO(You): 请在此实现代码 + + +if __name__ == '__main__': + app = wx.App(redirect=True) + top = PanelFrame( + title="Hello World", + pos=(150, 150), + size=(350, 200) + ) + top.Show() + app.MainLoop() +``` + +请选出下列能**正确**实现这一功能的选项。 + +## template + +```python +import wx +from create_window import BasicFrame + + +class PanelFrame(BasicFrame): + def __init__(self, title, pos, size): + super().__init__(title, pos, size) + self.init_panel() + + def init_panel(self): + panel = wx.Panel(self) + box = wx.BoxSizer(wx.VERTICAL) + + m_text = wx.StaticText(panel, -1, "Hello World!") + m_text.SetFont(wx.Font(14, wx.SWISS, wx.NORMAL, wx.BOLD)) + m_text.SetSize(m_text.GetBestSize()) + box.Add(m_text, 0, wx.ALL, 10) + + m_close = wx.Button(panel, wx.ID_CLOSE, "Close") + m_close.Bind(wx.EVT_BUTTON, self.OnClose) + box.Add(m_close, 0, wx.ALL, 10) + + panel.SetSizer(box) + panel.Layout() + + +if __name__ == '__main__': + app = wx.App(redirect=True) + top = PanelFrame( + title="Hello World", + pos=(150, 150), + size=(350, 200) + ) + top.Show() + app.MainLoop() +``` + +## 答案 + +```python +class PanelFrame(BasicFrame): + ... + def init_panel(self): + panel = wx.Panel(self) + box = wx.BoxSizer(wx.VERTICAL) + + m_text = wx.StaticText(panel, -1, "Hello World!") + m_text.SetFont(wx.Font(14, wx.SWISS, wx.NORMAL, wx.BOLD)) + m_text.SetSize(m_text.GetBestSize()) + box.Add(m_text, 0, wx.ALL, 10) + + m_close = wx.Button(panel, wx.ID_CLOSE, "Close") + m_close.Bind(wx.EVT_BUTTON, self.OnClose) + box.Add(m_close, 0, wx.ALL, 10) + + panel.SetSizer(box) + panel.Layout() +``` + +## 选项 + +### A + +```python +class PanelFrame(BasicFrame): + ... + def init_panel(self): + panel = wx.Panel(self) + box = wx.BoxSizer(wx.VERTICAL) + + m_text = wx.StaticText(panel, -1, "Hello World!") + m_text.SetFont(wx.Font(14, wx.SWISS, wx.NORMAL, wx.BOLD)) + m_text.SetSize(m_text.GetBestSize()) + box.Add(m_text, 0, wx.ALL, 10) + + m_close = wx.Button(panel, wx.ID_CLOSE, "Close") + m_close.Bind(wx.EVT_BUTTON, self.OnClose) + box.Add(m_close, 0, wx.ALL, 10) +``` + +### B + +```python +class PanelFrame(BasicFrame): + ... + def init_panel(self): + panel = wx.Panel(self) + box = wx.BoxSizer(wx.VERTICAL) + + m_text = wx.StaticText(panel, -1, "Hello World!") + m_text.SetFont(wx.Font(14, wx.SWISS, wx.NORMAL, wx.BOLD)) + m_text.SetSize(m_text.GetBestSize()) + + m_close = wx.Button(panel, wx.ID_CLOSE, "Close") + m_close.Bind(wx.EVT_BUTTON, self.OnClose) + + panel.SetSizer(box) + panel.Layout() +``` + +### C + +```python +class PanelFrame(BasicFrame): + ... + def init_panel(self): + panel = wx.Panel(self) + box = wx.BoxSizer(wx.VERTICAL) + + m_text = wx.StaticText(panel, -1, "Hello World!") + m_text.SetFont(wx.Font(14, wx.SWISS, wx.NORMAL, wx.BOLD)) + m_text.SetSize(m_text.GetBestSize()) + box.Add(m_text, 0, wx.ALL, 10) + + m_close = wx.Button(panel, wx.ID_CLOSE, "Close") + box.Add(m_close, 0, wx.ALL, 10) + + panel.SetSizer(box) + panel.Layout() +``` diff --git "a/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/3.WxPython/create_panel.py" "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/3.WxPython/create_panel.py" new file mode 100644 index 0000000..efd049e --- /dev/null +++ "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/3.WxPython/create_panel.py" @@ -0,0 +1,40 @@ +# -*- coding: UTF-8 -*- +# 作者:huanhuilong +# 标题:Python WxPython 例子 +# 描述:创建窗口、菜单、显示文本,关闭 + +import wx +from create_window import BasicFrame + + +class PanelFrame(BasicFrame): + def __init__(self, title, pos, size): + super().__init__(title, pos, size) + self.init_panel() + + def init_panel(self): + panel = wx.Panel(self) + box = wx.BoxSizer(wx.VERTICAL) + + m_text = wx.StaticText(panel, -1, "Hello World!") + m_text.SetFont(wx.Font(14, wx.SWISS, wx.NORMAL, wx.BOLD)) + m_text.SetSize(m_text.GetBestSize()) + box.Add(m_text, 0, wx.ALL, 10) + + m_close = wx.Button(panel, wx.ID_CLOSE, "Close") + m_close.Bind(wx.EVT_BUTTON, self.OnClose) + box.Add(m_close, 0, wx.ALL, 10) + + panel.SetSizer(box) + panel.Layout() + + +if __name__ == '__main__': + app = wx.App(redirect=True) + top = PanelFrame( + title="Hello World", + pos=(150, 150), + size=(350, 200) + ) + top.Show() + app.MainLoop() diff --git "a/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/3.WxPython/create_window.json" "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/3.WxPython/create_window.json" new file mode 100644 index 0000000..1cfc22d --- /dev/null +++ "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/3.WxPython/create_window.json" @@ -0,0 +1,8 @@ +{ + "source": "create_window.md", + "depends": [], + "exercise_id": 0, + "type": "code_options", + "author": "huanhuilong", + "notebook_enable": true +} \ No newline at end of file diff --git "a/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/3.WxPython/create_window.md" "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/3.WxPython/create_window.md" new file mode 100644 index 0000000..5e6711b --- /dev/null +++ "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/3.WxPython/create_window.md" @@ -0,0 +1,179 @@ +# Python WxPython 例子 + +使用 WxPython 创建窗口、菜单、添加关闭事件,请完成功能: + +1. 创建一个菜单栏 +2. 在菜单栏里添加一列菜单,并提添加一个关闭条目 +3. 绑定关闭条目的关闭事件 + +```python +# -*- coding: UTF-8 -*- +# create_window.py +import wx + +class BasicFrame(wx.Frame): + def __init__(self, title, pos, size): + wx.Frame.__init__(self, None, title=title, + pos=pos, size=size) + self.init_close_event() + self.init_menu_bar() + self.init_status_bar() + + def init_close_event(self): + # 绑定关闭事件 + self.Bind(wx.EVT_CLOSE, self.OnClose) + + def init_menu_bar(self): + # TODO(You): 请在此实现添加菜单逻辑 + + def init_status_bar(self): + # 创建一个状态栏 + self.statusbar = self.CreateStatusBar() + + def OnClose(self, event): + # 创建确认关闭对话框 + dlg = wx.MessageDialog( + self, + "Do you really want to close this application?", + "Confirm Exit", wx.OK | wx.CANCEL | wx.ICON_QUESTION + ) + + # 显示对话框 + result = dlg.ShowModal() + + # 销毁对话框 + dlg.Destroy() + if result == wx.ID_OK: + # 销毁窗口 + self.Destroy() + +if __name__ == '__main__': + app = wx.App(redirect=True) + top = BasicFrame( + title="Hello World", + pos=(150, 150), + size=(350, 200) + ) + top.Show() + app.MainLoop() +``` + +请选出下列能**正确**实现这一功能的选项。 + +## template + +```python +import wx + + +class BasicFrame(wx.Frame): + def __init__(self, title, pos, size): + wx.Frame.__init__(self, None, title=title, + pos=pos, size=size) + self.init_close_event() + self.init_menu_bar() + self.init_status_bar() + + def init_close_event(self): + self.Bind(wx.EVT_CLOSE, self.OnClose) + + def init_menu_bar(self): + menuBar = wx.MenuBar() + menu = wx.Menu() + m_exit = menu.Append( + wx.ID_EXIT, + "E&xit\tAlt-X", + "Close window and exit program." + ) + self.Bind(wx.EVT_MENU, self.OnClose, m_exit) + self.SetMenuBar(menuBar) + + def init_status_bar(self): + self.statusbar = self.CreateStatusBar() + + def OnClose(self, event): + dlg = wx.MessageDialog( + self, + "Do you really want to close this application?", + "Confirm Exit", wx.OK | wx.CANCEL | wx.ICON_QUESTION + ) + result = dlg.ShowModal() + dlg.Destroy() + if result == wx.ID_OK: + self.Destroy() + +if __name__ == '__main__': + app = wx.App(redirect=True) + top = BasicFrame( + title="Hello World", + pos=(150, 150), + size=(350, 200) + ) + top.Show() + app.MainLoop() +``` + +## 答案 + +```python +class BasicFrame(wx.Frame): + ... + def init_menu_bar(self): + menuBar = wx.MenuBar() + menu = wx.Menu() + m_exit = menu.Append( + wx.ID_EXIT, + "E&xit\tAlt-X", + "Close window and exit program." + ) + self.Bind(wx.EVT_MENU, self.OnClose, m_exit) + self.SetMenuBar(menuBar) +``` + +## 选项 + +### A + +```python +class BasicFrame(wx.Frame): + ... + def init_menu_bar(self): + menuBar = wx.MenuBar() + m_exit = menuBar.Append( + wx.ID_EXIT, + "E&xit\tAlt-X", + "Close window and exit program." + ) + self.Bind(wx.EVT_MENU, self.OnClose, m_exit) +``` + +### B + +```python +class BasicFrame(wx.Frame): + ... + def init_menu_bar(self): + menuBar = wx.MenuBar() + menu = wx.Menu() + m_exit = menu.Append( + "E&xit\tAlt-X", + "Close window and exit program." + ) + self.Bind(wx.EVT_MENU, self.OnClose, m_exit) + self.SetMenuBar(menuBar) +``` + +### C + +```python +class BasicFrame(wx.Frame): + ... + def init_menu_bar(self): + menuBar = wx.MenuBar() + m_exit = menuBar.Append( + wx.ID_EXIT, + "E&xit\tAlt-X", + "Close window and exit program." + ) + self.Bind(wx.EVT_MENU, m_exit) +``` diff --git "a/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/3.WxPython/create_window.py" "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/3.WxPython/create_window.py" new file mode 100644 index 0000000..a899473 --- /dev/null +++ "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/3.WxPython/create_window.py" @@ -0,0 +1,55 @@ +# -*- coding: UTF-8 -*- +# 作者:huanhuilong +# 标题:Python WxPython 例子 +# 描述:创建窗口、菜单、显示文本,关闭 + +import wx + + +class BasicFrame(wx.Frame): + def __init__(self, title, pos, size): + wx.Frame.__init__(self, None, title=title, + pos=pos, size=size) + self.init_close_event() + self.init_menu_bar() + self.init_status_bar() + + def init_close_event(self): + self.Bind(wx.EVT_CLOSE, self.OnClose) + + def init_menu_bar(self): + menuBar = wx.MenuBar() + menu = wx.Menu() + m_exit = menu.Append( + wx.ID_EXIT, + "E&xit\tAlt-X", + "Close window and exit program." + ) + self.Bind(wx.EVT_MENU, self.OnClose, m_exit) + menuBar.Append(menu, "&File") + self.SetMenuBar(menuBar) + + def init_status_bar(self): + self.statusbar = self.CreateStatusBar() + + def OnClose(self, event): + dlg = wx.MessageDialog( + self, + "Do you really want to close this application?", + "Confirm Exit", wx.OK | wx.CANCEL | wx.ICON_QUESTION + ) + result = dlg.ShowModal() + dlg.Destroy() + if result == wx.ID_OK: + self.Destroy() + + +if __name__ == '__main__': + app = wx.App(redirect=True) + top = BasicFrame( + title="Hello World", + pos=(150, 150), + size=(350, 200) + ) + top.Show() + app.MainLoop() diff --git "a/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/3.WxPython/event.json" "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/3.WxPython/event.json" deleted file mode 100644 index a3eb266..0000000 --- "a/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/3.WxPython/event.json" +++ /dev/null @@ -1,20 +0,0 @@ -{ - "one_line": { - "dlg.Destroy()": [ - "" - ], - "panel.Layout()": [ - "" - ], - "panel.SetSizer(box)": [ - "" - ], - "menuBar.Append(menu, \"&File\")": [ - "menuBar.append(menu, \"&File\")" - ] - }, - "source": "event.py", - "depends": [], - "exercise_id": 0, - "type": "code_options" -} \ No newline at end of file diff --git "a/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/3.WxPython/event.py" "b/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/3.WxPython/event.py" deleted file mode 100644 index decb68f..0000000 --- "a/data/2.python\344\270\255\351\230\266/4.\346\241\214\351\235\242\345\272\224\347\224\250\345\274\200\345\217\221/3.WxPython/event.py" +++ /dev/null @@ -1,63 +0,0 @@ -# -*- coding: UTF-8 -*- -# 作者:huanhuilong -# 标题:Python WxPython 例子 -# 描述:创建窗口、菜单、显示文本,关闭 - -import wx - - -class Frame(wx.Frame): - def __init__(self, title): - wx.Frame.__init__(self, None, title=title, - pos=(150, 150), size=(350, 200)) - self.init_close_event() - self.init_menu_bar() - self.init_status_bar() - self.init_panel() - - def init_close_event(self): - self.Bind(wx.EVT_CLOSE, self.OnClose) - - def init_menu_bar(self): - menuBar = wx.MenuBar() - menu = wx.Menu() - m_exit = menu.Append(wx.ID_EXIT, "E&xit\tAlt-X", - "Close window and exit program.") - self.Bind(wx.EVT_MENU, self.OnClose, m_exit) - menuBar.Append(menu, "&File") - self.SetMenuBar(menuBar) - - def init_status_bar(self): - self.statusbar = self.CreateStatusBar() - - def init_panel(self): - panel = wx.Panel(self) - box = wx.BoxSizer(wx.VERTICAL) - - m_text = wx.StaticText(panel, -1, "Hello World!") - m_text.SetFont(wx.Font(14, wx.SWISS, wx.NORMAL, wx.BOLD)) - m_text.SetSize(m_text.GetBestSize()) - box.Add(m_text, 0, wx.ALL, 10) - - m_close = wx.Button(panel, wx.ID_CLOSE, "Close") - m_close.Bind(wx.EVT_BUTTON, self.OnClose) - box.Add(m_close, 0, wx.ALL, 10) - - panel.SetSizer(box) - panel.Layout() - - def OnClose(self, event): - dlg = wx.MessageDialog(self, - "Do you really want to close this application?", - "Confirm Exit", wx.OK | wx.CANCEL | wx.ICON_QUESTION) - result = dlg.ShowModal() - dlg.Destroy() - if result == wx.ID_OK: - self.Destroy() - - -if __name__ == '__main__': - app = wx.App(redirect=True) - top = Frame("Hello World") - top.Show() - app.MainLoop() diff --git a/main.py b/main.py index 2e308f0..8c01f1c 100644 --- a/main.py +++ b/main.py @@ -6,8 +6,8 @@ import os import re if __name__ == '__main__': - walker = TreeWalker("data", "python", "python") + walker = TreeWalker("data", "python", "python", ignore_keywords=True) walker.walk() - # md = MDWalker('data/2.python中阶/3.网络爬虫') + # md = MDWalker('data/2.python中阶/4.桌面应用开发') # md.walk() -- GitLab