目錄
- 一、設計目標
- 二、實現流程
- 1. 數據庫操作
- 2. 后端功能實現
- 3. 前端UI界面實現
- 4. 程序入口
- 三、項目收獲
一、設計目標
1. 模擬網易云音樂,實現本地音樂盒。
2. 功能分析:
- 登錄功能
- 窗口顯示
- 加載本地音樂
- 建立播放列表
- 播放音樂
- 刪除播放列表音樂
3.設計思路:- 前端UI頁面:播放按鈕、導入音樂按鈕、刪除按鈕、音樂播放列表
- 后端服務端:登錄功能、導入音樂的功能、播放音樂的功能、刪除音樂的功能
- 為了將前端頁面和后端服務更好的結合,在實際實現中,根據設計程序的目標加入一些屬性或方法,來幫助程序功能更好的實現。
例如:前端音樂列表的加載,需要在后端服務程序中添加一個從數據庫中查找當前用戶音樂列表的方法,然后由前端UI界面調用把查找到的音樂加入音樂列表中。
4.數據庫組件:- 為了實現功能,需要在數據庫中設計的三張表:
- 用戶表:存儲用戶信息,用來實現登錄功能
- 音樂表:存儲音樂信息(名稱、歌手、資源路徑),存儲所有導入的音樂,用來實現尋找音樂資源進行加載、播放和刪除的功能。
- 用戶播放列表:存儲用戶id及其對應的音樂id,且這兩個值分別有另外兩張表的外鍵約束,用來正確的顯示用戶對應的歌曲。
二、實現流程
1. 數據庫操作
- 創建數據庫
# 創建音樂盒數據庫
CREATE DATABASE music_dbDEFAULT CHARACTER SET = 'utf8mb4';
- 使用數據庫
USE music_db;
- 創建用戶表
CREATE TABLE t_user(id int(11) PRIMARY KEY AUTO_INCREMENT, username VARCHAR(32),password VARCHAR(32)
);
- 創建音樂表
CREATE TABLE t_music(id int(11) PRIMARY KEY AUTO_INCREMENT,title VARCHAR(32),singer VARCHAR(32),path VARCHAR(256)
);
- 創建用戶播放列表
CREATE Table t_play_list(id int(11) PRIMARY KEY AUTO_INCREMENT,u_id int(11),m_id int(11),FOREIGN KEY(u_id) REFERENCES t_user(id),FOREIGN KEY(m_id) REFERENCES t_music(id)
);
- 插入用戶數據
insert into t_user(username, password) values('張三','123456');
2. 后端功能實現
1.登錄功能:
# 導包
from tools import DBUtil # 導入工具類:進行數據庫上的操作
import pygame # 用來播放音樂class MusicService:def __init__(self) -> None:self.user = Nonedef login(self,uname,pwd) -> bool:'''用戶登錄功能:param uname: 用戶名:param pwd: 密碼'''# 編寫sqlsql = "select id,username from t_user where username=%s and password=%s"# 創建工具類對象db = DBUtil()# 執行查詢操作res = db.query_one(sql,uname,pwd)# 判斷是否登錄成功if res:# print("賦值 self.user", self.user) # 這里應該看到 self.user 被正確賦值self.user = res print("登錄成功,歡迎使用")# print(self.user[0])return Trueelse:print("登錄失敗")return False
2.導入音樂:
def insert_music(self,files:tuple[str]) -> None:'''將導入的音樂添加到數據庫'''# 編寫sqlinsert_sql = "insert into t_music(title,path) values(%s,%s)"# 遍歷音樂文件for file in files:# print(file)name = file[file.rfind(" ")+1:file.rfind(".")]# 創建工具類對象db = DBUtil()# 執行sqlmid = db.execute_dml_back_id(insert_sql,name,file)# 維護用戶和音樂的對應關系# 創建工具類對象db = DBUtil()# 編寫sqlinsert_play_list_sql = "insert into t_play_list(u_id,m_id) values(%s,%s)"# 執行sqldb.execute_dml(insert_play_list_sql,self.user[0],mid)
3.查詢用戶音樂列表:
def find_user_music(self) -> list[str]:'''查詢用戶音樂列表:return: 音樂列表'''# 編寫sqlsql = "SELECT m.title from t_play_list p left join t_music m on p.m_id = m.id WHERE u_id = %s;"# 創建工具類對象db = DBUtil()# 執行sqlm_list = db.query_all(sql,self.user[0])return m_list
4.播放音樂:
def play_music(self,music_name:str) -> None:'''播放音樂:param m_name: 音樂名'''# 編寫sql:根據傳入的音樂名查找對應的音樂路徑sql = "SELECT m.path FROM t_play_list p left join t_music m on p.m_id = m.id WHERE u_id = %s and m.title = %s;"# 執行sql:獲取音樂路徑path = DBUtil().query_one(sql,self.user[0],music_name)[0]# 初始化混合器pygame.mixer.init()# 加載音樂pygame.mixer.music.load(path)# 播放音樂pygame.mixer.music.play()
5.刪除音樂:
def delete_music(self,music_name:str) -> None:'''刪除音樂:param: music_name: 音樂名'''# 編寫sql:根據傳入的音樂名查找要刪除的音樂idget_id_sql = "SELECT m.id from t_music m LEFT JOIN t_play_list p on m.id = p.m_id WHERE m.title = %s and p.u_id = %s;"# 執行sql:獲取音樂idmusic_id = DBUtil().query_one(get_id_sql,music_name,self.user[0])[0]# 編寫sql,并刪除播放列表中對應的音樂delete_play_list_sql = "DELETE FROM t_play_list WHERE u_id = %s and m_id = %s;"DBUtil().execute_dml(delete_play_list_sql,self.user[0],music_id)# 編寫sql,并刪除音樂表中對應的音樂delete_music_sql = "DELETE FROM t_music WHERE id = %s;"DBUtil().execute_dml(delete_music_sql,music_id)
3. 前端UI界面實現
1.初始化軟件窗口:
# 導包
import tkinter # 引入tkinter,繪畫界面
from service import MusicService # 引入服務層
from tkinter.filedialog import askopenfilenames # 引入文件選擇框class PlayWindow:'''軟件窗口'''def __init__(self) -> None:top = tkinter.Tk()# 創建按鈕btn1 = tkinter.Button(top,text='播放')btn2 = tkinter.Button(top,text='導入音樂')btn3 = tkinter.Button(top,text='刪除')# 創建播放列表self.listbox = tkinter.Listbox(top)# 設置按鈕的位置btn1.grid(row=0,column=0,padx=5,pady=5)btn2.grid(row=0,column=2,padx=5,pady=5)btn3.grid(row=0,column=4,padx=5,pady=5)# 設置播放列表的位置self.listbox.grid(row=1,column=0,columnspan=5,padx=5,pady=5)# 獲取用戶音樂播放列表self.load_music()# 綁定按鈕事件btn2.bind('<ButtonRelease-1>',self.import_music)btn1.bind('<ButtonRelease-1>',self.play_music)btn3.bind('<ButtonRelease-1>',self.delete_music)# 進入消息循環top.mainloop()
2.導入音樂按鈕事件綁定的方法:
def import_music(self,event):'''導入音樂'''print('導入音樂')# 彈出文件選擇框filenames = askopenfilenames(filetypes=[('mp3','*.mp3'),('flac','*.flac')])print(filenames)# 調用服務層# ms = MusicService()# 把導入的音樂插入到數據庫中ms.insert_music(filenames)# 導入新音樂后刷新播放列表self.load_music()
3.加載用戶音樂播放列表的方法:
def load_music(self):'''加載用戶音樂列表'''# 查詢當前用戶播放列表music_list = ms.find_user_music()# 清空播放列表self.listbox.delete(0,tkinter.END)# 遍歷列表,把音樂名添加到播放列表中for music in music_list:self.listbox.insert(0,music[0])
4.播放音樂按鈕綁定的方法:
def play_music(self,event):'''播放音樂'''# 獲取當前選中的音樂索引index = self.listbox.curselection()# 獲取當前選中的音樂名music_name = self.listbox.get(index)# print(music_name)# 播放音樂ms.play_music(music_name)
5.刪除音樂按鈕綁定的方法:
def delete_music(self,event):'''刪除音樂'''# 獲取當前選中的音樂索引index = self.listbox.curselection()# 根據音樂索引獲取音樂名music_name = self.listbox.get(index)# 調用后臺服務的刪除功能ms.delete_music(music_name)# 刷新播放列表self.load_music()
4. 程序入口
if __name__ == "__main__":# 輸入登錄信息uname = input('請輸入用戶名:')pwd = input('請輸入密碼:')# 創建服務對象ms = MusicService()if ms.login(uname,pwd):# 創建播放窗口pw = PlayWindow()
三、項目收獲
- 一種軟件設計思維:先明確要設計的軟件——>分析軟件各個功能并分成模塊——>前端頁面繪畫——>根據前端頁面設計與其頁面相綁定的后端方法——>后端方法要與數據庫交互
- 一個技巧:在編寫不確定的代碼的時候,可以使用調試模式,使用調試控制臺輸入代碼快速獲得相應的變量輸出,從而快速確定要編寫的代碼。
這樣可以有效的避免多次運行才能獲得正確代碼的情況,這在大型軟件的設計中很有用!!!
- 對軟件設計的認知:設計和編寫前端頁面、根據前端頁面實現功能;其中有一個重點:后端服務層的功能重點是與數據庫的交互,根據數據庫返回的數據進行條件判斷,提取數據庫的數據進行信息呈現和功能實現。