本文介紹在樹莓派上使用Pyside2+QML方式進(jìn)行GUI程序的開發(fā),該GUI程序可以通過按鈕來控制蜂鳴器播放不同的音調(diào),這里演示按鈕彈奏歌曲《兩只老虎》。開發(fā)環(huán)境依然使用之前介紹的PyCharm編寫python代碼和遠(yuǎn)程開發(fā),然后使用QtCreator編寫QML界面的方式。
1、新建項目
1.1、新建工程
打開PyCharm,新建工程buzzer_control,如下:

image-20210809223915634.png
1.2、添加python主程序
buzzer_control.py 主程序如下:
# This Python file uses the following encoding: utf-8
import os
from pathlib import Path
import sys
from PySide2.QtCore import Qt, QObject, Slot, QTimer
from PySide2.QtGui import QGuiApplication
from PySide2.QtQml import QQmlApplicationEngine
from gpiozero import TonalBuzzer
from gpiozero.tones import Tone
class Controler(QObject):
buzzer = TonalBuzzer(25)
def __init__(self):
super().__init__()
@Slot()
def exit(self):
sys.exit()
@Slot(str)
def play(self,mid_tone):
self.buzzer.play(Tone(mid_tone))
print("play.")
QTimer.singleShot(200, lambda: self.stop())
def stop(self):
self.buzzer.stop()
print("stop.")
if __name__ == "__main__":
app = QGuiApplication(sys.argv)
app.setOverrideCursor(Qt.BlankCursor)
engine = QQmlApplicationEngine()
controler = Controler()
context = engine.rootContext()
context.setContextProperty("_Controler", controler)
engine.load(os.fspath(Path(__file__).resolve().parent / "ui/main.qml"))
if not engine.rootObjects():
sys.exit(-1)
sys.exit(app.exec_())
- Controler類
這個類用于控制python控制硬件和退出程序
- TonalBuzzer
這個接口用于Buzzer播放不同的音調(diào),使用play方法播放,stop方法停止
- 停止播放的方法
要在播放一定時間后停止需要一定的延時,如果直接使用python中的sleep方法會導(dǎo)致界面在延時過程中無法響應(yīng),因此這里使用Qt中的QTimer來實現(xiàn)延時,即 QTimer.singleShot()
1.3、添加界面文件
- 在項目中添加ui文件夾,并新建main.qml文件;
- 同時在ui文件夾下新建image文件夾,并把要用到的資源放置在這個文件夾下;

image-20210812070417275.png
2、界面制作
界面用QtCreator編寫,里面主要包含一個7個按鍵用于控制不同聲調(diào);這里為了簡單,演示歌曲《兩只老虎》里面一共有7個音符:1、2、3、4、5、6、5.(低音5),因此這里就只制作了7個按鈕,如果要播放更復(fù)雜的歌曲,就需要實現(xiàn)完整的音符按鈕。
- 界面布局如下:

image-20210812070947234.png
- 參考代碼:
import QtQuick 2.11
import QtQuick.Window 2.4
import QtQuick.Controls 2.4
import QtQuick.Controls.Styles 1.4
import QtQuick.Extras 1.4
import QtGraphicalEffects 1.0
ApplicationWindow{
id:root
width: 800
height: 480
visible: true
visibility: Window.FullScreen
background: Rectangle{
color: "black"
anchors.fill: parent
}
Button{
id:btnexit
background: Rectangle{
color: "#a01010"
anchors.fill: parent
radius:12
}
width: 48
height: 48
anchors{
top: parent.top
right: parent.right
topMargin: 8
rightMargin: 8
}
Text {
text: qsTr("X")
anchors.centerIn: parent
font{
pointSize: 32
}
color: "white"
}
onClicked: {
_Controler.exit();
}
}
Text {
id: title
text: qsTr("BUZZER Control")
anchors{
horizontalCenter: parent.horizontalCenter
top: parent.top
topMargin: 10
}
font{
pointSize: 24
bold: true
}
color: "#1165B7"
}
AnimatedImage{
source: "./image/dance.gif"
anchors{
left: parent.left
top:parent.top
leftMargin: 40
topMargin: 40
}
width: 200
height: 160
}
Row{
id:pannelBack
spacing: 1
anchors{
bottom: parent.bottom
horizontalCenter: parent.horizontalCenter
bottomMargin: 30
}
Repeater{
model:8
Rectangle{
width: 80
height: 140
color: "#C4B197"
}
}
}
Row{
spacing: 12
anchors{
top: pannelBack.top
horizontalCenter: parent.horizontalCenter
}
Repeater{
model:7
Button {
width: 70
height: 100
property color backcolor: "#165D8F"
background: Rectangle{
anchors.fill: parent
color: parent.backcolor
}
onPressed: {
backcolor="#34ADE3"
}
onReleased: {
backcolor="#165D8F"
}
onClicked: {
console.log("click:"+index)
switch(index){
case 0:
one.visible=true;
one.restart();
_Controler.play("C5");
break;
case 1:
two.visible=true;
two.restart();
_Controler.play("D5");
break;
case 2:
three.visible=true;
three.restart();
_Controler.play("E5");
break;
case 3:
four.visible=true;
four.restart();
_Controler.play("F5");
break;
case 4:
five.visible=true;
five.restart();
_Controler.play("G5");
break;
case 5:
six.visible=true;
six.restart();
_Controler.play("A5");
break;
case 6:
seven.visible=true;
seven.restart();
_Controler.play("G4");
break;
}
}
}
}
}
Row{
spacing: 64
anchors{
horizontalCenter: parent.horizontalCenter
bottom: pannelBack.top
}
Repeater{
model: ["1","2","3","4","5","6","5."]
Text {
text: modelData
font.pointSize: 24
color: "#C4A781"
}
}
}
Image{
// anchors.centerIn: parent
id:one
x:pannelBack.x+50
y:pannelBack.y-60
width: 64
height: 64
source: "./image/1.svg"
visible: false
function restart(){
anixone.restart();
aniyone.restart();
anirone.restart();
}
NumberAnimation on y{
id:anixone
from:pannelBack.y-60
to: pannelBack.y - 1000
duration: 20000
easing.type: Easing.OutCirc
}
NumberAnimation on x{
id:aniyone
from:pannelBack.x+50
to: pannelBack.x +400
duration: 8000
easing.type: Easing.OutBounce
}
RotationAnimator on rotation{
id:anirone
to: 720
duration: 8000
}
}
......
}
/*##^##
Designer {
D{i:0;formeditorZoom:0.66;height:480;width:800}
}
##^##*/
3、執(zhí)行程序
3.1、上傳程序到樹莓派
在工程上右鍵將這個項目文件上傳到樹莓派中:

image-20210812071126896.png
3.2、執(zhí)行程序
上傳后,在樹莓派對應(yīng)文件夾中,執(zhí)行如下命令執(zhí)行程序:
python3 buzzer_control.py
執(zhí)行后可以看到顯示如下:

image-20210811233134669.png
3.3、演示彈奏歌曲
這里演示歌曲為《兩只老虎》,其簡譜如下圖,只需要按照簡譜表彈奏即可:

兩只老虎.jpg
視頻效果如下:
https://mp.weixin.qq.com/s/Y-WTBLuMcJxnIL7j316-aA
查看代碼:
github