import sys import psutil import time from datetime import datetime import csv import os from PyQt5.QtWidgets import (QApplication, QMainWindow, QVBoxLayout, QHBoxLayout, QWidget, QLabel, QPushButton, QFileDialog, QMessageBox) from PyQt5.QtCore import QTimer, Qt, QPoint from PyQt5.QtGui import QPainter, QPen, QColor, QFont, QBrush import matplotlib.pyplot as plt from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas from matplotlib.figure import Figure class CPUMonitor(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("CPU 监控") self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint) self.setAttribute(Qt.WA_TranslucentBackground) # 数据存储 self.cpu_percent_history = [] self.cpu_temp_history = [] self.max_history_length = 120 # 增加到120个数据点 self.logging_enabled = False self.log_file = None self.csv_writer = None self.init_ui() self.init_timer() def init_ui(self): central_widget = QWidget() self.setCentralWidget(central_widget) layout = QVBoxLayout(central_widget) layout.setSpacing(15) layout.setContentsMargins(20, 20, 20, 20) # 获取屏幕尺寸,设置为半个屏幕 screen_geometry = QApplication.primaryScreen().geometry() screen_width = screen_geometry.width() screen_height = screen_geometry.height() # 设置为半个屏幕的大小 window_width = screen_width // 2 window_height = screen_height // 2 self.resize(window_width, window_height) # 窗口居中 self.move(screen_width // 4, screen_height // 4) # 顶部栏 (拖动用) title_layout = QHBoxLayout() title_label = QLabel("360环视 主板核心温度监控") title_font = QFont("微软雅黑", 20, QFont.Bold) title_label.setFont(title_font) title_label.setStyleSheet("color: white; font-weight: bold;") title_layout.addWidget(title_label) # 关闭按钮 self.close_btn = QPushButton("✕") self.close_btn.setFixedSize(50, 50) close_font = QFont("微软雅黑", 24, QFont.Bold) self.close_btn.setFont(close_font) self.close_btn.setStyleSheet(""" QPushButton { background-color: #e74c3c; color: white; border-radius: 10px; } QPushButton:hover { background-color: #c0392b; } """) self.close_btn.clicked.connect(self.close) # 日志按钮 self.log_btn = QPushButton("开始记录") self.log_btn.setFixedSize(150, 50) log_font = QFont("微软雅黑", 16) self.log_btn.setFont(log_font) self.log_btn.setStyleSheet(""" QPushButton { background-color: #3498db; color: white; border-radius: 10px; } QPushButton:hover { background-color: #2980b9; } """) self.log_btn.clicked.connect(self.toggle_logging) title_layout.addStretch() title_layout.addWidget(self.log_btn) title_layout.addSpacing(10) title_layout.addWidget(self.close_btn) layout.addLayout(title_layout) # 数据标签(大字号) info_layout = QHBoxLayout() # CPU使用率显示 cpu_frame = QWidget() cpu_frame.setStyleSheet("background-color: rgba(0, 0, 0, 100); border-radius: 15px;") cpu_layout = QVBoxLayout(cpu_frame) cpu_title = QLabel("CPU 使用率") cpu_title_font = QFont("微软雅黑", 18, QFont.Bold) cpu_title.setFont(cpu_title_font) cpu_title.setStyleSheet("color: #ecf0f1;") cpu_layout.addWidget(cpu_title) self.cpu_label = QLabel("--%") self.cpu_label.setFont(QFont("微软雅黑", 48, QFont.Bold)) self.cpu_label.setStyleSheet("color: #2ecc71;") self.cpu_label.setAlignment(Qt.AlignCenter) cpu_layout.addWidget(self.cpu_label) # 温度显示 temp_frame = QWidget() temp_frame.setStyleSheet("background-color: rgba(0, 0, 0, 100); border-radius: 15px;") temp_layout = QVBoxLayout(temp_frame) temp_title = QLabel("CPU 温度") temp_title.setFont(cpu_title_font) temp_title.setStyleSheet("color: #ecf0f1;") temp_layout.addWidget(temp_title) self.temp_label = QLabel("--°C") self.temp_label.setFont(QFont("微软雅黑", 48, QFont.Bold)) self.temp_label.setStyleSheet("color: #e67e22;") self.temp_label.setAlignment(Qt.AlignCenter) temp_layout.addWidget(self.temp_label) info_layout.addWidget(cpu_frame) info_layout.addSpacing(20) info_layout.addWidget(temp_frame) layout.addLayout(info_layout) # 图形(更大尺寸) self.figure = Figure(figsize=(12, 6), dpi=100, facecolor='#1e1e1e') self.canvas = FigureCanvas(self.figure) self.ax = self.figure.add_subplot(111) self.ax.set_facecolor('#2d2d2d') self.ax.spines['bottom'].set_color('white') self.ax.spines['top'].set_color('white') self.ax.spines['right'].set_color('white') self.ax.spines['left'].set_color('white') # 设置大字号 self.ax.tick_params(colors='white', labelsize=12) self.ax.set_ylim(0, 100) self.ax.set_xlim(0, self.max_history_length) self.ax.set_title("CPU line", color='white', fontsize=20, fontweight='bold') self.ax.set_xlabel("time (s)", color='white', fontsize=16) self.ax.set_ylabel("number", color='white', fontsize=16) # 绘制曲线 self.line, = self.ax.plot([], [], '#2ecc71', linewidth=3, label='CPU use (%)') self.temp_line, = self.ax.plot([], [], '#e74c3c', linewidth=3, alpha=0.8, label='CPU temp (°C)') # 图例 self.ax.legend(loc='upper right', facecolor='#2d2d2d', labelcolor='white', fontsize=14, framealpha=0.9) # 添加网格 self.ax.grid(True, alpha=0.3, color='white') layout.addWidget(self.canvas) # 状态栏 status_layout = QHBoxLayout() self.status_label = QLabel("就绪") self.status_label.setFont(QFont("微软雅黑", 12)) self.status_label.setStyleSheet("color: #bdc3c7;") status_layout.addWidget(self.status_label) status_layout.addStretch() # 添加时间显示 self.time_label = QLabel("") self.time_label.setFont(QFont("微软雅黑", 12)) self.time_label.setStyleSheet("color: #bdc3c7;") status_layout.addWidget(self.time_label) layout.addLayout(status_layout) # 设置窗口样式 self.setStyleSheet(""" QMainWindow { background-color: rgba(20, 20, 30, 220); border: 2px solid #3498db; border-radius: 15px; } QLabel { background: transparent; } """) def init_timer(self): self.timer = QTimer() self.timer.timeout.connect(self.update_monitor) self.timer.start(1000) # 每秒更新 # 图形更新定时器 self.graph_timer = QTimer() self.graph_timer.timeout.connect(self.update_graph) self.graph_timer.start(500) # 更新时间显示 self.time_timer = QTimer() self.time_timer.timeout.connect(self.update_time) self.time_timer.start(1000) def update_time(self): current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") self.time_label.setText(current_time) def get_cpu_temperature(self): """获取CPU温度""" try: temps = psutil.sensors_temperatures() if not temps: return None for name in ['coretemp', 'cpu_thermal', 'k10temp', 'cpu-thermal']: if name in temps: return temps[name][0].current for sensor in temps.values(): if sensor: return sensor[0].current return None except: return None def update_monitor(self): # 获取CPU使用率 cpu_percent = psutil.cpu_percent(interval=0.1) self.cpu_label.setText(f"{cpu_percent:.1f}%") # 根据使用率改变颜色 if cpu_percent < 80: self.cpu_label.setStyleSheet("color: #2ecc71;") elif cpu_percent < 95: self.cpu_label.setStyleSheet("color: #f39c12;") else: self.cpu_label.setStyleSheet("color: #e74c3c;") # 获取CPU温度 cpu_temp = self.get_cpu_temperature() if cpu_temp is not None: self.temp_label.setText(f"{cpu_temp:.1f}°C") # 根据温度改变颜色 if cpu_temp < 60: self.temp_label.setStyleSheet("color: #2ecc71;") elif cpu_temp < 80: self.temp_label.setStyleSheet("color: #f39c12;") else: self.temp_label.setStyleSheet("color: #e74c3c;") else: self.temp_label.setText("N/A") # 保存数据 self.cpu_percent_history.append(cpu_percent) self.cpu_temp_history.append(cpu_temp if cpu_temp is not None else 0) # 保持历史长度 if len(self.cpu_percent_history) > self.max_history_length: self.cpu_percent_history.pop(0) self.cpu_temp_history.pop(0) # 保存日志 if self.logging_enabled and self.csv_writer: timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") temp_value = f"{cpu_temp:.1f}" if cpu_temp is not None else "N/A" self.csv_writer.writerow([timestamp, f"{cpu_percent:.1f}", temp_value]) self.log_file.flush() def update_graph(self): """更新图形""" if not self.cpu_percent_history: return # 更新CPU使用率曲线 x_data = list(range(len(self.cpu_percent_history))) self.line.set_data(x_data, self.cpu_percent_history) # 更新温度曲线 if any(self.cpu_temp_history): temp_data = [t if t is not None else 0 for t in self.cpu_temp_history] self.temp_line.set_data(x_data, temp_data) # 动态调整Y轴范围(温度) max_temp = max(temp_data) if max_temp > 0: self.ax.set_ylim(0, max(100, max_temp + 10)) else: self.temp_line.set_data([], []) # 调整X轴范围 self.ax.set_xlim(0, max(self.max_history_length, len(self.cpu_percent_history))) # 重绘 self.canvas.draw_idle() def toggle_logging(self): """切换日志记录状态""" if not self.logging_enabled: default_filename = f"cpu_log_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv" filepath, _ = QFileDialog.getSaveFileName( self, "保存日志文件", default_filename, "CSV文件 (*.csv)" ) if filepath: try: self.log_file = open(filepath, 'w', newline='', encoding='utf-8') self.csv_writer = csv.writer(self.log_file) self.csv_writer.writerow(['时间', 'CPU使用率(%)', 'CPU温度(°C)']) self.logging_enabled = True self.log_btn.setText("📝 记录中...") self.log_btn.setStyleSheet(""" QPushButton { background-color: #27ae60; color: white; border-radius: 10px; } QPushButton:hover { background-color: #229954; } """) self.status_label.setText(f"日志记录中: {os.path.basename(filepath)}") QMessageBox.information(self, "日志记录", f"开始记录日志到:\n{filepath}") except Exception as e: QMessageBox.warning(self, "错误", f"无法创建日志文件:\n{str(e)}") else: self.logging_enabled = False if self.log_file: self.log_file.close() self.log_file = None self.csv_writer = None self.log_btn.setText("📝 开始记录") self.log_btn.setStyleSheet(""" QPushButton { background-color: #3498db; color: white; border-radius: 10px; } QPushButton:hover { background-color: #2980b9; } """) self.status_label.setText("日志记录已停止") QMessageBox.information(self, "日志记录", "日志记录已停止") def mousePressEvent(self, event): """实现窗口拖动""" if event.button() == Qt.LeftButton: self.drag_position = event.globalPos() - self.frameGeometry().topLeft() event.accept() def mouseMoveEvent(self, event): """实现窗口拖动""" if event.buttons() == Qt.LeftButton: self.move(event.globalPos() - self.drag_position) event.accept() def closeEvent(self, event): """关闭时清理""" if self.logging_enabled and self.log_file: self.log_file.close() event.accept() def main(): app = QApplication(sys.argv) window = CPUMonitor() window.show() sys.exit(app.exec_()) if __name__ == "__main__": main()