提交 5875cc06 编写于 作者: F feilong

更新到第8章

上级 46deedf0
{ {
"one_line": { "source": "app.md",
"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",
"depends": [], "depends": [],
"exercise_id": 2, "exercise_id": 2,
"type": "code_options" "type": "code_options",
"author": "huanhuilong",
"notebook_enable": true
} }
\ No newline at end of file
# 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()
```
{ {
"multiline": [ "source": "basic.md",
{
"show.pack()": "",
"number.pack()": ""
},
{
"command=self.on_show": "command=self.on_show()"
},
{
"lambda: self.on_click(i)": "self.on_click(i)"
}
],
"source": "basic.py",
"depends": [], "depends": [],
"exercise_id": 1, "exercise_id": 1,
"type": "code_options" "type": "code_options",
"author": "huanhuilong",
"notebook_enable": true
} }
\ No newline at end of file
# 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()
```
{ {
"one_line": { "source": "for_each_month.md",
"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",
"depends": [ "depends": [
"q_progress_thread.py", "q_progress_thread.py",
"q_progress_bar.py" "q_progress_bar.py"
], ],
"exercise_id": 205, "exercise_id": 205,
"type": "code_options" "type": "code_options",
"author": "huanhuilong",
"notebook_enable": true
} }
\ No newline at end of file
# 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
```
...@@ -31,13 +31,13 @@ class MonthProgress: ...@@ -31,13 +31,13 @@ class MonthProgress:
break break
return count return count
def __for_each_month(self, on_progress): def __for_each_month(self, emit_progress):
d = self.start d = self.start
finish = self.finish finish = self.finish
progress = 0 progress = 0
while d < finish: while d < finish:
time.sleep(0.1) time.sleep(0.1)
on_progress(progress, d.__str__()) emit_progress(progress, d.__str__())
d = d+timedelta(monthrange(d.year, d.month)[1]) d = d+timedelta(monthrange(d.year, d.month)[1])
progress += 1 progress += 1
......
{ {
"one_line": { "source": "q_progress_bar.md",
"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",
"depends": [ "depends": [
"q_progress_thread.py" "q_progress_thread.py"
], ],
"exercise_id": 228, "exercise_id": 228,
"type": "code_options" "type": "code_options",
"author": "huanhuilong",
"notebook_enable": true
} }
\ No newline at end of file
# 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')
```
# -*- coding: UTF-8 -*-
# 作者:huanhuilong
# 标题:Python PyQt 进度条(2)
# 描述:请先完成上一题。封装一个能显示进度条的 PyQT GUI 对话框
import sys import sys
import time
import math 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 from q_progress_thread import QProgressThread
...@@ -16,7 +15,7 @@ class QRunnerProgressBar(QWidget): ...@@ -16,7 +15,7 @@ class QRunnerProgressBar(QWidget):
self.vbox = QVBoxLayout() self.vbox = QVBoxLayout()
self.btn = QPushButton(tip) self.btn = QPushButton(tip)
self.btn.clicked.connect(self.btnFunc) self.btn.clicked.connect(self.on_btn_click)
self.vbox.addWidget(self.btn) self.vbox.addWidget(self.btn)
self.pbar = QProgressBar(self) self.pbar = QProgressBar(self)
...@@ -30,19 +29,20 @@ class QRunnerProgressBar(QWidget): ...@@ -30,19 +29,20 @@ class QRunnerProgressBar(QWidget):
self.count = count self.count = count
self.runner = runner self.runner = runner
def btnFunc(self): def on_btn_click(self):
self.thread = QProgressThread(self.runner) self.thread = QProgressThread(self.runner)
self.thread._signal.connect(self.signal_accept) self.thread.connect(self.on_progress)
self.thread.start() self.thread.start()
self.btn.setEnabled(False) self.btn.setEnabled(False)
def signal_accept(self, info): def on_progress(self, info):
percent_value = int(math.floor(info.progress*100/self.count)) percent_value = int(math.floor(info.progress*100/self.count))
self.pbar.setValue(int(percent_value)) self.pbar.setValue(int(percent_value))
self.setWindowTitle(info.msg) self.setWindowTitle(info.msg)
if self.pbar.value() == 99: if self.pbar.value() == 100:
self.pbar.setValue(0) self.pbar.setValue(0)
self.btn.setEnabled(True) self.btn.setEnabled(True)
self.setWindowTitle('QRunnerProgressBar')
def closeEvent(self, event): def closeEvent(self, event):
self.thread = None self.thread = None
...@@ -50,9 +50,15 @@ class QRunnerProgressBar(QWidget): ...@@ -50,9 +50,15 @@ class QRunnerProgressBar(QWidget):
if __name__ == "__main__": if __name__ == "__main__":
app = QApplication(sys.argv) 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( p = QRunnerProgressBar(
100, count=5,
'看资料+做题,就有技能树进度', tip='看资料+做题,就有技能树进度',
lambda on_progress: on_progress(50, 'Python技能树->PyQT') runner=on_run
) )
sys.exit(app.exec_()) sys.exit(app.exec_())
{ {
"one_line": { "source": "q_progress_thread.md",
"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",
"depends": [], "depends": [],
"exercise_id": 233, "exercise_id": 233,
"type": "code_options" "type": "code_options",
"author": "huanhuilong",
"notebook_enable": true
} }
\ No newline at end of file
# 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)
```
# -*- coding: UTF-8 -*-
# 作者:huanhuilong
# 标题:Python PyQt 进度条(1)
# 描述:使用 QThread 发送信号,接收信号一方打印并结束程序
import sys import sys
from PyQt5.QtCore import QThread, pyqtSignal from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import QApplication from PyQt5.QtWidgets import QApplication
...@@ -20,27 +16,33 @@ class QProgressThread(QThread): ...@@ -20,27 +16,33 @@ class QProgressThread(QThread):
super(QProgressThread, self).__init__() super(QProgressThread, self).__init__()
self.runner = runner self.runner = runner
def __del__(self):
self.wait()
def run(self): def run(self):
def on_progress(progress, info): def emit_progress(progress, msg):
info = ProgressInfo(progress, info) info = ProgressInfo(progress, msg)
self._signal.emit(info) 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__": if __name__ == "__main__":
app = QApplication(sys.argv) 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): def on_signal(info):
print("accept info from signal:", info.msg) print("accept info from signal:", info.msg)
QApplication.quit() QApplication.quit()
p.connect(on_signal)
p._signal.connect(on_signal)
p.start() p.start()
sys.exit(app.exec_()) sys.exit(app.exec_())
{ {
"export": [ "export": [
"event.json" "create_window.json",
"create_panel.json"
], ],
"keywords": [], "keywords": [],
"children": [ "children": [
......
{
"source": "create_panel.md",
"depends": [],
"exercise_id": "bad097def1a54b009ee7f5b0f73b3b1f",
"type": "code_options",
"author": "huanhuilong",
"notebook_enable": true
}
\ No newline at end of file
# 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()
```
# -*- 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()
{
"source": "create_window.md",
"depends": [],
"exercise_id": 0,
"type": "code_options",
"author": "huanhuilong",
"notebook_enable": true
}
\ No newline at end of file
# 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)
```
...@@ -6,14 +6,13 @@ ...@@ -6,14 +6,13 @@
import wx import wx
class Frame(wx.Frame): class BasicFrame(wx.Frame):
def __init__(self, title): def __init__(self, title, pos, size):
wx.Frame.__init__(self, None, title=title, wx.Frame.__init__(self, None, title=title,
pos=(150, 150), size=(350, 200)) pos=pos, size=size)
self.init_close_event() self.init_close_event()
self.init_menu_bar() self.init_menu_bar()
self.init_status_bar() self.init_status_bar()
self.init_panel()
def init_close_event(self): def init_close_event(self):
self.Bind(wx.EVT_CLOSE, self.OnClose) self.Bind(wx.EVT_CLOSE, self.OnClose)
...@@ -21,8 +20,11 @@ class Frame(wx.Frame): ...@@ -21,8 +20,11 @@ class Frame(wx.Frame):
def init_menu_bar(self): def init_menu_bar(self):
menuBar = wx.MenuBar() menuBar = wx.MenuBar()
menu = wx.Menu() menu = wx.Menu()
m_exit = menu.Append(wx.ID_EXIT, "E&xit\tAlt-X", m_exit = menu.Append(
"Close window and exit program.") wx.ID_EXIT,
"E&xit\tAlt-X",
"Close window and exit program."
)
self.Bind(wx.EVT_MENU, self.OnClose, m_exit) self.Bind(wx.EVT_MENU, self.OnClose, m_exit)
menuBar.Append(menu, "&File") menuBar.Append(menu, "&File")
self.SetMenuBar(menuBar) self.SetMenuBar(menuBar)
...@@ -30,26 +32,12 @@ class Frame(wx.Frame): ...@@ -30,26 +32,12 @@ class Frame(wx.Frame):
def init_status_bar(self): def init_status_bar(self):
self.statusbar = self.CreateStatusBar() 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): def OnClose(self, event):
dlg = wx.MessageDialog(self, dlg = wx.MessageDialog(
"Do you really want to close this application?", self,
"Confirm Exit", wx.OK | wx.CANCEL | wx.ICON_QUESTION) "Do you really want to close this application?",
"Confirm Exit", wx.OK | wx.CANCEL | wx.ICON_QUESTION
)
result = dlg.ShowModal() result = dlg.ShowModal()
dlg.Destroy() dlg.Destroy()
if result == wx.ID_OK: if result == wx.ID_OK:
...@@ -58,6 +46,10 @@ class Frame(wx.Frame): ...@@ -58,6 +46,10 @@ class Frame(wx.Frame):
if __name__ == '__main__': if __name__ == '__main__':
app = wx.App(redirect=True) app = wx.App(redirect=True)
top = Frame("Hello World") top = BasicFrame(
title="Hello World",
pos=(150, 150),
size=(350, 200)
)
top.Show() top.Show()
app.MainLoop() app.MainLoop()
{
"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
...@@ -6,8 +6,8 @@ import os ...@@ -6,8 +6,8 @@ import os
import re import re
if __name__ == '__main__': if __name__ == '__main__':
walker = TreeWalker("data", "python", "python") walker = TreeWalker("data", "python", "python", ignore_keywords=True)
walker.walk() walker.walk()
# md = MDWalker('data/2.python中阶/3.网络爬虫') # md = MDWalker('data/2.python中阶/4.桌面应用开发')
# md.walk() # md.walk()
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册