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 1179b9d61b58a53b65ada55a521be67d461ea7c7..fa4e0b7e143e8e01d0befcb4fb5e09c662cdc7cf 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 0000000000000000000000000000000000000000..69dda17f8d6183b40f4f5effe7b67d95ef5f6ef5 --- /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 57f871f7fb881d28bf6cd3f0347dab1118815fb0..94f0371e0e5b748f8f97a04608488a171109f8dc 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 0000000000000000000000000000000000000000..6d39435ed65a12a5459cdeaf83071e6355cb7180 --- /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 238beb61f5e8d9f9d4c017b53e40550c13a5c5d9..9093cc90fd1ab37df6b08d13244edaa32f9f8fda 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 0000000000000000000000000000000000000000..fc657fd8d1b616726a0a7b69451a9bb2eb924103 --- /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 Binary files /dev/null and "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" differ 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 f44326139fb255f15e845dbeaf374f9487a9d3f5..f0e2d10b27f72ab8076e349579a9a3baf7950c94 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 c6989828ca6d782467f135fcfead517f69986d9a..ce707d8ac8d60d915cbc40d0fa2619f41a8fd2ae 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 0000000000000000000000000000000000000000..be8d3b78b6232882396f4c12271237a4d734fc98 --- /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 Binary files /dev/null and "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" differ 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 b4d9408f1670a0b4821d02a62bf2678c5e27de3f..fd739767f05ccc0d351dc8a4f795ebe3242aab28 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 007ac82c01d0dd232d30b8153c2b097f16144814..e91769db596250d4460fd2e50b2bbe3c52091a5d 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 0000000000000000000000000000000000000000..114143eed6bddc0e9a5ec5a0fb00ef4005534877 --- /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 5eb75901a1d9cca63dcf4728239f60ea12db6854..dab3f9a7d62f2cfc2438e897aeebf6d7a8f606ef 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 d6f93ab68f8b5daa0f3d5ebb7270f9ae80d79df9..dfdbde2f005d25f8bf157aadc84dfdeb1c8db2c1 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 0000000000000000000000000000000000000000..82223590daef243ce72a6d8d808d34e16bfa00d3 --- /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 0000000000000000000000000000000000000000..5efbb73659316749f599ae37a2554d0502f6aa12 --- /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 0000000000000000000000000000000000000000..efd049e656f006fc087e6565fdcb64afde2da10c --- /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 0000000000000000000000000000000000000000..1cfc22db0f351e9d381039bb58f2f62edc751a3e --- /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 0000000000000000000000000000000000000000..5e6711b666055e067e5ad377011df7d5a71056ec --- /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 0000000000000000000000000000000000000000..a899473af8f483619785f5789ab2a1e29d38197b --- /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 a3eb26618194de1267137767e270befa5df57b60..0000000000000000000000000000000000000000 --- "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 decb68f8557e124983fbd8b04d19c1829c43f14f..0000000000000000000000000000000000000000 --- "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 2e308f0ebb7765c1fa7be797772c66e6a69b2d3f..8c01f1ca065380f9424d75f49fbc4090e0416f1e 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()