前言
前些天天气太热了,前些天我们这里居然达到了近40℃的高温。
如此热的天气,表示都不想出门了;那就来写个便捷小空调来娱乐下趴~
本次所用的模块有:
1、gui窗口程序:PyQt5
2、多线程操作:threading
3、音频播放:pygame
项目实战
Gui窗口程序设计
窗口程序设计,这里为了节省时间成本,我就没有再去手动去写布局代码了。这里我使用的是 Qt Designer 通过拖拽的方式来快速完成GUI窗口程序的布局。
当布局ui文件生成好了之后,在pycharm中右键使用扩展命令快速将*.ui文件转为*.py文件。
这样我的QtGUI窗口类就有了,接下来就是调用并为相关按钮绑定上相关的处理代码即可。
生成好的 form.py 文件如下 :
# -*- coding: utf-8 -*- # Form implementation generated from reading ui file 'form1.ui' # # Created by: PyQt5 UI code generator 5.15.4 # # WARNING: Any manual changes made to this file will be lost when pyuic5 is # run again. Do not edit this file unless you know what you are doing. from PyQt5 import QtCore, QtGui, QtWidgets class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(753, 656) MainWindow.setFixedSize(MainWindow.width(), MainWindow.height()); MainWindow.setStyleSheet('background-color: rgb(255, 255, 255);') # 设置背景色 self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.label = QtWidgets.QLabel(self.centralwidget) self.label.setGeometry(QtCore.QRect(160, 70, 450, 200)) self.label.setStyleSheet("color: rgb(255, 255, 255);\n" "border-image: url(rescourse/kt.jpg);") self.label.setObjectName("label") self.pushButton = QtWidgets.QPushButton(self.centralwidget) self.pushButton.setGeometry(QtCore.QRect(240, 350, 60, 60)) self.pushButton.setMaximumSize(QtCore.QSize(60, 60)) self.pushButton.setStyleSheet("QPushButton{background-color: rgb(25, 118, 210);}\n" "QPushButton{color: rgb(255,255,255); }\n" "QPushButton{border-radius: 30px; }\n" "QPushButton{border-style: outset;}\n" "QPushButton{border-image: url(rescourse/slow.png);}\n" "QPushButton:pressed{background-color: rgb(224, 224, 224);}\n" "QPushButton{font: 75 16pt \"Agency FB\";}") self.pushButton.setText("") self.pushButton.setObjectName("pushButton") self.pushButton_3 = QtWidgets.QPushButton(self.centralwidget) self.pushButton_3.setGeometry(QtCore.QRect(330, 350, 60, 60)) self.pushButton_3.setMaximumSize(QtCore.QSize(60, 60)) self.pushButton_3.setStyleSheet("QPushButton{background-color: rgb(67, 160, 71);}\n" "QPushButton{color: rgb(255,255,255); }\n" "QPushButton{border-radius: 30px; }\n" "QPushButton:pressed{background-color: red;}\n" "QPushButton{border-image: url(rescourse/on.png);}\n" "QPushButton{border-style: outset;}") self.pushButton_3.setText("") self.pushButton_3.setObjectName("pushButton_3") self.pushButton_4 = QtWidgets.QPushButton(self.centralwidget) self.pushButton_4.setGeometry(QtCore.QRect(410, 350, 60, 60)) self.pushButton_4.setMaximumSize(QtCore.QSize(60, 60)) self.pushButton_4.setStyleSheet("QPushButton{background-color: orange;}\n" "QPushButton{color: rgb(255,255,255); } \n" "QPushButton{border-radius: 30px; }\n" "QPushButton{border-style: outset;}\n" "QPushButton:pressed{background-color: rgb(224, 224, 224);}\n" "QPushButton{border-image: url(rescourse/hot.png);}\n" "QPushButton{font: 75 12pt \"Agency FB\";}") self.pushButton_4.setText("") self.pushButton_4.setObjectName("pushButton_4") self.pushButton_5 = QtWidgets.QPushButton(self.centralwidget) self.pushButton_5.setGeometry(QtCore.QRect(330, 440, 60, 60)) self.pushButton_5.setMaximumSize(QtCore.QSize(60, 60)) self.pushButton_5.setStyleSheet("QPushButton{background-color: rgb(245, 245, 245);}\n" "QPushButton{color: black;} \n" "QPushButton{border-radius: 30px;} \n" "QPushButton:pressed{background-color: rgb(224, 224, 224);}\n" "QPushButton{border-style: outset;}") self.pushButton_5.setObjectName("pushButton_5") self.pushButton_6 = QtWidgets.QPushButton(self.centralwidget) self.pushButton_6.setGeometry(QtCore.QRect(330, 520, 60, 60)) self.pushButton_6.setMaximumSize(QtCore.QSize(60, 60)) self.pushButton_6.setStyleSheet("QPushButton{background-color: rgb(245, 245, 245);}\n" "QPushButton{color: black; } \n" "QPushButton{border-radius: 30px; } \n" "QPushButton:pressed{background-color: rgb(224, 224, 224);}\n" "QPushButton{border-style: outset;}") self.pushButton_6.setObjectName("pushButton_6") self.label_2 = QtWidgets.QLabel(self.centralwidget) self.label_2.setGeometry(QtCore.QRect(530, 130, 61, 30)) self.label_2.setStyleSheet("text-shadow: 0 0 2px rgb(0 0 0 / 10%);\n" "color:rgb(204, 204, 204);\n" "font: 75 16pt \"Agency FB\";") self.label_2.setObjectName("label_2") MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 753, 26)) self.menubar.setObjectName("menubar") MainWindow.setMenuBar(self.menubar) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "便捷小空调")) self.label.setText(_translate("MainWindow", "TextLabel")) self.pushButton_5.setText(_translate("MainWindow", "▲")) self.pushButton_6.setText(_translate("MainWindow", "▼")) self.label_2.setText(_translate("MainWindow", "0℃"))
Part 2
为GUI窗口程序绑定好处理代码
1.导入相关包
from PyQt5 import QtWidgets from PyQt5.QtGui import QIcon from pygame import mixer import sys, time from threading import Thread from form import Ui_MainWindow
2 定义空调类,调用GUI窗口程序类,并编写相关处理逻辑的类方法。
2.1 定义两个常量,分别来标记空调开关状态与空调温度。
# 空调开关常量 switch = 0 # 空调温度 temperature = 0
2.2 类初始化方法(调用GUI窗口类,并为相关控件绑定信号槽事件)
# 初始化 def __init__(self): app = QtWidgets.QApplication(sys.argv) MainWindow = QtWidgets.QMainWindow() app.setWindowIcon(QIcon('./rescourse/logo.ico')) self.ui = Ui_MainWindow() self.ui.setupUi(MainWindow) self.ui.pushButton_3.clicked.connect(lambda: self.start_thread(self.is_on)) self.ui.pushButton.clicked.connect(lambda: self.start_thread(self.play_di)) self.ui.pushButton_4.clicked.connect(lambda: self.start_thread(self.play_di)) self.ui.pushButton_5.clicked.connect(lambda: self.start_thread(self.add)) self.ui.pushButton_6.clicked.connect(lambda: self.start_thread(self.reduce)) MainWindow.show() sys.exit(app.exec_())
2.3 线程函数
因为gui窗口程序在点击时不同于控制台运行的方式,它会比较耗时,为了防止gui窗口发生卡顿,这里定义一个线程方法用于提升程序的运行速度。
def start_thread(self, func): thread = Thread(target=func) thread.start()
2.4 空调温度增加
当点击该按钮时,先判断空调是否打开,如果打开,则获取空调当前温度,再次判断空调温度是否在1-30 范围内,如果在这个范围内,我们获取当前空调温度给它+1,并更新到gui窗口程序上。
def add(self): # 判断空调是否打开 if not self.switch < 1: current = self.ui.label_2.text().replace('℃', '') self.temperature = int(current) # 如果温度在1-30℃则可以增温 if (self.temperature >= 1) and (self.temperature <= 29): self.temperature += 1 self.ui.label_2.setText(f'{self.temperature}℃') self.play_di()
2.5 空调降温
这个逻辑跟上面差不多,只是把增加一度换成了减小一度,这里不做过多讲解。
def reduce(self): # 判断空调是否打开 if not self.switch < 1: current = self.ui.label_2.text().replace('℃', '') self.temperature = int(current) # 如果温度在1-30内则可以减温 if (self.temperature >= 1) and (self.temperature <= 30): self.temperature -= 1 self.ui.label_2.setText(f'{self.temperature}℃') self.play_di()
2.6 滴声音频
def drop(self): mixer.init() mixer.music.load('rescourse/audio/di.mp3') mixer.music.play() time.sleep(1) mixer.init() mixer.music.load('rescourse/audio/air-extractor-fan.mp3') mixer.music.play(loops=-1)
2.7 空调开关
功能:点击一次开启空调,并将空调温度设为25℃,再次点击则关闭空调。
这里有个点还是挺坑的,就是音效播放的问题,我刚开始写的时候发现不能顺序播放音频直接播放最后的音频了,所以这里我换成了 queue (队列)的写法。即:播放完一条音频则自动播放下一条音频。
def air_switch(self): self.switch += 1 if not self.switch > 1: self.ui.label_2.setText('25℃') self.ui.pushButton_3.setStyleSheet("QPushButton{background-color: rgb(229, 57, 53);}\n" "QPushButton{color: rgb(255,255,255); }\n" "QPushButton{border-radius: 30px; }\n" "QPushButton:pressed{background-color: red;}\n" "QPushButton{border-image: url(rescourse/on.png);}\n" "QPushButton{border-style: outset;}") mixer.init() mixer.music.load('rescourse/audio/di.mp3') mixer.music.play() mixer.init() mixer.music.queue('rescourse/audio/ac-work.mp3') time.sleep(9) mixer.music.queue('rescourse/audio/air-extractor-fan.mp3') else: self.ui.label_2.setText('0℃') self.ui.pushButton_3.setStyleSheet("QPushButton{background-color: rgb(67, 160, 71);}\n" "QPushButton{color: rgb(255,255,255); }\n" "QPushButton{border-radius: 30px; }\n" "QPushButton:pressed{background-color: red;}\n" "QPushButton{border-image: url(rescourse/on.png);}\n" "QPushButton{border-style: outset;}") # 释放播放的资源 mixer.music.unload() self.switch = 0
以上就是空调类的封装说明了,完整的类如下:
class Air: # 空调开关常量 switch = 0 # 空调温度 temperature = 0 # 初始化 def __init__(self): app = QtWidgets.QApplication(sys.argv) MainWindow = QtWidgets.QMainWindow() app.setWindowIcon(QIcon('./rescourse/logo.ico')) self.ui = Ui_MainWindow() self.ui.setupUi(MainWindow) self.ui.pushButton_3.clicked.connect(lambda: self.start_thread(self.air_switch)) self.ui.pushButton.clicked.connect(lambda: self.start_thread(self.drop)) self.ui.pushButton_4.clicked.connect(lambda: self.start_thread(self.drop)) self.ui.pushButton_5.clicked.connect(lambda: self.start_thread(self.add)) self.ui.pushButton_6.clicked.connect(lambda: self.start_thread(self.reduce)) MainWindow.show() sys.exit(app.exec_()) def start_thread(self, func): thread = Thread(target=func) thread.start() def add(self): # 判断空调是否打开 if not self.switch < 1: current = self.ui.label_2.text().replace('℃', '') self.temperature = int(current) # 如果温度在1-30℃则可以增温 if (self.temperature >= 1) and (self.temperature <= 29): self.temperature += 1 self.ui.label_2.setText(f'{self.temperature}℃') self.drop() def reduce(self): # 判断空调是否打开 if not self.switch < 1: current = self.ui.label_2.text().replace('℃', '') self.temperature = int(current) # 如果温度在1-30内则可以减温 if (self.temperature >= 1) and (self.temperature <= 30): self.temperature -= 1 self.ui.label_2.setText(f'{self.temperature}℃') self.drop() def drop(self): mixer.init() mixer.music.load('rescourse/audio/di.mp3') mixer.music.play() time.sleep(1) mixer.init() mixer.music.load('rescourse/audio/air-extractor-fan.mp3') mixer.music.play(loops=-1) def air_switch(self): self.switch += 1 if not self.switch > 1: self.ui.label_2.setText('25℃') self.ui.pushButton_3.setStyleSheet("QPushButton{background-color: rgb(229, 57, 53);}\n" "QPushButton{color: rgb(255,255,255); }\n" "QPushButton{border-radius: 30px; }\n" "QPushButton:pressed{background-color: red;}\n" "QPushButton{border-image: url(rescourse/on.png);}\n" "QPushButton{border-style: outset;}") mixer.init() mixer.music.load('rescourse/audio/di.mp3') mixer.music.play() mixer.init() mixer.music.queue('rescourse/audio/ac-work.mp3') time.sleep(9) mixer.music.queue('rescourse/audio/air-extractor-fan.mp3') else: self.ui.label_2.setText('0℃') self.ui.pushButton_3.setStyleSheet("QPushButton{background-color: rgb(67, 160, 71);}\n" "QPushButton{color: rgb(255,255,255); }\n" "QPushButton{border-radius: 30px; }\n" "QPushButton:pressed{background-color: red;}\n" "QPushButton{border-image: url(rescourse/on.png);}\n" "QPushButton{border-style: outset;}") # 释放播放的资源 mixer.music.unload() self.switch = 0
运行程序
运行程序,这里直接实例化封装好的空调类即可,代码如下:
if __name__ == "__main__": app = Air()