runcat-pyqt5-win:在windows任务栏养猫(2)

runcat-pyqt5-win V2

之前撸了一个 runcat-pyqt5-win,可以在windows任务栏养猫,用奔跑的猫来显示当前系统资源(CPU)的占用情况。

原来的功能比较简单,这次增加了右键菜单:

  • 可切换图标类型: [cat, mario]
  • 可切换监控类型: [cpu, memory, gpu(nVidia)]
  • 增加了退出按钮

运行效果

Requirements

  • psutil
  • pyqt5
  • nvidia-ml-py

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import os
import sys
import threading
import time

import psutil
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QApplication, QSystemTrayIcon, QMenu, QAction

import pynvml

pynvml.nvmlInit()
handle = pynvml.nvmlDeviceGetHandleByIndex(0) # GPU id: 0


class TrayIcon(QSystemTrayIcon):
def __init__(self, parent=None):
super(TrayIcon, self).__init__(parent)
self.monitor = 'cpu'
self.cpu_usage = 0.2 # 初始化
self.mem_usage = 0.2 # 初始化
self.gpu_usage = 0.2 # 初始化

self.icon_type = 'runcat' # 设定默认图标,并加载
self.icon_list = self.loadIcon()
self.setIcon(self.icon_list[0])

self.setVisible(True)
self.setMenu() # 加载菜单
self.updateIcon() # 更新图标

# 加载图标
def loadIcon(self):
if self.icon_type == 'mario':
return [QIcon(f'icons/{self.icon_type}/{i}.png') for i in range(3)]
return [QIcon(f'icons/{self.icon_type}/{i}.png') for i in range(5)]

# 设置菜单
def setMenu(self):
self.menu = QMenu()
self.action_1 = QAction(QIcon(f'icons/cat.png'),
'Cat', self, triggered=lambda: self.changeIconType('runcat'))
self.action_2 = QAction(QIcon(f'icons/mario/0.png'),
'Mario', self, triggered=lambda: self.changeIconType('mario'))

self.action_c = QAction(QIcon(f'icons/cpu.png'),
'CPU', self, triggered=lambda: self.changeMonitor('cpu'))
self.action_m = QAction(QIcon(f'icons/mem.png'),
'Memory', self, triggered=lambda: self.changeMonitor('mem'))
self.action_g = QAction(QIcon(f'icons/gpu.png'),
'GPU', self, triggered=lambda: self.changeMonitor('gpu'))

self.action_q = QAction(QIcon(f'icons/quit.png'),
'Quit', self, triggered=self.quit)

self.menu.addAction(self.action_c)
self.menu.addAction(self.action_m)
self.menu.addAction(self.action_g)
self.menu.addSeparator()
self.menu.addAction(self.action_1)
self.menu.addAction(self.action_2)
self.menu.addSeparator()
self.menu.addAction(self.action_q)
self.setContextMenu(self.menu)

# 根据使用率更新图标,
# 创建两个 threading:一个获取使用率,一个更新图标
def updateIcon(self):
threading.Timer(0.1, self.thread_get_cpu_usage, []).start()
threading.Timer(0.1, self.thread_update_icon, []).start()

# get cpu usage
def thread_get_cpu_usage(self):
while True:
self.cpu_usage = psutil.cpu_percent(interval=1) / 100
self.mem_usage = psutil.virtual_memory().percent / 100
meminfo = pynvml.nvmlDeviceGetMemoryInfo(handle)
self.gpu_usage = meminfo.used / meminfo.total
# print(self.cpu_usage)
time.sleep(0.5)

# update icon
def thread_update_icon(self):
while True:
mon = self.cpu_usage
if self.monitor == 'mem':
mon = self.mem_usage
elif self.monitor == 'gpu':
mon = self.gpu_usage

t = 0.18 - mon * 0.15
# print(mon, t)
for i in self.icon_list:
self.setIcon(i)
tip = f'cpu: {self.cpu_usage:.2%} \nmem: {self.mem_usage:.2%} \ngpu: {self.gpu_usage:.2%}'
self.setToolTip(tip)
# print(i, self.cpu_usage)
time.sleep(t)

# Change icon type
def changeIconType(self, type):
print(type)
if type != self.icon_type:
self.icon_type = type
self.icon_list = self.loadIcon()
print(f'Load {self.icon_type}({len(self.icon_list)}) icons...')

# change monitor type
def changeMonitor(self, monitor_type):
print(monitor_type)
if monitor_type != self.monitor:
self.monitor = monitor_type

# 退出程序
def quit(self):
self.setVisible(False)
app.quit()
os._exit(-1) # 完全退出程序


if __name__ == "__main__":
app = QApplication(sys.argv)
tray = TrayIcon()

sys.exit(app.exec_())