python3GUI--网速内存小工具By:PyQt5(附源码)


一.前言

本次使用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模仿电脑管家内存、网速查看工具,实现了网速、内存的实时展示、详细内存查看、自定义界面透明度、背景颜色。软件打包好放在了蓝奏云。软件无恶意代码,但有可能会被误报,添加信任即可。如果觉得小工具还可以,能留下您的赞么?
在这里插入图片描述

五.参考

  1. Python实现桌面悬浮窗(显示网速,内存,CPU)
  2. Python PyQt5实战项目之网速监控器的实现

猜你喜欢

转载自blog.csdn.net/a1397852386/article/details/131500628