寫完這段代碼,又空虛了。
作者:林林zonzon?|?編輯:Jack?Cui?
https://blog.csdn.net/zujiasheng/article/details/124670676
大家好,我是 Jack。
今天分享個(gè) Python 實(shí)戰(zhàn)小項(xiàng)目,久違的基礎(chǔ)教程!
同時(shí),也有不少小伙伴問過我,怎么打包 Python 程序?yàn)?exe 可執(zhí)行文件,正好今天的實(shí)戰(zhàn)一起講解。
用 Python 做個(gè)屬于自己的寵物桌面,對(duì)原理和代碼進(jìn)行了詳細(xì)講解,非常適合新手~
一、桌面寵物素材
1.1 需要準(zhǔn)備什么素材
桌面寵物的各種動(dòng)畫效果,可以看作是由一個(gè)個(gè)GIF動(dòng)圖拼接而成,我們需要準(zhǔn)備多組GIF動(dòng)圖來實(shí)現(xiàn)桌面寵物的動(dòng)作切換。

最好選取是白底的GIF動(dòng)圖。
1.2 介紹幾種獲得GIF動(dòng)圖的方式
1.2.1 通過pr實(shí)現(xiàn)視頻轉(zhuǎn)GIF
pr在導(dǎo)出的時(shí)候選擇動(dòng)畫GIF可以直接導(dǎo)出GIF動(dòng)圖。
當(dāng)然了想要白底就需要自己用“蒙版”和畫筆工具自己摳圖。
1.2.2 通過ps實(shí)現(xiàn)圖片組轉(zhuǎn)GIF
ps會(huì)高級(jí)一點(diǎn),首先點(diǎn)擊最上方的窗口,再點(diǎn)擊時(shí)間軸,在下方顯示出的時(shí)間軸的最右邊的加號(hào)可以添加你想要添加的圖片。圖層右邊可以選擇刪除背景。
然后選擇最上方的文件,選擇導(dǎo)出,選擇導(dǎo)出為web所用格式舊版,即可。

1.2.3 百度一下,獲取網(wǎng)上現(xiàn)成的GIF資源
1)百度:“制作GIF動(dòng)圖”
2)百度:“GIF動(dòng)圖資源”
或者干脆找個(gè)2D游戲素材網(wǎng)站也行,里面有很多角色人物素材在里面。
二、python實(shí)現(xiàn)代碼
2.1 目錄結(jié)構(gòu)
項(xiàng)目的目錄結(jié)構(gòu)整體如下:main.py為主程序代碼。
normal下的GIF圖是寵物平常會(huì)隨機(jī)切換的動(dòng)作GIF圖, click下面的GIF圖是點(diǎn)擊寵物之后的寵物動(dòng)作的GIF圖。
dialog.txt 記錄了寵物的對(duì)話信息。
tigerIcon.jpg是縮小到托盤后托盤圖標(biāo)的圖片。
2.2 實(shí)現(xiàn)代碼
2.2.1 引用包
os包用于加載文件,sys包用于退出程序,random包用于程序中一些需要調(diào)用隨機(jī)數(shù)的操作。其他的三個(gè)包則是用于實(shí)現(xiàn)桌面寵物的基礎(chǔ)。
import?os
import?sys
import?random
from?PyQt5.QtGui?import?*
from?PyQt5.QtCore?import?*
from?PyQt5.QtWidgets?import?*
2.2.2 主代碼部分
if?__name__?==?'__main__':
????#?創(chuàng)建了一個(gè)QApplication對(duì)象,對(duì)象名為app,帶兩個(gè)參數(shù)argc,argv
????#?所有的PyQt5應(yīng)用必須創(chuàng)建一個(gè)應(yīng)用(Application)對(duì)象。sys.argv參數(shù)是一個(gè)來自命令行的參數(shù)列表。
????app?=?QApplication(sys.argv)
????#?窗口組件初始化
????pet?=?DesktopPet()
????# 1. 進(jìn)入時(shí)間循環(huán);
????# 2. wait,直到響應(yīng)app可能的輸入;
????# 3. QT接收和處理用戶及系統(tǒng)交代的事件(消息),并傳遞到各個(gè)窗口;
????# 4. 程序遇到exit()退出時(shí),機(jī)會(huì)返回exec()的值。
????sys.exit(app.exec_())
2.2.3 代碼運(yùn)行流程
整個(gè)運(yùn)行流程為:
通過self.init():實(shí)現(xiàn)窗體的初始化,寵物的GIF圖在這個(gè)窗體中播放
通過self.initPall():配置托盤化
通過self.initPetImage():將寵物的靜態(tài)GIF資源,包括對(duì)話和GIF動(dòng)圖進(jìn)行加載
通過self.petNormalAction():實(shí)現(xiàn)寵物隨機(jī)切換動(dòng)作和語句的功能
class?DesktopPet(QWidget):
????def?__init__(self,?parent=None,?**kwargs):
????????super(DesktopPet,?self).__init__(parent)
????????#?窗體初始化
????????self.init()
????????#?托盤化初始
????????self.initPall()
????????#?寵物靜態(tài)gif圖加載
????????self.initPetImage()
????????#?寵物正常待機(jī),實(shí)現(xiàn)隨機(jī)切換動(dòng)作
????????self.petNormalAction()
1、加載顯示GIF動(dòng)圖的窗體,通過函數(shù)init實(shí)現(xiàn),其代碼配置如下:
這幾句的作用是對(duì)展示寵物的窗體進(jìn)行一些初步的設(shè)置,使得白色GIF圖能夠去掉背景的白色,將GIF圖透明的展示出來。
#?窗體初始化
def?init(self):
????#?初始化
????#?設(shè)置窗口屬性:窗口無標(biāo)題欄且固定在最前面
????#?FrameWindowHint:無邊框窗口
????#?WindowStaysOnTopHint:?窗口總顯示在最上面
????#?SubWindow:?新窗口部件是一個(gè)子窗口,而無論窗口部件是否有父窗口部件
????#?https://blog.csdn.net/kaida1234/article/details/79863146
????self.setWindowFlags(Qt.FramelessWindowHint?|?Qt.WindowStaysOnTopHint?|?Qt.SubWindow)
????#?setAutoFillBackground(True)表示的是自動(dòng)填充背景,False為透明背景
????self.setAutoFillBackground(False)
????#?窗口透明,窗體空間不透明
????self.setAttribute(Qt.WA_TranslucentBackground,?True)
????#?重繪組件、刷新
????self.repaint()
2、實(shí)現(xiàn)能托盤顯示的功能,通過函數(shù)initPall實(shí)現(xiàn),其代碼配置如下:
主要有下面這幾個(gè)操作:
(1)讀取靜態(tài)圖片資源設(shè)置托盤化的圖標(biāo)。
(2)設(shè)置托盤化圖片點(diǎn)擊右鍵顯示的菜單,并對(duì)這些菜單的點(diǎn)擊操作進(jìn)行設(shè)置。
流程代碼如下:
#?托盤化設(shè)置初始化
def?initPall(self):
????#?導(dǎo)入準(zhǔn)備在托盤化顯示上使用的圖標(biāo)
????icons?=?os.path.join('tigerIcon.jpg')
????#?設(shè)置右鍵顯示最小化的菜單項(xiàng)
????#?菜單項(xiàng)退出,點(diǎn)擊后調(diào)用quit函數(shù)
????quit_action?=?QAction('退出',?self,?triggered=self.quit)
????#?設(shè)置這個(gè)點(diǎn)擊選項(xiàng)的圖片
????quit_action.setIcon(QIcon(icons))
????#?菜單項(xiàng)顯示,點(diǎn)擊后調(diào)用showing函數(shù)
????showing?=?QAction(u'顯示',?self,?triggered=self.showwin)
????#?新建一個(gè)菜單項(xiàng)控件
????self.tray_icon_menu?=?QMenu(self)
????#?在菜單欄添加一個(gè)無子菜單的菜單項(xiàng)‘退出’
????self.tray_icon_menu.addAction(quit_action)
????#?在菜單欄添加一個(gè)無子菜單的菜單項(xiàng)‘顯示’
????self.tray_icon_menu.addAction(showing)
????#?QSystemTrayIcon類為應(yīng)用程序在系統(tǒng)托盤中提供一個(gè)圖標(biāo)
????self.tray_icon?=?QSystemTrayIcon(self)
????#?設(shè)置托盤化圖標(biāo)
????self.tray_icon.setIcon(QIcon(icons))
????#?設(shè)置托盤化菜單項(xiàng)
????self.tray_icon.setContextMenu(self.tray_icon_menu)
????#?展示
????self.tray_icon.show()
其中‘退出’項(xiàng)涉及到的函數(shù)代碼如下:
#?退出操作,關(guān)閉程序
def?quit(self):
????self.close()
????sys.exit()
其中‘顯示’項(xiàng)涉及到的函數(shù)代碼如下:
#?顯示寵物
def?showwin(self):
????#?setWindowOpacity()設(shè)置窗體的透明度,通過調(diào)整窗體透明度實(shí)現(xiàn)寵物的展示和隱藏
????self.setWindowOpacity(1)
3、寵物靜態(tài)資源的加載,通過函數(shù)initPetImage實(shí)現(xiàn),其代碼配置如下:
靜態(tài)資源的加載主要涉及兩個(gè)部分,對(duì)話框內(nèi)容的加載和圖片內(nèi)容的加載。
#?寵物靜態(tài)gif圖加載
def?initPetImage(self):
????#?對(duì)話框定義
????self.talkLabel?=?QLabel(self)
????#?對(duì)話框樣式設(shè)計(jì)
????self.talkLabel.setStyleSheet("font:15pt?'楷體';border-width:?1px;color:blue;")?
????#?定義顯示圖片部分
????self.image?=?QLabel(self)
????#?QMovie是一個(gè)可以存放動(dòng)態(tài)視頻的類,一般是配合QLabel使用的,可以用來存放GIF動(dòng)態(tài)圖
????self.movie?=?QMovie("normal/normal1.gif")
????#?設(shè)置標(biāo)簽大小
????self.movie.setScaledSize(QSize(200,?200))
????#?將Qmovie在定義的image中顯示
????self.image.setMovie(self.movie)
????self.movie.start()
????self.resize(1024,?1024)
????#?調(diào)用自定義的randomPosition,會(huì)使得寵物出現(xiàn)位置隨機(jī)
????self.randomPosition()
????#?展示
????self.show()
????#?https://new.qq.com/rain/a/20211014a002rs00
????#?將寵物正常待機(jī)狀態(tài)的動(dòng)圖放入pet1中
????self.pet1?=?[]
????for?i?in?os.listdir("normal"):
????????self.pet1.append("normal/"?+?i)
????#?將寵物正常待機(jī)狀態(tài)的對(duì)話放入pet2中
????self.dialog?=?[]
????#?讀取目錄下dialog文件
????with?open("dialog.txt",?"r")?as?f:
????????text?=?f.read()
????????#?以\n?即換行符為分隔符,分割放進(jìn)dialog中
????????self.dialog?=?text.split("\n")
其中我們希望寵物出現(xiàn)的位置是隨機(jī)的而不是固定的,那么便通過 randomPosition()實(shí)現(xiàn)寵物出現(xiàn)位置的隨機(jī)。
#?寵物隨機(jī)位置
def?randomPosition(self):
????#?screenGeometry()函數(shù)提供有關(guān)可用屏幕幾何的信息
????screen_geo?=?QDesktopWidget().screenGeometry()
????#?獲取窗口坐標(biāo)系
????pet_geo?=?self.geometry()
????width?=?(screen_geo.width()?-?pet_geo.width())?*?random.random()
????height?=?(screen_geo.height()?-?pet_geo.height())?*?random.random()
????self.move(width,?height)
4、寵物正常待機(jī),實(shí)現(xiàn)隨機(jī)切換動(dòng)作,對(duì)話框通過函數(shù)petNormalAction實(shí)現(xiàn),其代碼配置如下
這里通過QTimer實(shí)現(xiàn)定時(shí)操作,到達(dá)設(shè)置的時(shí)間即調(diào)用相關(guān)的函數(shù)。其中condition為標(biāo)識(shí)寵物狀態(tài)的flag,0為平常狀態(tài),1為點(diǎn)擊狀態(tài),這個(gè)狀態(tài)可按照自己的喜好拓展。talk_condition同理,為標(biāo)識(shí)寵物對(duì)話狀態(tài)的flag。
#?寵物正常待機(jī)動(dòng)作
def?petNormalAction(self):
????#?每隔一段時(shí)間做個(gè)動(dòng)作
????#?定時(shí)器設(shè)置
????self.timer?=?QTimer()
????#?時(shí)間到了自動(dòng)執(zhí)行
????self.timer.timeout.connect(self.randomAct)
????#?動(dòng)作時(shí)間切換設(shè)置
????self.timer.start(3000)
????#?寵物狀態(tài)設(shè)置為正常
????self.condition?=?0
????#?每隔一段時(shí)間切換對(duì)話
????self.talkTimer?=?QTimer()
????self.talkTimer.timeout.connect(self.talk)
????self.talkTimer.start(3000)
????#?對(duì)話狀態(tài)設(shè)置為常態(tài)
????self.talk_condition?=?0
????#?寵物對(duì)話框
????self.talk()
其中,通過randomAct實(shí)現(xiàn)寵物動(dòng)作的隨機(jī)切換,通過talk實(shí)現(xiàn)對(duì)話框內(nèi)容的切換,其代碼如下:
self.pet1和self.dialog在初始化的時(shí)候即定義了。這里可以按照自己的喜好進(jìn)行拓展,用多個(gè)if-else if實(shí)現(xiàn)多種狀態(tài)的切換和定義,增加一些喂食,玩耍動(dòng)作等。
#?隨機(jī)動(dòng)作切換
def?randomAct(self):
????#?condition記錄寵物狀態(tài),寵物狀態(tài)為0時(shí),代表正常待機(jī)
????if?not?self.condition:
????????#?隨機(jī)選擇裝載在pet1里面的gif圖進(jìn)行展示,實(shí)現(xiàn)隨機(jī)切換
????????self.movie?=?QMovie(random.choice(self.pet1))
????????#?寵物大小
????????self.movie.setScaledSize(QSize(200,?200))
????????#?將動(dòng)畫添加到label中
????????self.image.setMovie(self.movie)
????????#?開始播放動(dòng)畫
????????self.movie.start()
????#?condition不為0,轉(zhuǎn)為切換特有的動(dòng)作,實(shí)現(xiàn)寵物的點(diǎn)擊反饋
????#?這里可以通過else-if語句往下拓展做更多的交互功能
????else:
????????#?讀取特殊狀態(tài)圖片路徑
????????self.movie?=?QMovie("./click/click.gif")
????????#?寵物大小
????????self.movie.setScaledSize(QSize(200,?200))
????????#?將動(dòng)畫添加到label中
????????self.image.setMovie(self.movie)
????????#?開始播放動(dòng)畫
????????self.movie.start()
????????#?寵物狀態(tài)設(shè)置為正常待機(jī)
????????self.condition?=?0
????????self.talk_condition?=?0
#?寵物對(duì)話框行為處理
def?talk(self):
????if?not?self.talk_condition:
????????#?talk_condition為0則選取加載在dialog中的語句
????????self.talkLabel.setText(random.choice(self.dialog))
????????#?設(shè)置樣式
????????self.talkLabel.setStyleSheet(
????????????"font:?bold;"
????????????"font:25pt?'楷體';"
????????????"color:white;"
????????????"background-color:?white"
????????????"url(:/)"
????????)
????????#?根據(jù)內(nèi)容自適應(yīng)大小
????????self.talkLabel.adjustSize()
????else:
????????#?talk_condition為1顯示為別點(diǎn)我,這里同樣可以通過if-else-if來拓展對(duì)應(yīng)的行為
????????self.talkLabel.setText("別點(diǎn)我")
????????self.talkLabel.setStyleSheet(
????????????"font:?bold;"
????????????"font:25pt?'楷體';"
????????????"color:white;"
????????????"background-color:?white"
????????????"url(:/)"
????????)
????????self.talkLabel.adjustSize()
????????#?設(shè)置為正常狀態(tài)
????????self.talk_condition?=?0
5、實(shí)現(xiàn)能夠拖動(dòng)寵物,通過多個(gè)自帶函數(shù)實(shí)現(xiàn),其代碼配置如下:
實(shí)現(xiàn)寵物的拖動(dòng)主要通過三個(gè)函數(shù)實(shí)現(xiàn),mouserPressEvent負(fù)責(zé)在鼠標(biāo)點(diǎn)擊判斷其是否在寵物窗口上,如果在則將寵物和鼠標(biāo)的位置綁定,并執(zhí)行點(diǎn)擊改變寵物GIF圖和對(duì)話框的操作。
mouseMoveEvent實(shí)現(xiàn)按下后寵物跟著鼠標(biāo)移動(dòng)
mouseReleaseEvent將之前的鎖定取消
#?鼠標(biāo)左鍵按下時(shí),?寵物將和鼠標(biāo)位置綁定
def?mousePressEvent(self,?event):
????#?更改寵物狀態(tài)為點(diǎn)擊
????self.condition?=?1
????#?更改寵物對(duì)話狀態(tài)
????self.talk_condition?=?1
????#?即可調(diào)用對(duì)話狀態(tài)改變
????self.talk()
????#?即刻加載寵物點(diǎn)擊動(dòng)畫
????self.randomAct()
????if?event.button()?==?Qt.LeftButton:
????????self.is_follow_mouse?=?True
????#?globalPos()?事件觸發(fā)點(diǎn)相對(duì)于桌面的位置
????#?pos()?程序相對(duì)于桌面左上角的位置,實(shí)際是窗口的左上角坐標(biāo)
????self.mouse_drag_pos?=?event.globalPos()?-?self.pos()
????event.accept()
????#?拖動(dòng)時(shí)鼠標(biāo)圖形的設(shè)置
????self.setCursor(QCursor(Qt.OpenHandCursor))
#?鼠標(biāo)移動(dòng)時(shí)調(diào)用,實(shí)現(xiàn)寵物隨鼠標(biāo)移動(dòng)
def?mouseMoveEvent(self,?event):
????#?如果鼠標(biāo)左鍵按下,且處于綁定狀態(tài)
????if?Qt.LeftButton?and?self.is_follow_mouse:
????????#?寵物隨鼠標(biāo)進(jìn)行移動(dòng)
????????self.move(event.globalPos()?-?self.mouse_drag_pos)
????event.accept()
#?鼠標(biāo)釋放調(diào)用,取消綁定
def?mouseReleaseEvent(self,?event):
????self.is_follow_mouse?=?False
????#?鼠標(biāo)圖形設(shè)置為箭頭
????self.setCursor(QCursor(Qt.ArrowCursor))
6、實(shí)現(xiàn)寵物右鍵點(diǎn)擊具有交互功能,通過函數(shù)contextMenuEvent實(shí)現(xiàn),其代碼配置如下:
退出操作通過 qApp.quit()實(shí)現(xiàn),直接退出相應(yīng)的QT程序。
隱藏操作則通過self.setWindowOpacity(0)實(shí)現(xiàn),這個(gè)可控制窗口的透明度。
#?寵物右鍵點(diǎn)擊交互
def?contextMenuEvent(self,?event):
????#?定義菜單
????menu?=?QMenu(self)
????#?定義菜單項(xiàng)
????quitAction?=?menu.addAction("退出")
????hide?=?menu.addAction("隱藏")
????#?使用exec_()方法顯示菜單。從鼠標(biāo)右鍵事件對(duì)象中獲得當(dāng)前坐標(biāo)。mapToGlobal()方法把當(dāng)前組件的相對(duì)坐標(biāo)轉(zhuǎn)換為窗口(window)的絕對(duì)坐標(biāo)。
????action?=?menu.exec_(self.mapToGlobal(event.pos()))
????#?點(diǎn)擊事件為退出
????if?action?==?quitAction:
????????qApp.quit()
????#?點(diǎn)擊事件為隱藏
????if?action?==?hide:
????????#?通過設(shè)置透明度方式隱藏寵物
????????self.setWindowOpacity(0)
7、鼠標(biāo)移到寵物上的時(shí)候顯示為閉合的手
#?鼠標(biāo)移進(jìn)時(shí)調(diào)用
def?enterEvent(self,?event):
????#?設(shè)置鼠標(biāo)形狀 Qt.ClosedHandCursor ??非指向手
????self.setCursor(Qt.ClosedHandCursor)
2.2.3 完整源碼
import?os
import?sys
import?random
from?PyQt5.QtGui?import?*
from?PyQt5.QtCore?import?*
from?PyQt5.QtWidgets?import?*
?
?
class?DesktopPet(QWidget):
????def?__init__(self,?parent=None,?**kwargs):
????????super(DesktopPet,?self).__init__(parent)
????????#?窗體初始化
????????self.init()
????????#?托盤化初始
????????self.initPall()
????????#?寵物靜態(tài)gif圖加載
????????self.initPetImage()
????????#?寵物正常待機(jī),實(shí)現(xiàn)隨機(jī)切換動(dòng)作
????????self.petNormalAction()
?
?
????#?窗體初始化
????def?init(self):
????????#?初始化
????????#?設(shè)置窗口屬性:窗口無標(biāo)題欄且固定在最前面
????????#?FrameWindowHint:無邊框窗口
????????#?WindowStaysOnTopHint:?窗口總顯示在最上面
????????#?SubWindow:?新窗口部件是一個(gè)子窗口,而無論窗口部件是否有父窗口部件
????????#?https://blog.csdn.net/kaida1234/article/details/79863146
????????self.setWindowFlags(Qt.FramelessWindowHint?|?Qt.WindowStaysOnTopHint?|?Qt.SubWindow)
????????#?setAutoFillBackground(True)表示的是自動(dòng)填充背景,False為透明背景
????????self.setAutoFillBackground(False)
????????#?窗口透明,窗體空間不透明
????????self.setAttribute(Qt.WA_TranslucentBackground,?True)
????????#?重繪組件、刷新
????????self.repaint()
?
????#?托盤化設(shè)置初始化
????def?initPall(self):
????????#?導(dǎo)入準(zhǔn)備在托盤化顯示上使用的圖標(biāo)
????????icons?=?os.path.join('tigerIcon.jpg')
????????#?設(shè)置右鍵顯示最小化的菜單項(xiàng)
????????#?菜單項(xiàng)退出,點(diǎn)擊后調(diào)用quit函數(shù)
????????quit_action?=?QAction('退出',?self,?triggered=self.quit)
????????#?設(shè)置這個(gè)點(diǎn)擊選項(xiàng)的圖片
????????quit_action.setIcon(QIcon(icons))
????????#?菜單項(xiàng)顯示,點(diǎn)擊后調(diào)用showing函數(shù)
????????showing?=?QAction(u'顯示',?self,?triggered=self.showwin)
????????#?新建一個(gè)菜單項(xiàng)控件
????????self.tray_icon_menu?=?QMenu(self)
????????#?在菜單欄添加一個(gè)無子菜單的菜單項(xiàng)‘退出’
????????self.tray_icon_menu.addAction(quit_action)
????????#?在菜單欄添加一個(gè)無子菜單的菜單項(xiàng)‘顯示’
????????self.tray_icon_menu.addAction(showing)
????????#?QSystemTrayIcon類為應(yīng)用程序在系統(tǒng)托盤中提供一個(gè)圖標(biāo)
????????self.tray_icon?=?QSystemTrayIcon(self)
????????#?設(shè)置托盤化圖標(biāo)
????????self.tray_icon.setIcon(QIcon(icons))
????????#?設(shè)置托盤化菜單項(xiàng)
????????self.tray_icon.setContextMenu(self.tray_icon_menu)
????????#?展示
????????self.tray_icon.show()
?
????#?寵物靜態(tài)gif圖加載
????def?initPetImage(self):
????????#?對(duì)話框定義
????????self.talkLabel?=?QLabel(self)
????????#?對(duì)話框樣式設(shè)計(jì)
????????self.talkLabel.setStyleSheet("font:15pt?'楷體';border-width:?1px;color:blue;")
????????#?定義顯示圖片部分
????????self.image?=?QLabel(self)
????????#?QMovie是一個(gè)可以存放動(dòng)態(tài)視頻的類,一般是配合QLabel使用的,可以用來存放GIF動(dòng)態(tài)圖
????????self.movie?=?QMovie("normal/normal1.gif")
????????#?設(shè)置標(biāo)簽大小
????????self.movie.setScaledSize(QSize(200,?200))
????????#?將Qmovie在定義的image中顯示
????????self.image.setMovie(self.movie)
????????self.movie.start()
????????self.resize(1024,?1024)
????????#?調(diào)用自定義的randomPosition,會(huì)使得寵物出現(xiàn)位置隨機(jī)
????????self.randomPosition()
????????#?展示
????????self.show()
????????#?https://new.qq.com/rain/a/20211014a002rs00
????????#?將寵物正常待機(jī)狀態(tài)的動(dòng)圖放入pet1中
????????self.pet1?=?[]
????????for?i?in?os.listdir("normal"):
????????????self.pet1.append("normal/"?+?i)
????????#?將寵物正常待機(jī)狀態(tài)的對(duì)話放入pet2中
????????self.dialog?=?[]
????????#?讀取目錄下dialog文件
????????with?open("dialog.txt",?"r")?as?f:
????????????text?=?f.read()
????????????#?以\n?即換行符為分隔符,分割放進(jìn)dialog中
????????????self.dialog?=?text.split("\n")
?
????#?寵物正常待機(jī)動(dòng)作
????def?petNormalAction(self):
????????#?每隔一段時(shí)間做個(gè)動(dòng)作
????????#?定時(shí)器設(shè)置
????????self.timer?=?QTimer()
????????#?時(shí)間到了自動(dòng)執(zhí)行
????????self.timer.timeout.connect(self.randomAct)
????????#?動(dòng)作時(shí)間切換設(shè)置
????????self.timer.start(3000)
????????#?寵物狀態(tài)設(shè)置為正常
????????self.condition?=?0
????????#?每隔一段時(shí)間切換對(duì)話
????????self.talkTimer?=?QTimer()
????????self.talkTimer.timeout.connect(self.talk)
????????self.talkTimer.start(3000)
????????#?對(duì)話狀態(tài)設(shè)置為常態(tài)
????????self.talk_condition?=?0
????????#?寵物對(duì)話框
????????self.talk()
?
????#?隨機(jī)動(dòng)作切換
????def?randomAct(self):
????????#?condition記錄寵物狀態(tài),寵物狀態(tài)為0時(shí),代表正常待機(jī)
????????if?not?self.condition:
????????????#?隨機(jī)選擇裝載在pet1里面的gif圖進(jìn)行展示,實(shí)現(xiàn)隨機(jī)切換
????????????self.movie?=?QMovie(random.choice(self.pet1))
????????????#?寵物大小
????????????self.movie.setScaledSize(QSize(200,?200))
????????????#?將動(dòng)畫添加到label中
????????????self.image.setMovie(self.movie)
????????????#?開始播放動(dòng)畫
????????????self.movie.start()
????????#?condition不為0,轉(zhuǎn)為切換特有的動(dòng)作,實(shí)現(xiàn)寵物的點(diǎn)擊反饋
????????#?這里可以通過else-if語句往下拓展做更多的交互功能
????????else:
????????????#?讀取特殊狀態(tài)圖片路徑
????????????self.movie?=?QMovie("./click/click.gif")
????????????#?寵物大小
????????????self.movie.setScaledSize(QSize(200,?200))
????????????#?將動(dòng)畫添加到label中
????????????self.image.setMovie(self.movie)
????????????#?開始播放動(dòng)畫
????????????self.movie.start()
????????????#?寵物狀態(tài)設(shè)置為正常待機(jī)
????????????self.condition?=?0
????????????self.talk_condition?=?0
?
????#?寵物對(duì)話框行為處理
????def?talk(self):
????????if?not?self.talk_condition:
????????????#?talk_condition為0則選取加載在dialog中的語句
????????????self.talkLabel.setText(random.choice(self.dialog))
????????????#?設(shè)置樣式
????????????self.talkLabel.setStyleSheet(
????????????????"font:?bold;"
????????????????"font:25pt?'楷體';"
????????????????"color:white;"
????????????????"background-color:?white"
????????????????"url(:/)"
????????????)
????????????#?根據(jù)內(nèi)容自適應(yīng)大小
????????????self.talkLabel.adjustSize()
????????else:
????????????#?talk_condition為1顯示為別點(diǎn)我,這里同樣可以通過if-else-if來拓展對(duì)應(yīng)的行為
????????????self.talkLabel.setText("別點(diǎn)我")
????????????self.talkLabel.setStyleSheet(
????????????????"font:?bold;"
????????????????"font:25pt?'楷體';"
????????????????"color:white;"
????????????????"background-color:?white"
????????????????"url(:/)"
????????????)
????????????self.talkLabel.adjustSize()
????????????#?設(shè)置為正常狀態(tài)
????????????self.talk_condition?=?0
?
????#?退出操作,關(guān)閉程序
????def?quit(self):
????????self.close()
????????sys.exit()
?
????#?顯示寵物
????def?showwin(self):
????????#?setWindowOpacity()設(shè)置窗體的透明度,通過調(diào)整窗體透明度實(shí)現(xiàn)寵物的展示和隱藏
????????self.setWindowOpacity(1)
?
????#?寵物隨機(jī)位置
????def?randomPosition(self):
????????screen_geo?=?QDesktopWidget().screenGeometry()
????????pet_geo?=?self.geometry()
????????width?=?(screen_geo.width()?-?pet_geo.width())?*?random.random()
????????height?=?(screen_geo.height()?-?pet_geo.height())?*?random.random()
????????self.move(width,?height)
?
????#?鼠標(biāo)左鍵按下時(shí),?寵物將和鼠標(biāo)位置綁定
????def?mousePressEvent(self,?event):
????????#?更改寵物狀態(tài)為點(diǎn)擊
????????self.condition?=?1
????????#?更改寵物對(duì)話狀態(tài)
????????self.talk_condition?=?1
????????#?即可調(diào)用對(duì)話狀態(tài)改變
????????self.talk()
????????#?即刻加載寵物點(diǎn)擊動(dòng)畫
????????self.randomAct()
????????if?event.button()?==?Qt.LeftButton:
????????????self.is_follow_mouse?=?True
????????#?globalPos()?事件觸發(fā)點(diǎn)相對(duì)于桌面的位置
????????#?pos()?程序相對(duì)于桌面左上角的位置,實(shí)際是窗口的左上角坐標(biāo)
????????self.mouse_drag_pos?=?event.globalPos()?-?self.pos()
????????event.accept()
????????#?拖動(dòng)時(shí)鼠標(biāo)圖形的設(shè)置
????????self.setCursor(QCursor(Qt.OpenHandCursor))
?
????#?鼠標(biāo)移動(dòng)時(shí)調(diào)用,實(shí)現(xiàn)寵物隨鼠標(biāo)移動(dòng)
????def?mouseMoveEvent(self,?event):
????????#?如果鼠標(biāo)左鍵按下,且處于綁定狀態(tài)
????????if?Qt.LeftButton?and?self.is_follow_mouse:
????????????#?寵物隨鼠標(biāo)進(jìn)行移動(dòng)
????????????self.move(event.globalPos()?-?self.mouse_drag_pos)
????????event.accept()
?
????#?鼠標(biāo)釋放調(diào)用,取消綁定
????def?mouseReleaseEvent(self,?event):
????????self.is_follow_mouse?=?False
????????#?鼠標(biāo)圖形設(shè)置為箭頭
????????self.setCursor(QCursor(Qt.ArrowCursor))
?
?
????#?鼠標(biāo)移進(jìn)時(shí)調(diào)用
????def?enterEvent(self,?event):
????????#?設(shè)置鼠標(biāo)形狀?Qt.ClosedHandCursor???非指向手
????????self.setCursor(Qt.ClosedHandCursor)
?
????#?寵物右鍵點(diǎn)擊交互
????def?contextMenuEvent(self,?event):
????????#?定義菜單
????????menu?=?QMenu(self)
????????#?定義菜單項(xiàng)
????????quitAction?=?menu.addAction("退出")
????????hide?=?menu.addAction("隱藏")
????????#?使用exec_()方法顯示菜單。從鼠標(biāo)右鍵事件對(duì)象中獲得當(dāng)前坐標(biāo)。mapToGlobal()方法把當(dāng)前組件的相對(duì)坐標(biāo)轉(zhuǎn)換為窗口(window)的絕對(duì)坐標(biāo)。
????????action?=?menu.exec_(self.mapToGlobal(event.pos()))
????????#?點(diǎn)擊事件為退出
????????if?action?==?quitAction:
????????????qApp.quit()
????????#?點(diǎn)擊事件為隱藏
????????if?action?==?hide:
????????????#?通過設(shè)置透明度方式隱藏寵物
????????????self.setWindowOpacity(0)
?
?
if?__name__?==?'__main__':
????#?創(chuàng)建了一個(gè)QApplication對(duì)象,對(duì)象名為app,帶兩個(gè)參數(shù)argc,argv
????#?所有的PyQt5應(yīng)用必須創(chuàng)建一個(gè)應(yīng)用(Application)對(duì)象。sys.argv參數(shù)是一個(gè)來自命令行的參數(shù)列表。
????app?=?QApplication(sys.argv)
????#?窗口組件初始化
????pet?=?DesktopPet()
????# 1. 進(jìn)入時(shí)間循環(huán);
????# 2. wait,直到響應(yīng)app可能的輸入;
????# 3. QT接收和處理用戶及系統(tǒng)交代的事件(消息),并傳遞到各個(gè)窗口;
????# 4. 程序遇到exit()退出時(shí),機(jī)會(huì)返回exec()的值。
????sys.exit(app.exec_())
三、程序打包
3.1 安裝pyinstaller
pip?install?pyinstaller?
如果提示黃色提示pip版本問題,照著上面的提示修改即可。
3.2 項(xiàng)目目錄下完成打包
進(jìn)入打開cmd命令行,進(jìn)入項(xiàng)目目錄,輸入命令
pyinstaller?-F?-w?main.py
打包完成后,在生成的dist里面可以看到main.exe文件。
將main.exe放到主目錄下就可正常運(yùn)行。
四、總結(jié)與參考資料
4.1 項(xiàng)目百度網(wǎng)盤:
已經(jīng)將代碼和exe文件,打包。
DeskTopPetEXE為帶打包好的文件。
DeskTopPet是打包前的文件。
公眾號(hào)后臺(tái)回復(fù):桌面寵物,即可下載。
寫之前挺開心的,寫的時(shí)候也挺開心的,寫完之后就有點(diǎn)索然無味了。

純粹是因?yàn)闊o聊寫著玩的,下次再試試能不能弄個(gè)3D的。

推薦閱讀
?? ?我與身旁的美女,格格不入,我決定...?? ?請(qǐng)做好3年內(nèi)隨時(shí)失業(yè)的準(zhǔn)備?????該死,這糟糕的心動(dòng)感
