当前位置: 首页 > news >正文

python3GUI--运维系统大屏 By:PyQt5(附下载地址)

文章目录

  • 一.前言
  • 二.预览
  • 三.相关技术
    • 1.ECharts
    • 2.PyQt5
    • 3.PyQt5 WEB技术
    • 4.系统核心
    • 5.为什么系统不卡?
    • 6.关于项目
  • 四.总结


文件大小120M,欢迎下载体验!通过网盘分享的文件:pyqt5运维系统大屏.zip
链接: https://pan.baidu.com/s/1GfAx35XnoaO_pXb_laFNdg?pwd=2333 提取码: 2333

请添加图片描述

一.前言

今天给大家带来我使用PyQt5开发的运维系统大屏,笔者定义系统名称为:「SysPulse」 - 智能系统监测中心,此系统用于展示当前操作系统相关指标参数,采用多种可视化方案对当前系统的指标进行可视化展示,请大家拭目以待!
本篇我将详细分享软件系统实现流程,也会粘贴具体的代码片段和大家分享!

二.预览

软件启动后进入到系统主屏,主屏包括三个区域分别是左侧、中间、右侧区域,这三个区域分别展示了:
通过折线图、地图、水球图、条形图、表格动态展示了系统真实数据,实时刷新。
系统内置7种背景图,支持动态调整!
在这里插入图片描述

左侧中间右侧
• 系统信息• IP归属地• CPU使用率
OS版本/主机名/运行时间公网IP/地理定位总占用/核心温度/负载
• 网关连通性• 磁盘• 内存使用率
默认网关PING延迟总量/已用/读写IOPS物理+Swap/缓存占比
• 网络情况• TOP5进程
实时流量(↑↓)/TCP连接数PID/名称/资源占用

三.相关技术

1.ECharts

ECharts 是一款由百度开源的高性能 JavaScript 可视化库,提供丰富的图表类型(如折线图、柱状图、地图等)和强大的交互功能(缩放、拖拽、动态更新等),支持响应式设计并兼容多端设备。其灵活的配置选项和扩展性使开发者能够轻松创建专业的数据可视化应用,广泛应用于数据分析、实时监控及商业报表等领域。通过简洁的代码即可实现复杂图表,是前端数据可视化的热门选择。
在这里插入图片描述

2.PyQt5

PyQt5 是一个用于创建图形用户界面(GUI)的 Python 库,基于 Qt 框架开发。它提供了丰富的控件(如按钮、文本框、表格等)和强大的功能(多线程、网络通信、数据库交互等),支持跨平台运行(Windows、macOS、Linux)。开发者可以用 PyQt5 快速构建复杂的桌面应用程序,同时结合 Python 的简洁语法和 Qt 的高性能渲染,适用于数据分析工具、多媒体软件、自动化程序等开发。

请添加图片描述

3.PyQt5 WEB技术

我们本次的可视化方案大多数都是使用Echarts图展示的并且不依赖本地html文件,这是如何做到的呢?

PyQtWebEngine 是 PyQt5 的一个扩展模块,基于 Chromium 的 Qt WebEngine 框架,用于在 PyQt5 应用程序中嵌入现代网页浏览器功能。它支持 HTML5、CSS3、JavaScript 和 WebGL,允许开发者:
内嵌网页渲染:在 PyQt5 窗口内显示网页内容,如加载在线地图、Web 应用或本地 HTML 文件。
交互控制:通过 Python 与网页 JavaScript 双向通信(如调用 JS 函数或监听网页事件)。
定制浏览器:构建带有导航栏、开发者工具等功能的完整浏览器应用。
适用于需要混合 Web 技术与桌面 GUI 的场景,如内嵌 Web 报表、在线文档查看器或基于 Web 的桌面应用。

首先我们重写了QWebEnginePage的contextMenuEvent禁用了浏览器右击事件,这样避免了用户误操作右击事件,然后我们重写了QWebEngineView的contextMenuEvent也禁用了鼠标右击事件,最后我们定义了一个BaseChart,继承自QWidget,所有子图表类都继承自这个基类,拥有相同的属性,大致的初始化流程见下图。
请添加图片描述
这里我们以水球图为例,水球图继承图表基类,通过generate_html方法生成整体html框架,最后使用self.view.setHtml(html, QUrl(""))函数设置内存中的html代码到webengintview里,这样就完成了整体页面的渲染,大家能看到下图的效果。
在这里插入图片描述
如何更新这个百分比数值呢?这里给出两种方案:
1.使用js,通过page的runJavaScript对图表数据进行更新,具体代码可以参考:

	def update_value(self, percent):self.percent = percentpercent_display = f"{percent * 100:.2f}%"js = f"""if (window.chart) {{window.chart.setOption({{series: [{{data: [{percent}],label: {{formatter: '{percent_display}'}}}}]}});}}"""self.view.page().runJavaScript(js)

2.使用QWebChannel设置信号“桥”来进行通信,具体来说是定义一个类继承自QObject,在其中定义一个信号,通过这个信号来改变网页中的内容

class GaugeBridge(QObject):update_value = pyqtSignal(float, str)def send_value(self, value: float, label: str):self.update_value.emit(value, label)def get_html(self):title_block = (f"title: {{ text: '{self.chart_title}', textStyle: {{ color: '#ffffff' }} }},"if self.chart_title else "")# 根据 mode 设置颜色if self.mode == 2:color_gradient = """color: [[1, new echarts.graphic.LinearGradient(0, 0, 1, 1, [{ offset: 0, color: 'rgb(0,255,127)' },{ offset: 1, color: 'rgb(0,255,127)' }])]]"""else:color_gradient = """color: [[1, new echarts.graphic.LinearGradient(0, 0, 1, 1, [{ offset: 0, color: 'rgb(0,228,200)' },{ offset: 1, color: 'rgb(0,220,222)' }])]]"""return f"""
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>仪表盘</title><script src="https://cdn.jsdelivr.net/npm/echarts@5"></script><script src="qrc:///qtwebchannel/qwebchannel.js"></script><style>html, body, #main {{width: 100%;height: 100%;margin: 0;background: transparent;}}</style>
</head>
<body><div id="main"></div><script>var chart = echarts.init(document.getElementById('main'));window.addEventListener("resize", function () {{chart.resize();}});var option = {{{title_block}series: [{{type: 'gauge',min: 0,max: 100,axisLine: {{lineStyle: {{width: 20,{color_gradient}}}}},progress: {{show: true,width: 20}},pointer: {{width: 6,length: '80%',itemStyle: {{color: '#fff'}}}},axisTick: {{ show: false }},splitLine: {{length: 20,lineStyle: {{ color: '#fff', width: 2 }}}},axisLabel: {{color: '#ffffff',fontSize: 12}},detail: {{formatter: function(value) {{return value;}},fontSize: 20,offsetCenter: [0, '65%'],color: '#ffffff'}},data: [{{ value: 0 }}]}}]}};chart.setOption(option);new QWebChannel(qt.webChannelTransport, function(channel) {{let bridge = channel.objects.bridge;bridge.update_value.connect(function(val, label) {{chart.setOption({{series: [{{data: [{{ value: val }}],detail: {{formatter: function() {{return label;}}}}}}]}});}});}});</script>
</body>
</html>
"""

更新效果见下图
请添加图片描述

4.系统核心

本小结为系统核心部分,这里把我代码里的main_utils.py代码贴出来,需要的朋友直接复制粘贴即可运行,界面上所有的数据都是取自系统,这个工具脚本可以帮你完成一切。

import getpass
import platform
import socket
import netifaces
from datetime import datetime
import requests
import psutil
import time
from collections import defaultdict
from concurrent.futures import ThreadPoolExecutor, as_completed
from src.conf import test_data, system_conf
from src.utils.custom_utils import format_sizedef sample_process(proc, num_cpus):try:cpu = proc.cpu_percent(None) / num_cpusmem = proc.memory_percent()info = proc.as_dict(attrs=['pid', 'name'])name = info['name']pid = info['pid']if name in ["System Idle Process", "", "System"] or pid == 0:return Nonereturn {'pid': pid,'name': name,'cpu_percent': cpu,'memory_percent': mem}except (psutil.NoSuchProcess, psutil.AccessDenied):return Nonedef get_top_processes():num_cpus = psutil.cpu_count(logical=True)procs = []for proc in psutil.process_iter(['pid', 'name']):try:proc.cpu_percent(None)  # 初始化procs.append(proc)except (psutil.NoSuchProcess, psutil.AccessDenied):continuetime.sleep(0.1)  # 等待 CPU 使用率更新temp = defaultdict(lambda: {'pid': None, 'name': '', 'cpu_percent': 0.0, 'memory_percent': 0.0})with ThreadPoolExecutor(max_workers=32) as executor:futures = [executor.submit(sample_process, proc, num_cpus) for proc in procs]for future in as_completed(futures):result = future.result()if result:name = result['name']if temp[name]['pid'] is None:temp[name]['pid'] = result['pid']temp[name]['name'] = nametemp[name]['cpu_percent'] += result['cpu_percent']temp[name]['memory_percent'] += result['memory_percent']merged_processes = list(temp.values())top_processes = sorted(merged_processes, key=lambda x: x['cpu_percent'], reverse=True)[:5]return top_processesdef get_disk_usage():"""获取硬盘使用数据:return: List[Dict] 每个字典包含一个分区的信息"""partitions = psutil.disk_partitions()disk_info_list = []for part in partitions:try:usage = psutil.disk_usage(part.mountpoint)disk_info = {"device": part.device,"mountpoint": part.mountpoint,"fstype": part.fstype,"total": format_size(usage.total),"used": format_size(usage.used),"free": format_size(usage.free),"percent": f"{usage.percent:.1f}%"}disk_info_list.append(disk_info)except PermissionError:continue  # 忽略无权限访问的分区return disk_info_listdef get_default_gateway():"""获取网关地址:return:"""gateways = netifaces.gateways()default_gateway = gateways.get('default')if default_gateway:return default_gateway.get(netifaces.AF_INET, [None])[0]return Nonedef get_system_info():"""获取系统数据:return:"""uname = platform.uname()boot_time = psutil.boot_time()uptime_str = str(datetime.now() - datetime.fromtimestamp(boot_time)).split('.')[0]info = {"os_version": f"{uname.system} {uname.release}","cpu_model": uname.processor or platform.processor(),"physical_cores": psutil.cpu_count(logical=False),"logical_cores": psutil.cpu_count(logical=True),"architecture": platform.machine(),"internal_ip": socket.gethostbyname(socket.gethostname()),"uptime": uptime_str,"username": getpass.getuser()}return infodef get_cpu_memory_usage():"""获取cpu和内存数据:return:"""cpu_usage = psutil.cpu_percent(interval=1)  # 1 秒采样时间memory_usage = psutil.virtual_memory().percentreturn float(cpu_usage), float(memory_usage)def get_network_speed(interval=1.0):"""获取当前网络上下行速度,单位 Mbps。:param interval: 采样间隔,单位秒:return: (upload_mbps, download_mbps)"""net1 = psutil.net_io_counters()time.sleep(interval)net2 = psutil.net_io_counters()bytes_sent = net2.bytes_sent - net1.bytes_sentbytes_recv = net2.bytes_recv - net1.bytes_recv# Bytes → bits → megabits (除以 1e6)upload_mbps = (bytes_sent * 8) / (interval * 1e6)download_mbps = (bytes_recv * 8) / (interval * 1e6)return round(upload_mbps, 3), round(download_mbps, 3)if __name__ == '__main__':print(get_location_by_ip())

5.为什么系统不卡?

有的同学可能会好奇,为什么系统1秒更新一次数据,界面并没有明显卡顿呢?
这里要多亏了多线程,具体来说我们定义了多个线程类,这些类继承自QThread,实现了其中的run方法,这样我们可以使用信号和槽对线程之间的数据进行管理,使用线程进行耗时操作不阻塞UI线程,所有数据更新都是在子线程中进行的,当数据处理完成通过信号的方式发射回到主线程,主线程操作UI,更新展示数据,通过上面的操作就避免了系统卡顿,这里我贴一段代码吧!

在这里插入图片描述
使用方法也很简单,实例化这个线程类后连接信号,最后调用.start方法开启线程
在这里插入图片描述
PS:这里可能有的同学还会有疑问,为什么我的线程类里重写的run方法,但是实例化之后调用的是start方法呢?这里告诉大家:您调用了start方法后会自动调用run方法,这里的逻辑QThread都帮咱们实现啦!

6.关于项目

本次项目设计并没有具体的设计图,是博主结合多种可视化方案以及可用技术整理出来的一套UI。
系统的项目名是:pyqt5-system-monitor-dashboard
我们的项目结构十分清晰,大家见名知意!
在这里插入图片描述

四.总结

本次和大家详细分享了我开发的运维系统大屏,详细介绍了我的项目实现和具体流程,通过粘贴代码和大家分享了我的项目部分代码,对于“web展示可视化图表以及图表数据更新”提出了我自己的两套方案,最后感谢大家看到这里!

在这里插入图片描述

在这里插入图片描述

相关文章:

  • 11.SPI和W25Q64
  • Gemini 的超长回复
  • CSS相关知识
  • 6个月Python学习计划 Day 4
  • 前端流行框架Vue3教程:26. 异步组件
  • 【25软考网工】第八章 (1)交换机基础
  • springboot 控制层调用业务逻辑层,注入报错,无法自动装配 解决办法
  • 在机器学习中,L2正则化为什么能够缓过拟合?为何正则化等机制能够使一个“过度拟合训练集”的模型展现出更优的泛化性能?正则化
  • c++总结-04-智能指针
  • 奈雪小程序任务脚本
  • Python与C++中浮点数的精度与计算误差(易忽略易错)
  • C++11(2):
  • 历年华东师范大学保研上机真题
  • 计算机病毒的发展历程及其分类
  • 审计报告附注救星!实现Word表格纵向求和+横向计算及其对应的智能校验
  • JavaScript 中的 structuredClone() 如何彻底改变你的对象复制方式
  • 制造业主要管理哪些主数据范围
  • 智能办公系统 — 审批管理模块 · 开发日志
  • 理解HTTP基本认证与表单登录认证
  • [创业之路-381]:企业战略管理案例分析-战略制定/设计-市场洞察“五看”:看宏观-经济-如何获得国家经济政策与愿景规划,以及技术发展趋势、技术成熟度
  • 做同城网站需要哪些/东莞百度搜索网站排名
  • 主流的网站开发技术/苏州网站建设书生商友
  • 深圳做网站建设/上海b2b网络推广外包
  • 怎么在自己做网站/网站网络营销
  • php网站的开发环境/网络推广营销网站建设专家
  • 毕业设计做旅游网站/黑帽seo什么意思