用Python制作一個(gè)可以聊天的皮卡丘版桌面寵物
導(dǎo)語(yǔ)
前段時(shí)間有小伙伴留言說(shuō)想讓我?guī)Т蠹覍?xiě)寫(xiě)桌面小掛件,今天就滿足一下留過(guò)類似言的小伙伴的請(qǐng)求唄~不過(guò)感覺(jué)寫(xiě)桌面的掛歷啥的沒(méi)意思,就簡(jiǎn)單帶大家做一只桌面寵物吧~
廢話不多說(shuō),讓我們愉快地開(kāi)始吧~
開(kāi)發(fā)工具
Python版本:3.6.4
相關(guān)模塊:
PyQt5模塊;
以及一些Python自帶的模塊
原理簡(jiǎn)介
既然要寫(xiě)個(gè)桌面寵物,首先當(dāng)然是要找寵物的圖片素材啦。這里我們使用的是來(lái)自shimiji這款手機(jī)APP上的寵物圖片素材,例如皮卡丘:
我下了大約60多種寵物的圖片素材供大家選擇:
在相關(guān)文件里都打包一起提供了,所以這里就不分享爬蟲(chóng)代碼了(我挑選了一下,只要不是我覺(jué)得特別丑的,我基本都保留了),別給人家服務(wù)器帶來(lái)不必要的壓力。
接下來(lái),我們就可以開(kāi)始設(shè)計(jì)我們的桌面寵物啦。鑒于網(wǎng)上用python寫(xiě)的桌面掛件基本都是基于tkinter的,為了突出公眾號(hào)的與眾不同,這里我們采用PyQt5來(lái)實(shí)現(xiàn)我們的桌面寵物。
步驟實(shí)現(xiàn)
首先,我們來(lái)初始化一個(gè)桌面寵物的窗口組件:
class DesktopPet(QWidget): def __init__(self, parent=None, **kwargs): super(DesktopPet, self).__init__(parent) self.show()
它的效果是這樣子的:
接下來(lái),我們?cè)O(shè)置一下窗口的屬性讓更適合作為一個(gè)寵物的窗口:
# 初始化 self.setWindowFlags(Qt.FramelessWindowHint|Qt.WindowStaysOnTopHint|Qt.SubWindow) self.setAutoFillBackground(False) self.setAttribute(Qt.WA_TranslucentBackground, True) self.repaint()
并隨機(jī)導(dǎo)入一張寵物圖片來(lái)看看運(yùn)行效果:
# 隨機(jī)導(dǎo)入一個(gè)寵物 self.pet_images, iconpath = self.randomLoadPetImages() # 當(dāng)前顯示的圖片 self.image = QLabel(self) self.setImage(self.pet_images[0][0])
其中隨機(jī)導(dǎo)入一個(gè)寵物的所有圖片的函數(shù)代碼實(shí)現(xiàn)如下:
'''隨機(jī)導(dǎo)入一個(gè)桌面寵物的所有圖片''' def randomLoadPetImages(self): pet_name = random.choice(list(cfg.PET_ACTIONS_MAP.keys())) actions = cfg.PET_ACTIONS_MAP[pet_name] pet_images = [] for action in actions: pet_images.append([self.loadImage(os.path.join(cfg.ROOT_DIR, pet_name, 'shime'+item+'.png')) for item in action]) iconpath = os.path.join(cfg.ROOT_DIR, pet_name, 'shime1.png') return pet_images, iconpath
當(dāng)然,我們也希望寵物每次在桌面上出現(xiàn)的位置是隨機(jī)的,這樣會(huì)更有趣一些:
'''隨機(jī)到一個(gè)屏幕上的某個(gè)位置''' 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)
現(xiàn)在,運(yùn)行我們的程序時(shí),效果是這樣子的:
好像蠻不錯(cuò)的呢~等等,好像有問(wèn)題,重新設(shè)置了窗口屬性之后,這玩意咋退出啊?在寵物右上角加個(gè)×這樣的符號(hào)又好像很奇怪?
別急,我們可以給我們的桌面寵物添加一個(gè)托盤(pán)圖標(biāo),以實(shí)現(xiàn)桌面寵物程序的退出功能:
# 設(shè)置退出選項(xiàng) quit_action = QAction('退出', self, triggered=self.quit) quit_action.setIcon(QIcon(iconpath)) self.tray_icon_menu = QMenu(self) self.tray_icon_menu.addAction(quit_action) self.tray_icon = QSystemTrayIcon(self) self.tray_icon.setIcon(QIcon(iconpath)) self.tray_icon.setContextMenu(self.tray_icon_menu) self.tray_icon.show()
效果是這樣子的:
OK,這樣好像有模有樣了呢~但是好像還是不太對(duì)的樣子,這寵物每次在桌面生成的位置是隨機(jī)的,但是我們卻無(wú)法調(diào)整這個(gè)寵物的位置,這顯然不合理,作為一個(gè)桌面寵物,你肯定不能在妨礙主人工作的位置??!要不我們來(lái)寫(xiě)一下鼠標(biāo)按下、移動(dòng)以及釋放時(shí)的函數(shù)吧,這樣就可以用鼠標(biāo)拖動(dòng)它了:
'''鼠標(biāo)左鍵按下時(shí), 寵物將和鼠標(biāo)位置綁定''' def mousePressEvent(self, event): if event.button() == Qt.LeftButton: self.is_follow_mouse = True self.mouse_drag_pos = event.globalPos() - self.pos() event.accept() self.setCursor(QCursor(Qt.OpenHandCursor)) '''鼠標(biāo)移動(dòng), 則寵物也移動(dòng)''' def mouseMoveEvent(self, event): if Qt.LeftButton and self.is_follow_mouse: self.move(event.globalPos() - self.mouse_drag_pos) event.accept() '''鼠標(biāo)釋放時(shí), 取消綁定''' def mouseReleaseEvent(self, event): self.is_follow_mouse = False self.setCursor(QCursor(Qt.ArrowCursor))
效果如下:
哈哈,越來(lái)越像樣了呢~最后,作為一個(gè)活潑的寵物,你不能這么呆板,一動(dòng)也不動(dòng)吧?好歹要學(xué)會(huì)做做表情逗主人開(kāi)心吧?OK,我們先來(lái)設(shè)置一個(gè)定時(shí)器:
# 每隔一段時(shí)間做個(gè)動(dòng)作 self.timer = QTimer() self.timer.timeout.connect(self.randomAct) self.timer.start(500)
定時(shí)器每隔一段時(shí)間切換一下選中的寵物的圖片,以達(dá)到寵物做表情動(dòng)作的動(dòng)畫(huà)效果(視頻是一幀幀的圖片組成的這種基礎(chǔ)內(nèi)容就不需要我來(lái)科普了吧T_T)。當(dāng)然,這里我們必須對(duì)圖片進(jìn)行動(dòng)作分類(在做同一個(gè)動(dòng)作的圖片屬于同一類),保證寵物做表情動(dòng)作時(shí)的連貫性。具體而言,代碼實(shí)現(xiàn)如下:
'''隨機(jī)做一個(gè)動(dòng)作''' def randomAct(self): if not self.is_running_action: self.is_running_action = True self.action_images = random.choice(self.pet_images) self.action_max_len = len(self.action_images) self.action_pointer = 0 self.runFrame() '''完成動(dòng)作的每一幀''' def runFrame(self): if self.action_pointer == self.action_max_len: self.is_running_action = False self.action_pointer = 0 self.action_max_len = 0 self.setImage(self.action_images[self.action_pointer]) self.action_pointer += 1
OK,大功告成了~
到此這篇關(guān)于用Python制作一個(gè)可以聊天的皮卡丘版桌面寵物的文章就介紹到這了,更多相關(guān)Python桌面寵物內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python 實(shí)現(xiàn)GUI(圖形用戶界面)編程詳解
今天小編就為大家分享一篇python 實(shí)現(xiàn)GUI(圖形用戶界面)編程詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-07-07matplotlib畫(huà)圖之修改坐標(biāo)軸刻度問(wèn)題
這篇文章主要介紹了matplotlib畫(huà)圖之修改坐標(biāo)軸刻度問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11django框架中ajax的使用及避開(kāi)CSRF 驗(yàn)證的方式詳解
這篇文章主要介紹了django框架中ajax的使用及避開(kāi)CSRF 驗(yàn)證的方式,結(jié)合實(shí)例形式分析了Django框架ajax后臺(tái)交互與排除驗(yàn)證csrf相關(guān)操作技巧,需要的朋友可以參考下2019-12-12Python樹(shù)的序列化與反序列化的實(shí)現(xiàn)
在本文中,我們將深入討論如何實(shí)現(xiàn)樹(shù)的序列化與反序列化算法,提供Python代碼實(shí)現(xiàn),并詳細(xì)說(shuō)明算法的原理和步驟,感興趣的可以了解一下2023-11-11Flask?+?MySQL如何實(shí)現(xiàn)用戶注冊(cè),登錄和登出的項(xiàng)目實(shí)踐
本文主要介紹了Flask?+?MySQL?如何實(shí)現(xiàn)用戶注冊(cè),登錄和登出的項(xiàng)目實(shí)踐,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06Python利用字典將兩個(gè)通訊錄文本合并為一個(gè)文本實(shí)例
這篇文章主要介紹了Python利用字典將兩個(gè)通訊錄文本合并為一個(gè)文本實(shí)例,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-01-01淺談python中的@以及@在tensorflow中的作用說(shuō)明
這篇文章主要介紹了淺談python中的@以及@在tensorflow中的作用說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-03-03