开发者

Python+PyQt5实现自动化任务管理

目录
  • 一、项目概述
  • 二、功能使用
    • 1. 添加任务
    • 2. 定时任务执行
    • 3. 任务管理
    • 4. 日志功能
    • 5. 自定义界面设计
  • 三、代码实现与技术解析
    • 1. PyQt5界面设计
    • 2. 定时任务执行
    • 3. 任务执行与错误处理
    • 4. 日志导出
  • 四、效果展示
    • 五、相关源码
      • 六、总结

        一、项目概述

        本项目通过PyQt5构建图形界面,使用python实现了一个自动化任务管理系统。该系统支持添加各种类型的任务,能够根据用户设置的时间自动执行任务,如打开程序、关闭程序、关机、重启、锁屏等,同时记录任务执行过程中的日志,帮助用户实时跟踪任务的执行状态。

        项目目标

        任务类型:支持打开程序、关闭程序、关机、重启和锁屏等任务类型。

        任务调度:能够按计划时间定时执行任务,支持计划时间选择和倒计时执行。

        日志记录:每个任务的执行状态和结果都会被记录到日志中,方便用户查看历史记录。

        UI设计:通过PyQt5实现用户友好的图形界面,支持添加、删除、取消任务,界面美观,操作简单。

        二、功能使用

        1. 添加任务

        在任务管理界面中,用户可以通过选择任务类型(如打开程序、关闭程序、关机等)并设置目标路径(程序的路径),来创建一个新的任务。例如,选择“打开程序”后,用户可以通过“浏览”按钮选择需要启动的程序路径,设置好计划执行时间后,点击“添加任务”按钮,系统会根据设定的时间自动执行该任务。

        2. 定时任务执行

        任务被成功添加后,系统会计算当前时间与任务设定时间之间的差值,然后通过定时器(QTimer)在任务设定的时间点触发任务执行。例如,如果设置任务在“2023年12月31日 20:00:00”执行,程序会在该时刻自动运行相应的操作,如启动程序、关机等。

        3. 任务管理

        在任务列表中,用户可以查看所有已添加的任务,并根据任务的执行状态进行管理。系统支持以下操作:

        取消任务:用户可以取消一个待执行的任务,任务一旦被取消,将不会再执行。

        删除任务:用户可以删除已经执行过的任务,这样可以清理历史记录。

        查看日志:每个任务的执行日志会实时记录,包括任务的启动、执行结果、是否成功等信息,用户可以查看并导出日志,进行长期保存。

        4. 日志功能

        在任务管理软件中,日志功能是一个非常重要的部分。所有任务的执行过程都会被记录到日志中,用户可以实时查看任务的执行状态。如果任务执行失败,错误信息会被详细记录,并可以导出成文本文件,方便后期审查和分析。

        def log_task(self, task, message):
            timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            log_entry = f"{timestamp}: {message}"
            self.logs.append(log_entry)
            self.update_log_view()
        

        通过log_task函数,任务执行过程中产生的各种信息(如任务开始执行、执行成功或失败、错误信息等)都会记录在日志中。用户还可以导出这些日志,以便进一步分析。

        5. 自定义界面设计

        整个软件的界面使用了PyQt5框架进行设计。界面元素简洁、直观,用户可以方便地进行任务添加、删除、查看日志等操作。同时,通过QSS(Qt样式表)实现了美观的界面风格,如任务表格的样式、按钮的动态变化等,极大提升了用户体验。

        def get_button_style(self, color):
            return f"""
                QPushButton {{
                    background-color: {color};
                    color: white;
                    border: none;
                    border-radius: 4px;
                    padding: 8px;
                }}
                QPushButton:hover {{
                    background-color: {self.darken_color(color)};
                }}
                QPushButton:pressed {{
                    background-color: {self.darken_color(color, 30)};
                }}
            """
        

        通过get_button_style函数,按钮在不同状态下(如悬停、点击)会显示不同的颜色,增加了界面的交互性。

        三、代码实现与技术解析

        1. PyQt5界面设计

        在本项目中,界面设计主要通过PyQt5中的各种布局组件(如QvboxLayout, QHBoxLayout, QTableWidget等)来实现。QTableWidget用于显示任务列表,QComboBox用于选择任务类型,QLineEdit用于输入目标路径,QPushButton用于操作按钮。

        2. 定时任务执行

        定时任务的实现依赖于QTimer类,系统通过计算当前时间与任务设定时间之间的差值来启动定时器,一旦定时器到期,就会调用任务执行函数。通过这种方式,可以非常准确地按照用户设定的时间执行任务。

        3. 任务执行与错误处理

        在执行任务时,系统会根据任务类型调用相应的操作。例如,调用subprocess.Popen来启动程序,调用os.system来关机或重启。如果任务执行失败,系统会捕获异常并记录错误信息到日志中。

        def execute_task(self, task):
            try:
                if task_type == '打开程序':
                    subprocess.Popen(target_path)
                elif task_type == '关闭程序':
                    os.system(f'taskkill /IM {os.path.basename(target_path)} /F /T')
                elif task_type == '关机':
                    os.system("shutdown /s /t 0")
                elif task_type == '重启':
                    os.system("shutdown /r /t 0")
                elif task_type == '锁屏':
                    os.system("rundll32.exe user32.dll,LockWorkStation")
            except Exception as e:
                status = f"失败: {str(e)}"
                log_entry += f" - 错误: {status}"
            else:
                log_entry += " - 成功"
        

        4. 日志导出

        用户可以将日志导出为文本文件,方便长期保存。通过QFileDialog对话框,用户可以选择保存日志的路径和文件名,系统会将日志内容写入到指定的文件中。

        def export_logs(self):
            file_path, _ = QFileDialog.getSaveFileName(
                self, 
                '导出日志', 
                f'任务日志_{timestamp}.txt', 
                'Text Files (*.txt);;All Files (*)'
            )
            if file_path:
                try:
                    with open(编程客栈file_path, 'w', encoding='utf-8') as f:
                        f.write("=== 任务执行日志 ===\n")
                        f.write(f"导出时间: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n")
                        for log in self.logs:
                            f.write(log + '\n')
                    QMessageBox.information(self, "成功", f"日志已成功导出到:\n{file_path}")
                except Exception as e:
                    QMessageBox.critical(self, "错误", f"导出日志失败:\n{str(e)}")
        

        四、效果展示

        Python+PyQt5实现自动化任务管理

        Python+PyQt5实现自动化任务管理

        五、相关源码

        import sys
        import os
        import subprocess
        import datetime
        from PyQt5.QtCore import Qt, QDateTime, QTimer
        from PyQt5.QtGui import QIcon, QColor, QBrush
        from PyQt5.QtWidgets import (
            QApplication, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QComboBox,
            QLineEdit, QLabel, QTableWidget, QTableWidgetItem, QFileDialog,
            QDateTimeEdit, QMessageBox, QTextEdit, QHeaderView, QSizePolicy
        )
        
        class TaskManager(QWidget):
            def __init__(self):
                super().__init__()
                self.setWindowTitle('自动化任务管理软件')
                self.setWindowIcon(QIcon('icon.png'))
                self.setGeometry(100, 100, 1000, 700)
                self.setup_ui_style()
                self.tasks = []
                self.task_timers = {}
                self.task_id_counter = 0
                self.logs = []
                self.init_ui()
        
            def setup_ui_style(self):
                self.setStyleSheet("""
                    QWidget {
                        font-family: 'Microsoft YaHei';
                        font-size: 12px;
                    }
                    QLabel {
                        font-weight: bold;
                    }
                    QTableWidget {
                        alternate-background-color: #f5f5f5;
                        selection-background-color: #e0f7fa;
                        border: 1px solid #e0e0e0;
                    }
                    QHeaderView::section {
                        background-color: #607d8b;
                        color: white;
                        padding: 8px;
                        font-weight: bold;
                    }
                    QLineEdit, QDateTimeEdit, QComboBox {
                        padding: 5px;
                        border: 1px solid #bdbdbd;
                        border-radius: 3px;
                        min-height: 25px;
                    }
                    QTextEdit {
                        background-color: #fafafa;
                        border: 1px solid #e0e0e0;
                        padding: 5px;
                    }
                """)
        
            def init_ui(self):
                main_layout = QVBoxLayout()
                main_layout.setContentsMargins(15, 15, 15, 15)
                main_layout.setSpacing(15)
        
                # 任务类型选择
                task_type_layout = QHBoxLayout()
                task_type_layout.setSpacing(10)
                self.task_type_combo = QComboBox()
                self.task_type_combo.setMinimumWidth(200)
                self.task_type_combo.addItems(['打开程序', '关闭程序', '关机', '重启', '锁屏'])
                self.task_type_combo.currentIndexChanged.connect(self.update_target_path_status)
                task_type_layout.addwidget(QLabel('任务类型:'))
                task_type_layout.addWidget(self.task_type_combo)
                main_layout.addLayout(task_type_layout)
        
                # 目标路径输入
                self.target_path_input = QLineEdit()
                self.target_path_input.setPlaceholderText("请输入程序路径(如:C:\\Program Files\\App\\app.exe)")
                self.browse_button = QPushButton("浏览")
                self.browse_button.setFixedWidth(80)
                self.browse_button.setStyleSheet(self.get_button_style("#2196F3"))
                self.browse_button.clicked.connect(self.browse_file)
                target_layout = QHBoxLayout()
                target_layout.setSpacing(10)
                target_layout.addWidget(QLabel('目标路径:'))
                target_layout.addWidget(self.target_path_input)
                target_layout.addWidget(self.browse_button)
                main_layout.addLayout(target_layout)
        
                # 执行时间选择
                self.execution_time_picker = QDateTimeEdit()
                self.execution_time_picker.setCalendarPopup(True)
                self.execution_time_picker.setDisplayFormat("yyyy-MM-dd HH:mm:ss")
                current_time = QDateTime.currentDateTime()
                current_time.setSecssinceEpoch(current_time.toSecsSinceEpoch() - current_time.time().second())
                self.execution_time_picker.setDateTime(current_time)
                time_layout = QHBoxLayout()
                time_layout.addWidget(QLabel('执行时间:'))
                time_layout.addWidget(self.execution_time_picker)
                main_layout.addLayout(time_layout)
        
                # 操作按钮
                button_layout = QHBoxLayout()
                button_layout.setSpacing(20)
                self.add_task_button = QPushButton('添加任务')
                self.add_task_button.setFixedHeight(35)
                self.add_task_button.setStyleSheet(self.get_button_style("#4CAF50"))
                self.add_task_button.clicked.connect(self.add_task)
                self.export_log_button = QPushButton('导出日志')
                self.export_log_button.setFixedHeight(35)
                self.export_log_button.setStyleSheet(self.get_button_style("#2196F3"))
                self.export_log_button.clicked.connect(self.export_logs)
                button_layout.addWidget(self.add_task_button)
                button_layout.addWidget(self.export_log_button)
                main_layout.addLayout(button_layout)
        
                # 任务列表
                self.task_table = QTableWidget(0, 5)
                self.task_table.setHorizontalHeaderLabels(['任务类型', '目标路径', '执行时间', '执行状态', '操作'])
                self.task_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
                self.task_table.setColumnWidth(3, 100)
                self.task_table.setColumnWidth(4, 120)
                self.task_table.verticalHeader().setDefaultSectionSize(40)
                self.task_table.setAlternatingRowColors(True)
                main_layout.addWidget(QLabel('任务列表:'))
                main_layout.addWidget(self.task_table)
        
                # 日志显示
                self.log_text_edit = QTextEdit()
                self.log_text_edit.setReadOnly(True)
                main_layout.addWidget(QLabel('日志:'))
                main_layout.addWidget(self.log_text_edit)
        
                self.setLayout(main_layout)
        
            def get_button_style(self, color):
                return f"""
                    QPushButton {{
                        background-color: {color};
                        color: white;
                        border: none;
                        border-radius: 4px;
                        padding: 8px;
                    }}
                    QPushButton:hover {{
                        background-color: {self.darken_color(color)};
                    }}
                    QPushButton:pressed {{
                        background-color: {self.darken_color(color, 30)};
                    }}
                """
        
            def darken_color(self, hex_color, percent=20):
                """颜色变暗效果"""
                hex_color = hex_color.lstrip('#')
                rgb = tuple(int(hex_color[i:i+2], 16) for i in (0, 2, 4))
                darkened = tuple(max(0, int(c * (100 - percent) / 100)) for c in rgb)
        
                return f"#{darkened[0]:02x}{darkened[1]:02x}{darkened[2]:02x}"
        
            def update_target_path_status(self):
                task_type = self.task_type_combo.currentText()
                if task_type in ['打开程序', '关闭程序']:
                    self.target_path_input.setEnabled(True)
                    self.browse_button.setEnabled(True)
                else:
                    self.target_path_input.setEnabled(False)
                    self.browse_button.setEnabled(False)
        
            def browse_file(self):
                file_path, _ = QFileDialog.getOpenFileName(self, '选择程序', '', 'Executable Files (*.exe);;All Files (*)')
                if file_path:
                    self.target_path_input.setText(file_path)
        
            def add_task(self):
                task_type = self.task_type_combo.currentText()
                target_path = self.target_path_input.text()
                execution_time = self.execution_time_picker.dateTime()
                execution_time_str = execution_time.toString("yyyy-MM-dd HH:mm:ss")
        
                # 检查执行时间是否已过期
                if execution_time < QDateTime.currentDateTime():
                    error_msg = f"错误:不能添加过期任务(计划时间:{execution_time_str})"
                    self.show_error(error_msg)
                    self.log_task(None, error_msg)
                    return
        
                if task_type in ['打开程序', '关闭程序'] and not target_path:
                    error_msg = '错误:目标路径不能为空!'
                    self.show_error(error_msg)
                    self.log_task(None, error_msg)
                    return
        
                task_id = self.task_id_counter
                self.task_id_counter += 1
                task = {
                    'task_id': task_id,
                    '任务类型': task_type,
                    '目标路径': target_path,
                    '执行时间': execution_time_str,
                    '执行状态': '待执行'
                }
        
                delay = QDateTime.currentDateTime().msecsTo(execution_time)
                if delay <= 0:
                    self.execute_task(task)
                else:
                    timer = QTimer(self)
                    timer.setSingleShot(True)
                    timer.timeout.connect(lambda: self.execute_task(task))
                    timer.start(delay)
                    self.task_timers[task_id] = timer
        
                self.tasks.append(task)
                self.update_task_table()
                
                log_entry = f"已添加任务:{task_type} {target_path if target_path else ''},计划执行时间:{execution_time_str}"
                self.log_task(task, log_entry)
        
            def execute_task(self, task):
                task_type = task['任务类型']
                target_path = task['目标路径']
                status = '执行成功'
                log_entry = f"开始执行任务:{task_type} {target_path if target_path else ''}"
        
                try:
                    if task_type == '打开程序':
                        subprocess.Popen(target_path)
                    elif task_type == '关闭程序':
                        os.system(f'taskkill /IM {os.path.basename(target_path)} /F /T')
                    elif task_type == '关机':
                        os.system("shutdown /s /t 0")
                    elif task_type == '重启':
                        os.system("shutdown /r /t 0")
                    elif task_type == '锁屏':
                        os.system("rundll32.exe user32.dll,LockWorkStation")
                except Exception as e:
                    status = f"失败: {str(e)}"
                    log_entry += f" - 错误: {status}"
                else:
                    log_entry += " - 成功"
        
                task['执行状态'] = '已执行'
                if task['task_id'] in self.task_timers:
                    del self.task_timers[task['task_id']]
                
                self.log_task(task, log_entry)
                self.update_task_table()
        
            def update_task_table(self):
                self.task_table.setRowCount(0)
                for row, task in enumerate(self.tasks):
                    self.task_table.insertRow(row)
                    self.task_table.setRowHeight(row, 40)
                    
                    # 任务类型列
                    type_item = QTableWidgetItem(task['任务类型'])
                    self.task_table.setItem(row, 0, type_item)
                    
                    # 目标路径列
                    path_item = QTableWidgetItem(task['目标路径'])
                    path_item.setToolTip(task['目标路径'])
                    self.task_table.setItem(row, 1, path_ithttp://www.devze.comem)
                    
                    # 执行时间列
                    time_item = QTableWidgetItem(task['执行时间'])
                    self.task_table.setItem(row, 2, time_item)
                    
                    # 执行状态列
                    status_item = QTableWidgetItem(task['执行状态'])
                    status_item.setTextAlignment(Qt.AlignCenter)
                    if task['执行状态'] == '已执行':
                        status_item.setBackground(QBrush(QColor(200, 200, 200)))  # 灰色
                        status_item.setForeground(QBrush(QColor(50, 50, 50)))
                    else:
                        status_item.setBackground(QBrush(QColor(144, 238, 144)))  # 浅绿色
                        status_item.setForeground(QBrush(QColor(0, 100, 0)))
                    self.task_table.setItem(row, 3, status_item)
                    
                    # 操作列
                    button_container = QWidget()
                    button_layout = QHBoxLayout(button_container)
                    button_layout.setContentsMargins(5, 2, 5, 2)
                    button_layout.setSpacing(5)
                    
                    if task['执行状态'] == '待执行':
                        cancel_button = QPushButton('取消任务')
                        cancel_button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
                        cancel_button.setStyleSheet(self.get_button_style("#f44336"))
                        cancel_button.clicked.connect(lambda _, r=row: self.cancel_task(r))
                        button_layout.addWidget(cancel_button)
                    else:
                        delete_button = QPushButton('删除任务')
                        delete_button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
                        delete_button.setStyleSheet(self.get_button_style("#f44336"))
                        delete_button.clicked.connect(lambda _, r=row: self.delete_task(r))
                        button_layout.addWidget(delete_button)
                    
                    self.task_table.setCellWidget(row, 4, button_container)
        
            def cancel_task(self, row):
                if row < 0 or row >= len(self.tasks):
                    return
        
                task_to_cancel = self.tasks[row]
                
                # 停止定时器
                if task_to_cancel['task_id'] in self.task_time编程rs:
                    timer = self.task_timers[task_to_cancel['task_id']]
                    if timer.isActive():
                        timer.stop()
                    del self.task_timers[task_to_cancel['task_id']]
        
                # 从任务列表中移除
                self.tasks.pop(row)
                
                # 从表格中移除
                self.task_table.removeRow(row)
                
                # 记录日志
                log_entry = f"已取消任务:{task_to_cancel['任务类型']} {task_to_cancel['目标路径'] if task_to_cancel['目标路径'] else ''},原计划执行时间:{task_to_cancel['执行时间']}"
                self.log_task(task_to_cancel, log_entry)
                
                QMessageBox.information(self, "成功", "任务已取消并删除!")
        
            def delete_task(self, row):
                if row < 0 or row >= len(self.tasks):
                    return
        
                task_to_delete = self.tasks[row]
                self.tasks.pop(row)
                self.task_table.removeRow(row)
                
                log_entry = f"已删除任务:{task_to_delete['任务类型']} {task_to_delete['目标路径'] if task_to_delete['目标路径'] else ''},原执行时间:{task_to_delete['执行时间']}"
                self.log_task(task_to_delete, log_entry)
                
                QMessageBox.information(self, "成功", "任务已删除!")
        
            def log_task(self, task, message):
                timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                log_entry = f"{timestamp}: {message}"
                self.logs.append(log_entry)
                self.update_log_view()
        
            def update_log_view(self):
                self.log_text_edit.clear()
                for log in self.logs:
                    self.log_text_edit.append(log)
        
            def export_logs(self):
                timestamp = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
                file_path, _ = QFileDialog.getSaveFileName(
                    self, 
                    '导出日志', 
                    f'任务日志_{timestamp}.txt', 
                    'Text Files (*.txt);;All Files (*)'
                )
                if file_path:
                    try:
                        with open(file_path, 'w', encoding='utf-8') as f:
                            f.write("=== 任务执行日志 ===\n")
                            f.write(f"导出时间: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n")
                            for log in self.lo编程客栈gs:
                                f.write(log + '\n')
                        QMessageBox.information(self, "成功", f"日志已成功导出到:\n{file_path}")
                    except Exception as e:
                        QMessageBox.critical(self, "错误", f"导出日志失败:\n{str(e)}")
        
            def show_error(self, message):
                msg = QMessageBox(self)
                msg.setIcon(QMessageBox.Critical)
                msg.setWindowTitle("错误")
                msg.setText(message)
                msg.setStyleSheet("""
                    QMessageBox {
                        font-family: 'Microsoft YaHei';
                    }
                    QMessageBox QLabel {
                        font-size: 12px;
                    }
                """)
                msg.exec_()
        
        if __name__ == '__main__':
            app = QApplication(sys.argv)
            app.setStyle('Fusion')
            task_manager = TaskManager()
            task_manager.show()
            sys.exit(app.exec_())
        

        六、总结

        通过使用PyQt5和Python,成功实现了一个功能完善的自动化任务管理软件。该软件能够满足日常使用中对定时任务执行的需求,具备丰富的功能,包括任务添加、定时执行、任务取消、任务删除和日志导出等。通过对PyQt5的灵活使用和Python的强大支持,使得这一软件在功能实现、界面交互等方面都做得非常优秀。

        未来可以进一步扩展和优化该软件的功能,例如:

        支持更多的任务类型,如自动备份文件、自动清理系统等。

        增加任务优先级管理,让用户可以根据任务的紧急程度设定执行顺序。

        加强错误处理和系统监控功能,提供更多的反馈信息。

        总的来说,这是一个非常适合个人和小型团队使用的自动化php任务管理工具,能够显著提高工作效率和系统管理的便捷性。

        以上就是基于PyQt5实现自动化任务管理的详细内容,更多关于PyQt5任务管理的资料请关注编程客栈(www.devze.com)其它相关文章!

        0

        上一篇:

        下一篇:

        精彩评论

        暂无评论...
        验证码 换一张
        取 消

        最新开发

        开发排行榜