update repo

This commit is contained in:
phil616 2025-06-27 15:59:08 +08:00
commit d30d6f290d
21 changed files with 436 additions and 0 deletions

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
*.gif filter=lfs diff=lfs merge=lfs -text
*.svg filter=lfs diff=lfs merge=lfs -text

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.DS_Store

BIN
GIF/angry.gif (Stored with Git LFS) Normal file

Binary file not shown.

BIN
GIF/appear.gif (Stored with Git LFS) Normal file

Binary file not shown.

BIN
GIF/baji.gif (Stored with Git LFS) Normal file

Binary file not shown.

BIN
GIF/boring.gif (Stored with Git LFS) Normal file

Binary file not shown.

BIN
GIF/cake.gif (Stored with Git LFS) Normal file

Binary file not shown.

BIN
GIF/call.gif (Stored with Git LFS) Normal file

Binary file not shown.

BIN
GIF/charge.gif (Stored with Git LFS) Normal file

Binary file not shown.

BIN
GIF/crying.gif (Stored with Git LFS) Normal file

Binary file not shown.

BIN
GIF/crying2.gif (Stored with Git LFS) Normal file

Binary file not shown.

BIN
GIF/exercise.gif (Stored with Git LFS) Normal file

Binary file not shown.

BIN
GIF/normal.gif (Stored with Git LFS) Normal file

Binary file not shown.

BIN
GIF/stick.gif (Stored with Git LFS) Normal file

Binary file not shown.

BIN
GIF/walkdog.gif (Stored with Git LFS) Normal file

Binary file not shown.

BIN
GIF/working.gif (Stored with Git LFS) Normal file

Binary file not shown.

BIN
GIF/working2.gif (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Image/Energy.svg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Image/Happiness.svg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
Image/MenuIcon.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

382
main.py Normal file
View File

@ -0,0 +1,382 @@
import sys
import os
import random
import datetime
from PyQt5.QtGui import QIcon, QMovie, QCursor, QPixmap
from PyQt5.QtWidgets import (QWidget, QApplication, QSystemTrayIcon,
QMenu, QAction, QLabel, QDesktopWidget,
QProgressBar, QVBoxLayout, QHBoxLayout)
from PyQt5.QtCore import Qt, QSize, QTimer
class DesktopPet(QWidget):
def __init__(self, parent=None, **kwargs):
super(DesktopPet, self).__init__(parent)
self.init()
self.initPall()
self.action_timer = QTimer(self)
self.action_timer.setSingleShot(True)
self.action_timer.timeout.connect(self.checkInitialGif)
self.status_timer = QTimer(self)
self.status_timer.timeout.connect(self.statusTimer)
self.happiness_accumulated = 0
self.energy_accumulated = 0
self.working_timer = QTimer(self)
self.working_timer.timeout.connect(self.updateWorking)
self.boring_timer = QTimer(self)
self.boring_timer.setSingleShot(True)
self.boring_timer.timeout.connect(self.setBoring)
self.is_boring = False
self.resetBoringTimer()
self.resurrect_timer = QTimer(self)
self.resurrect_timer.setSingleShot(True)
self.resurrect_timer.timeout.connect(self.resurrectPet)
self.is_dead = False
self.initPetImage()
def init(self):
self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.Tool | Qt.NoDropShadowWindowHint)
self.setAutoFillBackground(False)
self.setAttribute(Qt.WA_TranslucentBackground, True)
self.repaint()
def initPall(self):
icons = os.path.join('Image/MenuIcon.jpg')
self.quit_action = QAction(u'退出', self, triggered=self.quit)
self.showing = QAction(u'显示', self, triggered=self.showup)
self.hideup = QAction(u'隐藏', self, triggered=self.hide)
self.hidestats = QAction(u'显示/隐藏状态栏', self, triggered=self.hideStatsBar)
self.tray_icon_menu = QMenu(self)
self.tray_icon_menu.addAction(self.quit_action)
self.tray_icon_menu.addAction(self.showing)
self.tray_icon_menu.addAction(self.hideup)
self.tray_icon_menu.addAction(self.hidestats)
self.tray_icon = QSystemTrayIcon(self)
self.tray_icon.setIcon(QIcon(icons))
self.tray_icon.setContextMenu(self.tray_icon_menu)
self.tray_icon.show()
def initPetImage(self):
self.main_layout = QVBoxLayout(self)
self.main_layout.setContentsMargins(0, 0, 0, 0)
self.main_layout.setSpacing(0)
self.stats_visible = True
self.happiness_layout = QHBoxLayout()
self.happiness_layout.setContentsMargins(0, 0, 0, 0)
self.happiness_layout.setSpacing(0)
self.happiness_icon = QLabel()
self.happiness_icon.setContentsMargins(0, 0, 0, 0)
self.happiness_icon_pixmap = QPixmap("Image/Happiness.svg")
self.happiness_icon_pixmap = self.happiness_icon_pixmap.scaled(QSize(20, 20), Qt.KeepAspectRatio, Qt.SmoothTransformation)
self.happiness_icon.setPixmap(self.happiness_icon_pixmap)
self.happiness_layout.addWidget(self.happiness_icon, alignment=Qt.AlignCenter)
self.happiness_bar = QProgressBar()
self.happiness_bar.setRange(0, 100)
self.happiness_bar.setValue(80)
self.happiness_bar.setFixedHeight(12)
self.happiness_bar.setFixedWidth(150)
self.happiness_bar.setStyleSheet("""
QProgressBar {
border: 1px solid #ccc;
border-radius: 5px;
text-align: center;
}
QProgressBar::chunk {
background-color: #FF69B4;
}
""")
self.happiness_layout.addWidget(self.happiness_bar, alignment=Qt.AlignCenter)
self.energy_layout = QHBoxLayout()
self.energy_layout.setContentsMargins(0, 0, 0, 0)
self.energy_layout.setSpacing(0)
self.energy_label = QLabel()
self.energy_label.setContentsMargins(0, 0, 0, 0)
self.energy_icon_pixmap = QPixmap("Image/Energy.svg")
self.energy_icon_pixmap = self.energy_icon_pixmap.scaled(QSize(20, 20), Qt.KeepAspectRatio, Qt.SmoothTransformation)
self.energy_label.setPixmap(self.energy_icon_pixmap)
self.energy_layout.addWidget(self.energy_label, alignment=Qt.AlignCenter)
self.energy_bar = QProgressBar()
self.energy_bar.setRange(0, 100)
self.energy_bar.setValue(80)
self.energy_bar.setFixedHeight(12)
self.energy_bar.setFixedWidth(150)
self.energy_bar.setStyleSheet("""
QProgressBar {
border: 1px solid #ccc;
border-radius: 5px;
text-align: center;
}
QProgressBar::chunk {
background-color: #1E90FF;
}
""")
self.energy_layout.addWidget(self.energy_bar, alignment=Qt.AlignCenter)
self.image = QLabel(self)
self.image.setContentsMargins(0, 0, 0, 0)
self.checkInitialGif()
self.main_layout.addWidget(self.image)
self.main_layout.addLayout(self.happiness_layout)
self.main_layout.addLayout(self.energy_layout)
self.resize(200, 240)
self.randomPosition()
self.show()
self.pet1 = []
for filename in os.listdir("GIF"):
self.pet1.append(os.path.join("GIF", filename))
def showMenu(self):
menu = QMenu()
menu.addAction(u"贴贴", self.stick)
menu.addAction(u"拍一拍", self.call)
menu.addAction(u"锻炼", self.exercise)
menu.addAction(u"充电", self.charge)
menu.addAction(u"投喂小白", self.cake)
menu.addAction(u"吧唧", self.baji)
menu.addAction(u"随机出现", self.appear)
menu.addAction(u"遛小鸡毛", self.walkDog)
right_pos = self.mapToGlobal(self.rect().topRight())
menu.exec_(right_pos)
def stick(self):
if self.is_dead:
return
self.resetBoringTimer()
self.working_timer.stop()
self.changeGif("GIF/stick.gif")
self.action_timer.start(10 * 60 * 1000)
self.updateStatus(15, -5, 10 * 60 * 1000)
def call(self):
if self.is_dead:
return
self.resetBoringTimer()
self.working_timer.stop()
self.changeGif("GIF/call.gif")
self.action_timer.start(2000)
def exercise(self):
if self.is_dead:
return
self.resetBoringTimer()
self.working_timer.stop()
self.changeGif("GIF/exercise.gif")
self.action_timer.start(10 * 60 * 1000)
self.updateStatus(5, -10, 10 * 60 * 1000)
def charge(self):
if self.is_dead:
return
self.resetBoringTimer()
self.working_timer.stop()
self.changeGif("GIF/charge.gif")
self.action_timer.start(45 * 60 * 1000)
self.updateStatus(30, 30, 30 * 60 * 1000)
def cake(self):
if self.is_dead:
return
self.resetBoringTimer()
self.working_timer.stop()
self.changeGif("GIF/cake.gif")
self.action_timer.start(5 * 60 * 1000)
self.updateStatus(10, 5, 5 * 60 * 1000)
def baji(self):
if self.is_dead:
return
self.resetBoringTimer()
self.working_timer.stop()
self.changeGif("GIF/baji.gif")
self.action_timer.start(5 * 60 * 1000)
self.updateStatus(10, 10, 5 * 60 * 1000)
def appear(self):
if self.is_dead:
return
self.resetBoringTimer()
self.working_timer.stop()
self.changeGif("GIF/appear.gif")
self.action_timer.start(3500)
self.randomPosition()
def walkDog(self):
if self.is_dead:
return
self.resetBoringTimer()
self.working_timer.stop()
self.changeGif("GIF/walkdog.gif")
self.action_timer.start(10 * 60 * 1000)
self.updateStatus(15, -10, 10 * 60 * 1000)
def checkInitialGif(self):
current_time = datetime.datetime.now()
current_hour = current_time.hour
weekday = current_time.weekday()
self.is_working_time = (0 <= weekday <= 4) and (10 <= current_hour < 18)
happiness = self.happiness_bar.value()
energy = self.energy_bar.value()
if happiness == 0 and energy == 0:
self.petDied()
elif happiness < 20 and energy < 20:
if self.is_working_time:
self.working_timer.stop()
self.working_timer.start(60 * 1000)
return self.changeGif("GIF/angry.gif")
elif happiness < 20:
if self.is_working_time:
self.working_timer.stop()
self.working_timer.start(2 * 60 * 1000)
return self.changeGif("GIF/crying2.gif")
elif energy < 20:
if self.is_working_time:
self.working_timer.stop()
self.working_timer.start(2 * 10 * 1000)
return self.changeGif("GIF/crying.gif")
if self.is_working_time:
self.working_timer.start(3 * 60 * 1000)
return self.changeGif("GIF/working2.gif")
else:
self.working_timer.stop()
return self.changeGif("GIF/normal.gif")
def updateWorking(self):
self.updateHappiness(-1)
self.updateEnergy(-1)
if self.happiness_bar.value() <= 20 or self.energy_bar.value() <= 20:
self.checkInitialGif()
def updateStatus(self, happinesschange, energychange, duration):
self.total_happiness_change = happinesschange
self.total_energy_change = energychange
interval = 100
self.remaining = duration / interval
self.happiness_change_step = happinesschange / self.remaining
self.energy_change_step = energychange / self.remaining
self.status_timer.start(interval)
def statusTimer(self):
if self.remaining <= 0:
self.status_timer.stop()
return
self.happiness_accumulated += self.happiness_change_step
self.energy_accumulated += self.energy_change_step
if self.happiness_accumulated >= 1 or self.happiness_accumulated <= -1:
self.updateHappiness(int(self.happiness_accumulated))
self.happiness_accumulated = 0
if self.energy_accumulated >= 1 or self.energy_accumulated <= -1:
self.updateEnergy(int(self.energy_accumulated))
self.energy_accumulated = 0
self.remaining -= 1
def setBoring(self):
if not self.is_boring and not self.is_working_time:
self.is_boring = True
self.changeGif("GIF/boring.gif")
self.updateHappiness(-5)
def resetBoringTimer(self):
if self.is_boring:
self.is_boring = False
self.checkInitialGif()
self.boring_timer.stop()
self.boring_timer.start(60 * 60 * 1000)
def petDied(self):
if self.is_dead:
return
self.is_dead = True
self.working_timer.stop()
self.boring_timer.stop()
self.action_timer.stop()
self.status_timer.stop()
self.showing.setEnabled(False)
self.hidestats.setEnabled(False)
self.hideup.setEnabled(False)
self.hide()
self.resurrect_timer.start(5000)
def resurrectPet(self):
self.is_dead = False
self.happiness_bar.setValue(50)
self.energy_bar.setValue(50)
self.showing.setEnabled(True)
self.hidestats.setEnabled(True)
self.hideup.setEnabled(True)
self.showup()
self.resetBoringTimer()
self.checkInitialGif()
def randomPosition(self):
screen_geometry = QDesktopWidget().screenGeometry()
pet_geometry = self.geometry()
width = int((screen_geometry.width() - pet_geometry.width()) * random.random())
height = int((screen_geometry.height() - pet_geometry.height()) * random.random())
self.move(width, height)
def changeGif(self, path):
self.movie = QMovie(path)
self.movie.setScaledSize(QSize(200, 200))
self.image.setMovie(self.movie)
self.movie.start()
def mousePressEvent(self, event):
self.condition = 1
if event.button() == Qt.LeftButton:
self.is_follow_mouse = True
self.mouse_drag_pos = event.globalPos() - self.pos()
self.setCursor(QCursor(Qt.OpenHandCursor))
elif event.button() == Qt.RightButton:
self.showMenu()
event.accept()
def mouseMoveEvent(self, event):
if Qt.LeftButton and self.is_follow_mouse:
self.move(event.globalPos() - self.mouse_drag_pos)
event.accept()
def mouseReleaseEvent(self, event):
self.is_follow_mouse = False
self.setCursor(QCursor(Qt.ArrowCursor))
def enterEvent(self, event):
self.setCursor(Qt.ClosedHandCursor)
def updateHappiness(self, value):
current_value = self.happiness_bar.value()
new_value = max(0, min(100, current_value + value))
self.happiness_bar.setValue(new_value)
def updateEnergy(self, value):
current_value = self.energy_bar.value()
new_value = max(0, min(100, current_value + value))
self.energy_bar.setValue(new_value)
def hideStatsBar(self):
if self.is_dead:
return
self.stats_visible = not self.stats_visible
self.happiness_icon.setVisible(self.stats_visible)
self.happiness_bar.setVisible(self.stats_visible)
self.energy_label.setVisible(self.stats_visible)
self.energy_bar.setVisible(self.stats_visible)
def quit(self):
self.close()
sys.exit()
def showup(self):
self.setWindowOpacity(1)
def hide(self):
self.setWindowOpacity(0)
if __name__ == '__main__':
app = QApplication(sys.argv)
pet = DesktopPet()
sys.exit(app.exec_())