使用Qt实现一个简易时钟应用

原文链接:https://blog.qyadbr.top/2024/12/08/hexo9/

前言

我使用Qt制作了一个时钟应用,现在来分享一下实现的过程。

这个小项目包括了四个部分:

  • 时钟(显示当前时间)
  • 秒表(正向计时器,支持记录时间)
  • 倒计时
  • 闹钟

各种准备工作

导入

制作这个应用,我使用了一大堆QtWidgets组件。同时,还有至关重要的time模块。

from PySide6.QtWidgets import (QApplication,QWidget,QPushButton,QGroupBox,QLabel,
                                QTableWidget,QTableWidgetItem,QProgressBar,QScrollArea,
				                QDialog,QGridLayout,QVBoxLayout,QHBoxLayout,QSpinBox,QLineEdit,QComboBox,QSystemTrayIcon,QCheckBox)
from PySide6.QtGui import QIcon,QFont
from PySide6.QtCore import QObject,QTimer,Qt,QSize
import time

然后,建立一个QApplication,定义一些常量。

qapp=QApplication([])
icon=QIcon('../media/images/1.png') #窗口图标
widgetslist=[] #每个模式对应一个窗格
musicUrlList=['../media/audio/1.wav'] #闹铃音乐
musicNameList=['音乐1'] #音乐名称

menubuttonnamelist=['时钟','秒表','倒计时','闹钟']
menubuttonlist=[]
mode=0 #当前的模式

#下面这段永远放在最后
qapp.exec()

建立窗口

建立一个类,继承QtWidgets.QWidget

class Window(QWidget):
    def __init__(self,width,height,title,icon):
        super().__init__()
        self.setWindowTitle(QObject.tr(title))
        self.resize(width,height)
        self.setWindowIcon(icon)

实例化窗口对象。

mainWindow=Window(1000,600,'时钟',icon)
mainWindow.show()

功能窗格与切换按钮

我在窗口左侧做了四个按钮,分别对应四种功能。点击按钮就可以切换窗格的显示状态。

#定义按钮类
class MenuButton(QPushButton):
    def __init__(self,parent,num):
        super().__init__(parent)
        self.num=num
        self.clicked.connect(self.toggleMode)
    def toggleMode(self):
        global mode
        widgetslist[mode].hide()
        widgetslist[self.num].show()
        mode=self.num
#显示
for i in range(len(menubuttonnamelist)):
    button=MenuButton(mainWindow,i)
    button.setText(menubuttonnamelist[i])
    button.move(10,10+i*30)
    button.show()
    menubuttonlist.append(button)
    group=QGroupBox(parent=mainWindow,title=menubuttonnamelist[i])
    group.resize(890,580)
    group.move(100,10)
    widgetslist.append(group)

窗格尺寸自适应

当缩放窗口时,窗格的大小不会改变,因此我们要自动设置窗格的尺寸。

Qt中,QWidget被缩放大小就会自动执行resizeEvent函数,重写其内容即可。

# class Window(QWidget):
    def resizeEvent(self,event):
        size=self.size()
        for i in widgetslist:
            i.resize(size.width()-110,size.height()-20)

时间显示

这是整个项目最最简单的一部分。

组件

nowtime=time.strftime('%H:%M:%S')
labelTime=QLabel(widgetslist[0])
font=QFont('Arian',100,10)
labelTime.setFont(font)
labelTime.setText(nowtime)

更新显示

除了刷新时间,还设置了窗口自适应

def update():
    size1_1=widgetslist[0].size()
    nowtime=time.strftime('%H:%M:%S')
    labelTime.setText(nowtime)
    labelTime.move(size1_1.width()/2-size2.width()/2,size1_1.height()/2-size2.height()/2)

timer=QTimer()
timer.start(0.05)
timer.timeout.connect(update)

效果

image

正向计时器

这是第二个功能,需要实现一个可以开始、暂停的计时器,计时状态下可以记录,非计时状态下可以清零。

创建组件

实现它,需要一个文本显示,三个按钮,以及一个表格。

recorder=QLabel(widgetslist[1])
recorder.setText('00:00:00.000')
recorder.setFont(font)
startStopButton=QPushButton('开始',widgetslist[1])
recordButton=QPushButton('记录',widgetslist[1])
recordButton.setDisabled(True)
clearButton=QPushButton('清零',widgetslist[1])
clearButton.setDisabled(True)
recordTable=QTableWidget(0,3,widgetslist[1])
recordTable.setHorizontalHeaderLabels(['序次','间隔','总计'])
recordTable.verticalHeader().setVisible(False)
recordTable.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
recordTable.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

变量

startTimeStamp=0
lastEndStamp=0
lastRecordStamp=0
running=False
timeDelta=0
  • startTimeStamp:计时开始的时间戳
  • lastEndStamp:上次暂停时的时间戳
  • lastRecordStamp:上次记录时的时间戳,用于计算记录间隔
  • running:是否正在计时
  • timeDelta:暂停后,将产生时间差,在计算当前时间是要减去这个时间差

获取与格式化时间戳

变量已经齐全,下一步就是获取当前的时间。获取时间可以使用下面简单的公式:
r e s = n o w − s t a r t T i m e S t a m p − t i m e D e l t a res=now-startTimeStamp-timeDelta res=nowstartTimeStamptimeDelta
这个公式要使用多次,所以封装成函数:

def getTime():
    global startTimeStamp,timeDelta
    return time.time()-startTimeStamp-timeDelta 

获取到时间之后,将时间戳直接展示给用户肯定不现实,因此将其转换成时间字符串。同时,要传入一个参数,表示取整还是精确到小数点后三位。(后续倒计时和闹钟都不取后三位。)

def formatTime(data,round=False):
    return '{:0>2d}'.format(int(data//3600))+':'+'{:0>2d}'.format((int(data)%3600)//60)+':'+'{:0>2d}'.format(int(data)%60)+('.'+'{:0>3d}'.format(int((data%1)*1000)) if not round else '')

计时控制

刚刚我创建了三个按钮组件,现在在要对应地写着三个按钮被点击是执行的函数。

开始和停止

这个函数可以控制running变量,以及做出对应的操作:

  • 设置按钮位置;
  • 改变timeDelta
  • 设置按钮
def startStop():
    global running,startTimeStamp,lastEndStamp,timeDelta,lastRecordStamp
    if running:
        lastEndStamp=time.time()
        startStopButton.setText('开始')
    else:
        if startTimeStamp==0:
            startTimeStamp=lastEndStamp=time.time()
        timeDelta+=time.time()-lastEndStamp
        startStopButton.setText('停止')
    recordButton.setDisabled(running)
    running=not running
    clearButton.setDisabled(running)

记录

记录按钮被按下时,就在表格中插入一行,第一列是次数,第二列是间隔,第三列是总计时间。最后,还要设置这次记录的时间戳,以计算这一次到下一次记录的时间间隔。

def writeRecord():
    global lastRecordStamp
    recordTable.insertRow(0)
    recordTable.setItem(0,0,QTableWidgetItem(str(recordTable.rowCount())))
    if recordTable.rowCount()>1:
        recordTable.setItem(0,1,QTableWidgetItem(formatTime(getTime()-lastRecordStamp)))
    recordTable.setItem(0,2,QTableWidgetItem(formatTime(getTime())))
    lastRecordStamp=getTime()

清除记录

清除,要把各种变量都初始化,设置时间文本的文字也为初始的。因为表格控件没有提供清空函数,所以只能逐行删除直至表格为空为止。

def clearRecord():
    global startTimeStamp,lastEndStamp,timeDelta,recorder
    startTimeStamp=lastEndStamp=timeDelta=0
    recorder.setText('00:00:00.000')
    clearButton.setDisabled(True)
    while(recordTable.rowCount()>0):
        recordTable.removeRow(0)

连接按钮与函数

使用按钮控件.clicked.connect(函数名)就可以在按钮被点击时调用函数。


                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值