文章目录
- 一.前言
- 二.预览
- 1.主界面
- 2.动图演示
- 3.内存详细信息查看
- 4.自定义界面
- 三.源代码
- 1.tool_god_GUI.py
- 2.tool_god_ui.py
- 3.engine.py
- 4.CWidgets.py
- 四.总结
- 五.参考
一.前言
本次使用PyQt5进行开发一款网速内存查看小工具,类似于一个低配的“电脑管家加速小火箭”,支持实时内存、网速查看、详细内存占用情况查看。
二.预览
本次界面极其简单,实现功能较为单一
1.主界面
2.动图演示
3.内存详细信息查看
双左侧内存占用比,展示详细内存占用情况
4.自定义界面
可以自定义透明度以及背景颜色
三.源代码
1.tool_god_GUI.py
文件主逻辑调用
import sys
import webbrowser
from PyQt5.QtCore import QTimer, Qt, QLockFile
from PyQt5.QtGui import QCursor, QColor
from PyQt5.QtWidgets import QMainWindow, QApplication, QGraphicsDropShadowEffect, QMessageBox, QMenu, QAction, \
QColorDialog, QActionGroup
from qtpy import QtGui, QtCore
from CWidgets import subThread
from tool_god_ui import Ui_MainWindow as mainWindow
from engine import speedEngine, Tool
"""
https://blog.csdn.net/weixin_44446598/article/details/115031335
https://www.yingsoo.com/news/devops/38816.html
"""
class toolGod(QMainWindow, mainWindow):
__author_blog = "https://blog.csdn.net/a1397852386"
def __init__(self, parent=None):
super(toolGod, self).__init__()
self.setupUi(self)
self.engine = speedEngine()
self.tool = Tool()
self.ui_init()
self.menu_init()
self.slot_init()
self.timer_init()
def ui_init(self):
self.setFixedHeight(40)
self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint | Qt.Tool)
self.setAttribute(Qt.WA_TranslucentBackground) # 窗口透明
def timer_init(self):
self.memory_timer = QTimer(self)
self.net_timer = QTimer(self)
self.memory_timer.setInterval(1000)
self.net_timer.setInterval(1000)
self.memory_timer.timeout.connect(self.show_memory_percent)
self.net_timer.timeout.connect(self.show_net_speed)
self.memory_timer.start()
self.net_timer.start()
def menu_init(self):
self.base_menu = QMenu(self)
self.action_change_transparency = QMenu(self)
self.action_change_transparency.setTitle("调整透明度")
self.action_change_bg_color = QAction(self.base_menu)
self.action_about_author = QAction(self.base_menu)
self.action_quit = QAction(self.base_menu)
self.action_about_author.setText("关于作者")
self.action_quit.setText("退出")
self.action_change_bg_color.setText("调整背景颜色")
self.base_menu.addMenu(self.action_change_transparency)
self.base_menu.addAction(self.action_change_bg_color)
self.base_menu.addAction(self.action_about_author)
self.base_menu.addAction(self.action_quit)
self.action_trans5 = QAction(self.action_change_transparency)
self.action_trans25 = QAction(self.action_change_transparency)
self.action_trans50 = QAction(self.action_change_transparency)
self.action_trans75 = QAction(self.action_change_transparency)
self.action_trans100 = QAction(self.action_change_transparency)
self.action_trans5.setText("5%")
self.action_trans25.setText("25%")
self.action_trans50.setText("50%")
self.action_trans75.setText("75%")
self.action_trans100.setText("100%")
self.action_trans5.setCheckable(True)
self.action_trans25.setCheckable(True)
self.action_trans50.setCheckable(True)
self.action_trans75.setCheckable(True)
self.action_trans100.setCheckable(True)
self.action_trans100.setChecked(True)
group = QActionGroup(self)
group.addAction(self.action_trans5)
group.addAction(self.action_trans25)
group.addAction(self.action_trans50)
group.addAction(self.action_trans75)
group.addAction(self.action_trans100)
group.setExclusive(True)
self.action_change_transparency.addActions(
[self.action_trans5, self.action_trans25, self.action_trans50, self.action_trans75, self.action_trans100])
self.action_trans5.triggered.connect(lambda: self.change_bg_opacity(0.05))
self.action_trans25.triggered.connect(lambda: self.change_bg_opacity(0.25))
self.action_trans50.triggered.connect(lambda: self.change_bg_opacity(0.5))
self.action_trans75.triggered.connect(lambda: self.change_bg_opacity(0.75))
self.action_trans100.triggered.connect(lambda: self.change_bg_opacity(1))
self.action_change_bg_color.triggered.connect(self.change_bg_color)
self.action_about_author.triggered.connect(self.show_about_author)
self.action_quit.triggered.connect(self.close)
def slot_init(self):
self.frame_3.customContextMenuRequested.connect(lambda: self.base_menu.exec_(QCursor.pos()))
self.frame.mouse_double_signal.connect(self.show_memory_detail)
def change_bg_opacity(self, opacity):
"""
改变窗口透明度
:param opacity:
:return:
"""
self.setWindowOpacity(opacity)
def change_bg_color(self):
"""
改变背景颜色
:return:
"""
color = QColorDialog.getColor(QColor("white"), self, "请选择一种颜色")
rgb_color_str = color.toRgb()
rgb_str = "rgb(%s,%s,%s)" % (rgb_color_str.red(), rgb_color_str.green(),
rgb_color_str.blue())
self.frame_3.setStyleSheet(
"""#frame_3{background-color:%s;border:1px solid %s;border-radius:15px;}""" % (rgb_str, rgb_str))
def show_memory_detail(self):
"""
展示详细内存信息
:return:
"""
mem_total, mem_used, mem_free, mem_percent = self.tool.memory_format(self.engine.get_memory_detail())
msg = """总内存:{}\n已使用:{}\n空闲:{}\n占用:{}""".format(mem_total, mem_used, mem_free, mem_percent)
QMessageBox.information(self, "内存详细信息", msg)
def show_about_author(self):
"""
关于作者
:return:
"""
ret = QMessageBox.question(self, "关于作者", '你好我是懷淰メ\n是否要访问我的播客主页?', QMessageBox.Yes | QMessageBox.No,
QMessageBox.Yes)
if ret == QMessageBox.Yes:
webbrowser.open(self.__author_blog)
def show_memory_percent(self):
"""
内存占用百分比
:return:
"""
memory_percent = self.engine.get_memory_percent()
self.label_mem_precent.setText("{}%".format(memory_percent))
def show_net_speed(self):
"""
展示当前网速
:return:
"""
net_download_speed, net_upload_speed = self.engine.get_net_speed()
self.label_net_upload.setText(self.tool.speed_format(net_upload_speed))
self.label_net_download.setText(self.tool.speed_format(net_download_speed))
def closeEvent(self, a0: QtGui.QCloseEvent):
ret = QMessageBox.question(self, "退出", '确认要退出?', QMessageBox.Yes | QMessageBox.No,
QMessageBox.Yes)
if ret == QMessageBox.Yes:
a0.accept()
sys.exit(-1)
else:
a0.ignore()
# 无边框的拖动
def mouseMoveEvent(self, e: QtGui.QMouseEvent): # 重写移动事件
try:
self._endPos = e.pos() - self._startPos
self.move(self.pos() + self._endPos)
except (AttributeError, TypeError):
pass
def mousePressEvent(self, e: QtGui.QMouseEvent):
if e.button() == QtCore.Qt.LeftButton:
self._isTracking = True
self._startPos = QtCore.QPoint(e.x(), e.y())
def mouseReleaseEvent(self, e: QtGui.QMouseEvent):
if e.button() == QtCore.Qt.LeftButton:
self._isTracking = False
self._startPos = None
self._endPos = None
if __name__ == '__main__':
app = QApplication(sys.argv)
# ui = toolGod()
# ui.show()
# sys.exit(app.exec_())
lockFile = QLockFile("./lock.lock")
if lockFile.tryLock(timeout=2000):
ui = toolGod()
ui.show()
sys.exit(app.exec_())
else:
msg_box = QMessageBox()
msg_box.setWindowTitle("警告")
msg_box.setText("软件已在运行,请勿重复开启!")
msg_box.setIcon(QMessageBox.Warning)
msg_box.addButton("确定", QMessageBox.YesRole)
msg_box.exec()
sys.exit(-1)
2.tool_god_ui.py
由designer转化而来
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'tool_god_ui.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(143, 45)
MainWindow.setStyleSheet("#label_4{color:rgb(0, 85, 255);font-weight:600;}\n"
"#label_5{color;green;font-weight:600;}\n"
"*{font-family:\"微软雅黑\"}\n"
"#frame_3{background-color:#00ffff;border:1px solid #00ffff ;border-radius:15px;}\n"
"#line{color:gray;}\n"
"\n"
"")
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)
self.verticalLayout_2.setSpacing(0)
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.frame_3 = QtWidgets.QFrame(self.centralwidget)
self.frame_3.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.frame_3.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame_3.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame_3.setObjectName("frame_3")
self.horizontalLayout = QtWidgets.QHBoxLayout(self.frame_3)
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout.setSpacing(0)
self.horizontalLayout.setObjectName("horizontalLayout")
self.frame = myFrame(self.frame_3)
self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame.setObjectName("frame")
self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.frame)
self.horizontalLayout_2.setContentsMargins(10, 0, 10, 0)
self.horizontalLayout_2.setSpacing(0)
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.label_mem_precent = QtWidgets.QLabel(self.frame)
self.label_mem_precent.setObjectName("label_mem_precent")
self.horizontalLayout_2.addWidget(self.label_mem_precent)
self.horizontalLayout.addWidget(self.frame)
self.frame_2 = QtWidgets.QFrame(self.frame_3)
self.frame_2.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame_2.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame_2.setObjectName("frame_2")
self.verticalLayout = QtWidgets.QVBoxLayout(self.frame_2)
self.verticalLayout.setContentsMargins(0, 0, 10, 0)
self.verticalLayout.setSpacing(0)
self.verticalLayout.setObjectName("verticalLayout")
self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
self.horizontalLayout_4.setObjectName("horizontalLayout_4")
self.label_4 = QtWidgets.QLabel(self.frame_2)
self.label_4.setObjectName("label_4")
self.horizontalLayout_4.addWidget(self.label_4, 0, QtCore.Qt.AlignLeft)
self.label_net_upload = QtWidgets.QLabel(self.frame_2)
self.label_net_upload.setObjectName("label_net_upload")
self.horizontalLayout_4.addWidget(self.label_net_upload)
self.verticalLayout.addLayout(self.horizontalLayout_4)
self.line = QtWidgets.QFrame(self.frame_2)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.line.sizePolicy().hasHeightForWidth())
self.line.setSizePolicy(sizePolicy)
self.line.setFrameShape(QtWidgets.QFrame.HLine)
self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
self.line.setObjectName("line")
self.verticalLayout.addWidget(self.line)
self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
self.label_5 = QtWidgets.QLabel(self.frame_2)
self.label_5.setObjectName("label_5")
self.horizontalLayout_3.addWidget(self.label_5, 0, QtCore.Qt.AlignLeft)
self.label_net_download = QtWidgets.QLabel(self.frame_2)
self.label_net_download.setObjectName("label_net_download")
self.horizontalLayout_3.addWidget(self.label_net_download)
self.verticalLayout.addLayout(self.horizontalLayout_3)
self.horizontalLayout.addWidget(self.frame_2)
self.horizontalLayout.setStretch(0, 1)
self.horizontalLayout.setStretch(1, 3)
self.verticalLayout_2.addWidget(self.frame_3)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.label_mem_precent.setText(_translate("MainWindow", "0.0%"))
self.label_4.setText(_translate("MainWindow", "↑"))
self.label_net_upload.setText(_translate("MainWindow", "0k/s"))
self.label_5.setText(_translate("MainWindow", "↓"))
self.label_net_download.setText(_translate("MainWindow", "0k/s"))
from CWidgets import myFrame
3.engine.py
主要引擎、工具类,获取网速、内存、单位格式转化
import psutil
import traceback
class speedEngine(object):
last_total_bytes_sent = psutil.net_io_counters().bytes_sent
last_total_bytes_recv = psutil.net_io_counters().bytes_recv
def get_net_speed(self):
"""
获取网络上传下载速度
:return:
"""
try:
total_bytes_sent = psutil.net_io_counters().bytes_sent
total_bytes_recv = psutil.net_io_counters().bytes_recv
diff_bytes_sent = (total_bytes_sent - self.last_total_bytes_sent) / 1024
diff_bytes_recv = (total_bytes_recv - self.last_total_bytes_recv) / 1024
net_download_speed = diff_bytes_recv / 1
net_upload_speed = diff_bytes_sent / 1
self.last_total_bytes_sent = total_bytes_sent
self.last_total_bytes_recv = total_bytes_recv
return net_download_speed, net_upload_speed
except:
traceback.print_exc()
return "", ""
def get_memory_percent(self):
"""
获取内存占用
:return:
"""
try:
memory_percent = psutil.virtual_memory().percent
return memory_percent
except:
traceback.print_exc()
return 0.0
def get_memory_detail(self):
"""
获取内存占用详细情况
:return:
"""
try:
mem = psutil.virtual_memory()
return mem
except:
traceback.print_exc()
return ""
class Tool():
def speed_format(self, speed: float):
"""
格式化网速
:param speed:
:return:
"""
if int(speed) > 1024:
return "%.2f M/s" % (speed / 1024)
else:
return "%.2f k/s" % (speed)
def memory_format(self, mem):
"""
格式化内存
:param mem:
:return:
"""
mem_total = mem.total / 1024 / 1024 / 1024 # 获取内存的总数
mem_used = mem.used / 1024 / 1024 / 1024 # 获取已使用的内存
mem_free = mem.free / 1024 / 1024 / 1024 # 获取空闲内存大小
mem_percent = mem.percent # 获取空闲内存占用比
format_str = "{:.2f}GB"
return format_str.format(mem_total), format_str.format(mem_used), format_str.format(mem_free), "{:.2f}%".format(mem_percent)
if __name__ == '__main__':
tool = speedEngine()
print(tool.get_memory_detail())
4.CWidgets.py
自定义Frame,支持双击响应
import sys
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtGui import QMouseEvent
from PyQt5.QtWidgets import QWidget, QApplication, QFrame
from engine import speedEngine
from bak.memory_detail_ui import Ui_Form as memory_detail
class myFrame(QFrame):
mouse_double_signal = pyqtSignal()
def __init__(self, parent=None):
super(myFrame, self).__init__()
self.setParent(parent)
def mouseDoubleClickEvent(self, a0: QMouseEvent):
print("double click")
self.mouse_double_signal.emit()
super(myFrame, self).mouseDoubleClickEvent(a0)
class subThread(QThread):
memory_percent_finished = pyqtSignal(str)
net_speed_finished = pyqtSignal(str, str)
def __init__(self, task, *arg, **args):
super(subThread, self).__init__()
self.engine = speedEngine()
def get_mem_percent(self):
mem_percent = self.engine.get_memory_percent()
self.memory_percent_finished.emit(mem_percent)
def get_net_speed(self):
net_download_speed, net_upload_speed = self.engine.get_net_speed()
self.net_speed_finished.emit(net_download_speed, net_upload_speed)
class memoryDetail(QWidget, memory_detail):
def __init__(self):
super(memoryDetail, self).__init__()
self.setupUi(self)
if __name__ == '__main__':
app = QApplication(sys.argv)
ui = memoryDetail()
ui.show()
sys.exit(app.exec_())
四.总结
本次使用PyQt5模仿电脑管家内存、网速查看工具,实现了网速、内存的实时展示、详细内存查看、自定义界面透明度、背景颜色。软件打包好放在了蓝奏云。软件无恶意代码,但有可能会被误报,添加信任即可。如果觉得小工具还可以,能留下您的赞么?
五.参考
- Python实现桌面悬浮窗(显示网速,内存,CPU)
- Python PyQt5实战项目之网速监控器的实现