实现功能
- 通过qt的qml系列实现
- 自定义计时时间
- 滑动条控制时间长短
- 支持暂停继续
程序预览
默认
计时
暂停
基本思路
- 使用
qml
绘制窗口 - 通过
qrc
打包资源文件 - 通过
QQmlApplicationEngine().addImportPath()
添加导入路径 - 通过
QThread
进行计时 - 通过
QMutex
与QWaitCondition
实现暂停功能 - 通过
win32com
实现计时语言播报
具体实现
qml
绘制窗口
-
使用
qt
的Qt Design Studio
创建项目 -
绑定python类(后面会详细讲)
- 在qml中输入
import py
- 在
root
中定义Py {id: py}
- 在qml中输入
-
编写ui和事件控制(4个信号监视器)
Connections { target: start onCheckedChanged: { if (chooseTime.value != 0) { py.start(start.checked) if (start.checked) { start.text = qsTr("计时中") } else { start.text = qsTr("计时停止") } } else { start.checked = false } } } Connections { target: chooseTime onValueChanged: { py.changeTime(chooseTime.value) start.checked = false } } Connections { target: py function onSignal(time) { showTime.text = time } } Connections { target: root onWidthChanged: { showTime.font.pixelSize = root.width / 3 win.minimumHeight = showTime.font.pixelSize } onHeightChanged: { showTime.font.pixelSize = root.width / 3 win.minimumHeight = showTime.font.pixelSize } }
- 原理介绍(Connections)
- 作用:用来监视信号
- 参数
- target:后接被监视对象的id
- onSignal
- 表示接受的信号
- 格式为
on<信号名(首字母大写)>: {<doSomething>}
- 信号名可以是自带的,也可以是自定义的信号
- 如果需要从信号中接收参数,则建议写为
function onSignal(argv) {<doSomethong>}
其中function为定义函数,argv表示接收的参数
- 具体实现
- 开始按钮的点击(target: star)
- 调用python函数,开始计时或暂停
- 设置自身文字标注
- 禁止在时间为0时开始计时
- 选择时间的滑动条(target: chooseTime)
- 调用python函数,传递当前时间数字
- 将计时开关关闭
- python传递的当前时间(target: py)
- 设置文本框显示的时间
- 监视窗口大小改变(target: root)
- 设置时间文字大小为窗口宽度的 1 3 \frac{1}{3} 31
- 设置窗口最小高度为文字高度
- 开始按钮的点击(target: star)
- 原理介绍(Connections)
qrc
打包资源文件
- 在
content
目录下新建文件qmldir
并写入以下内容-
module content App 1.0 App.qml Screen01.ui 1.0 Screen01.ui.qml
- 语法说明
model <模块名>
<类名> <版本号> <文件路径>
-
- 在
Qt Design Studio
中点击文件-export project-…QRC…
- 不要改变默认路径,选择所有文件
- 通过
pyside6-rcc.exe <qrc路径> -o <py路径>
- 前人之述备矣,详见 <Qt Design Studio导出项目到python中使用>(注:只看打包部分即可,无法导入后续问题我会讲解)
添加导入路径&加载qmlwj
engine = QQmlApplicationEngine()
engine.addImportPath("qrc:/")
engine.addImportPath("qrc:/imports")
engine.load(":/main.qml")
- QQmlApplicationEngine() 为qml加载器,可以显示qml窗口
- addImportPath() 用来添加qml的import搜索路径(冒号签到qrc可以省略)
- load() 用来加载并显示qml
QThread
线程计时
class Main(QThread):
signal = Signal(int)
paused = False
def __init__(self):
super().__init__()
self.secs = 0
self.mutex = QMutex()
self.pauseCond = QWaitCondition()
def run(self):
for i in range(self.secs, -1, -1):
self.mutex.lock()
if self.paused:
self.pauseCond.wait(self.mutex)
self.mutex.unlock()
self.signal.emit(i)
time.sleep(1)
def pause(self):
self.mutex.lock()
self.paused = True
self.mutex.unlock()
def resume(self):
self.mutex.lock()
self.paused = False
self.pauseCond.wakeAll()
self.mutex.unlock()
- 信号
signal
用于通知用户界面当前秒数 paused
用于标识当前程序是否暂停QMutex
与QWaitCondition
用来实现线程锁与等待QMutex.lock()
后,如果再次调用QMutex.lock()
会被阻塞,直到QMutex.unlock()
后继续执行QWaitCondition.wait()
方法来等待条件变为真,如果条件不满足,程序将会被阻塞,并且会自动释放互斥锁.QWaitCondition.wakeAll()
被调用后会唤醒被暂停的操作
语言朗读
from win32com import client
def speak(self, text: str):
engine = client.Dispatch("SAPI.SpVoice")
engine.Speak(text)
通过调用 win32com
实现
计时线程回调处理
def callBack(self, msg: int):
min, sec = divmod(msg, 60)
self.signal.emit(f"{min:02d}:{sec:02d}")
if msg == 0 and self.min != 0:
self.signal.emit(f"{min:02d}:{sec:02d}")
Thread(target=self.speak, args=(f"{self.min}分钟计时完成",)).start()
- 将回调得到的秒数转换为分钟和秒
- 格式化后
emit()
给qml - 如果计时完成,进行语言播报