| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290 |
- #!/usr/bin/env python
- # -*- coding: utf-8 -*-
- import sys
- import os
- from datetime import datetime
- # 添加项目根目录到 Python 路径
- current_dir = os.path.dirname(os.path.abspath(__file__))
- project_root = os.path.dirname(current_dir)
- sys.path.append(project_root)
- from PyQt6.QtWidgets import (
- QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
- QPushButton, QLabel, QTextEdit, QGroupBox, QCheckBox,
- QComboBox, QSpinBox, QFrame, QSplitter, QFileDialog,
- QMessageBox
- )
- from PyQt6.QtCore import Qt, QTimer, pyqtSlot
- from PyQt6.QtGui import QFont, QTextCursor, QColor, QTextCharFormat
- from kodi_util.LoggerToolModule import LoggerTool
- class LogViewerWindow(QMainWindow):
- """日志查看器窗口"""
-
- def __init__(self, parent=None):
- super().__init__(parent)
-
- # 获取日志工具实例
- self.logger = LoggerTool()
-
- # 日志级别颜色映射
- self.level_colors = {
- 'DEBUG': QColor(128, 128, 128), # 灰色
- 'INFO': QColor(0, 0, 0), # 黑色
- 'WARNING': QColor(255, 165, 0), # 橙色
- 'ERROR': QColor(255, 0, 0), # 红色
- 'CRITICAL': QColor(139, 0, 0) # 深红色
- }
-
- # 日志过滤设置
- self.filter_levels = {'DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'}
- self.max_lines = 1000 # 最大显示行数
- self.auto_scroll = True # 自动滚动
-
- self.init_ui()
- self.connect_logger()
-
- def init_ui(self):
- """初始化用户界面"""
- self.setWindowTitle("日志查看器")
- self.setMinimumSize(800, 600)
-
- # 创建中央部件
- central_widget = QWidget()
- self.setCentralWidget(central_widget)
-
- # 创建主布局
- main_layout = QVBoxLayout(central_widget)
- main_layout.setContentsMargins(5, 5, 5, 5)
- main_layout.setSpacing(5)
-
- # 创建控制面板
- control_panel = self.create_control_panel()
- main_layout.addWidget(control_panel)
-
- # 创建分割器
- splitter = QSplitter(Qt.Orientation.Vertical)
-
- # 创建日志显示区域
- log_display_group = QGroupBox("日志显示")
- log_display_layout = QVBoxLayout(log_display_group)
-
- # 创建日志文本显示区域
- self.log_text_edit = QTextEdit()
- self.log_text_edit.setReadOnly(True)
- self.log_text_edit.setFont(QFont("Consolas", 9))
- self.log_text_edit.setLineWrapMode(QTextEdit.LineWrapMode.NoWrap)
- log_display_layout.addWidget(self.log_text_edit)
-
- # 创建状态信息区域
- status_group = QGroupBox("状态信息")
- status_layout = QVBoxLayout(status_group)
-
- self.status_label = QLabel("就绪")
- self.status_label.setStyleSheet("QLabel { color: green; }")
- status_layout.addWidget(self.status_label)
-
- self.log_count_label = QLabel("日志条数: 0")
- status_layout.addWidget(self.log_count_label)
-
- # 添加到分割器
- splitter.addWidget(log_display_group)
- splitter.addWidget(status_group)
- splitter.setStretchFactor(0, 4) # 日志显示区域占更多空间
- splitter.setStretchFactor(1, 1)
-
- main_layout.addWidget(splitter)
-
- # 日志计数器
- self.log_count = 0
-
- def create_control_panel(self):
- """创建控制面板"""
- control_group = QGroupBox("控制面板")
- control_layout = QVBoxLayout(control_group)
-
- # 第一行:日志级别过滤
- level_layout = QHBoxLayout()
- level_layout.addWidget(QLabel("日志级别过滤:"))
-
- self.level_checkboxes = {}
- for level in ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']:
- checkbox = QCheckBox(level)
- checkbox.setChecked(True)
- checkbox.stateChanged.connect(self.update_level_filter)
- self.level_checkboxes[level] = checkbox
- level_layout.addWidget(checkbox)
-
- level_layout.addStretch()
- control_layout.addLayout(level_layout)
-
- # 第二行:显示设置
- settings_layout = QHBoxLayout()
-
- # 最大行数设置
- settings_layout.addWidget(QLabel("最大显示行数:"))
- self.max_lines_spinbox = QSpinBox()
- self.max_lines_spinbox.setMinimum(100)
- self.max_lines_spinbox.setMaximum(10000)
- self.max_lines_spinbox.setValue(self.max_lines)
- self.max_lines_spinbox.valueChanged.connect(self.update_max_lines)
- settings_layout.addWidget(self.max_lines_spinbox)
-
- # 自动滚动设置
- self.auto_scroll_checkbox = QCheckBox("自动滚动")
- self.auto_scroll_checkbox.setChecked(self.auto_scroll)
- self.auto_scroll_checkbox.stateChanged.connect(self.update_auto_scroll)
- settings_layout.addWidget(self.auto_scroll_checkbox)
-
- settings_layout.addStretch()
- control_layout.addLayout(settings_layout)
-
- # 第三行:操作按钮
- button_layout = QHBoxLayout()
-
- # 清空日志按钮
- clear_btn = QPushButton("清空日志")
- clear_btn.clicked.connect(self.clear_logs)
- button_layout.addWidget(clear_btn)
-
- # 保存日志按钮
- save_btn = QPushButton("保存日志")
- save_btn.clicked.connect(self.save_logs)
- button_layout.addWidget(save_btn)
-
- # 测试日志按钮
- test_btn = QPushButton("测试日志")
- test_btn.clicked.connect(self.test_logs)
- button_layout.addWidget(test_btn)
-
- button_layout.addStretch()
- control_layout.addLayout(button_layout)
-
- return control_group
-
- def connect_logger(self):
- """连接日志信号"""
- try:
- ui_handler = self.logger.get_ui_handler()
- ui_handler.log_signal.connect(self.append_log)
- self.status_label.setText("已连接到日志系统")
- self.status_label.setStyleSheet("QLabel { color: green; }")
- except Exception as e:
- self.status_label.setText(f"连接日志系统失败: {str(e)}")
- self.status_label.setStyleSheet("QLabel { color: red; }")
-
- @pyqtSlot(str, str)
- def append_log(self, level, message):
- """添加日志消息"""
- # 检查级别过滤
- if level not in self.filter_levels:
- return
-
- # 获取当前光标位置
- cursor = self.log_text_edit.textCursor()
- cursor.movePosition(QTextCursor.MoveOperation.End)
-
- # 设置文本格式
- format = QTextCharFormat()
- if level in self.level_colors:
- format.setForeground(self.level_colors[level])
-
- # 插入日志消息
- cursor.insertText(message + '\n', format)
-
- # 更新计数
- self.log_count += 1
- self.log_count_label.setText(f"日志条数: {self.log_count}")
-
- # 限制最大行数
- self.limit_max_lines()
-
- # 自动滚动到底部
- if self.auto_scroll:
- scrollbar = self.log_text_edit.verticalScrollBar()
- scrollbar.setValue(scrollbar.maximum())
-
- def limit_max_lines(self):
- """限制最大显示行数"""
- document = self.log_text_edit.document()
- if document.blockCount() > self.max_lines:
- cursor = QTextCursor(document)
- cursor.movePosition(QTextCursor.MoveOperation.Start)
-
- # 删除超出的行数
- lines_to_remove = document.blockCount() - self.max_lines
- for _ in range(lines_to_remove):
- cursor.select(QTextCursor.SelectionType.BlockUnderCursor)
- cursor.removeSelectedText()
- cursor.deleteChar() # 删除换行符
-
- def update_level_filter(self):
- """更新日志级别过滤"""
- self.filter_levels.clear()
- for level, checkbox in self.level_checkboxes.items():
- if checkbox.isChecked():
- self.filter_levels.add(level)
-
- def update_max_lines(self, value):
- """更新最大行数设置"""
- self.max_lines = value
- self.limit_max_lines()
-
- def update_auto_scroll(self, state):
- """更新自动滚动设置"""
- self.auto_scroll = state == Qt.CheckState.Checked.value
-
- def clear_logs(self):
- """清空日志显示"""
- self.log_text_edit.clear()
- self.log_count = 0
- self.log_count_label.setText("日志条数: 0")
- self.status_label.setText("日志已清空")
- self.status_label.setStyleSheet("QLabel { color: blue; }")
-
- def save_logs(self):
- """保存日志到文件"""
- try:
- file_path, _ = QFileDialog.getSaveFileName(
- self,
- "保存日志文件",
- f"logs_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt",
- "文本文件 (*.txt);;所有文件 (*)"
- )
-
- if file_path:
- with open(file_path, 'w', encoding='utf-8') as f:
- f.write(self.log_text_edit.toPlainText())
-
- QMessageBox.information(self, "保存成功", f"日志已保存到: {file_path}")
- self.status_label.setText("日志保存成功")
- self.status_label.setStyleSheet("QLabel { color: green; }")
-
- except Exception as e:
- QMessageBox.critical(self, "保存失败", f"保存日志文件失败: {str(e)}")
- self.status_label.setText(f"保存失败: {str(e)}")
- self.status_label.setStyleSheet("QLabel { color: red; }")
-
- def test_logs(self):
- """测试日志输出"""
- self.logger.debug("这是一条调试信息")
- self.logger.info("这是一条信息")
- self.logger.warning("这是一条警告信息")
- self.logger.error("这是一条错误信息")
- self.logger.critical("这是一条严重错误信息")
-
- self.status_label.setText("测试日志已发送")
- self.status_label.setStyleSheet("QLabel { color: blue; }")
- if __name__ == "__main__":
- from PyQt6.QtWidgets import QApplication
-
- app = QApplication(sys.argv)
- window = LogViewerWindow()
- window.show()
- sys.exit(app.exec())
|