使用 Python 和 PyQt5 构建一个 带图标的任务管理器 附源码

在本博客中,我将分享如何使用 Python 和 PyQt5 构建一个简单的任务管理器应用程序。此应用程序可以显示所有运行中的进程,并提供一个按钮来终止每个进程。此外,每个进程还显示其关联的图标。这将是一个非常有趣的项目,可以帮助您更好地理解 Python 和 PyQt5 的实际应用。

环境准备

在开始之前,您需要确保安装了以下 Python 包:

  • psutil
  • Pillow
  • pywin32
  • PyQt5

您可以使用以下命令来安装这些包:

pip install psutil Pillow pywin32 PyQt5

代码片段解析与使用步骤

1. 导入必要的库

首先,我们需要导入一些必要的库:

import sys
import os
import ctypes
import psutil
import win32gui
import win32ui
import win32process
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QLabel, QPushButton, QWidget, QScrollArea, QHBoxLayout
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap, QImage
from PIL import Image

这些库包括系统操作、图形界面、进程管理等功能。

2. 提取图标函数

定义一个函数 extract_icon(exe_path) 来提取可执行文件的图标:

def extract_icon(exe_path):
    try:
        large, small = win32gui.ExtractIconEx(exe_path, 0)
        hdc = win32ui.CreateDCFromHandle(win32gui.GetDC(0))
        hbmp = win32ui.CreateBitmap()
        hbmp.CreateCompatibleBitmap(hdc, 32, 32)
        hdc = hdc.CreateCompatibleDC()
        hdc.SelectObject(hbmp)
        hdc.DrawIcon((0, 0), large[0])

        # 保存图标
        hbmpinfo = hbmp.GetInfo()
        hbmpstr = hbmp.GetBitmapBits(True)
        img = Image.frombuffer(
            'RGBA',
            (hbmpinfo['bmWidth'], hbmpinfo['bmHeight']),
            hbmpstr, 'raw', 'BGRA', 0, 1
        )

        # 释放资源
        win32gui.DestroyIcon(large[0])
        win32gui.DestroyIcon(small[0])

        return img
    except Exception as e:
        print(f"Error extracting icon from {exe_path}: {e}")
        return None

这个函数从可执行文件中提取图标,并将其转换为 PIL 图像对象。

3. 创建主窗口类

定义一个 ProcessManager 类来创建主窗口:

class ProcessManager(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.setGeometry(100, 100, 800, 600)
        self.setWindowTitle('任务管理器')

        self.central_widget = QWidget()
        self.layout = QVBoxLayout(self.central_widget)

        self.scroll_area = QScrollArea()
        self.scroll_area.setWidgetResizable(True)
        self.scroll_content = QWidget()
        self.scroll_layout = QVBoxLayout(self.scroll_content)

        self.scroll_area.setWidget(self.scroll_content)
        self.layout.addWidget(self.scroll_area)

        self.central_widget.setLayout(self.layout)
        self.setCentralWidget(self.central_widget)

        self.load_processes()

这个类初始化了主窗口,并设置了滚动区域来显示进程信息。

4. 加载进程信息

定义一个 load_processes 方法来加载当前运行的进程信息:

    def load_processes(self):
        # 清空现有布局
        for i in reversed(range(self.scroll_layout.count())):
            widget = self.scroll_layout.itemAt(i).widget()
            if widget is not None:
                widget.deleteLater()

        for proc in psutil.process_iter(['pid', 'name', 'exe']):
            try:
                exe_path = proc.info['exe']
                icon = extract_icon(exe_path)

                if icon:
                    qimage = self.pil2pixmap(icon)
                    icon_label = QLabel(self)
                    icon_label.setPixmap(qimage)

                    pid_label = QLabel(f"PID: {proc.info['pid']}, Name: {proc.info['name']}", self)

                    kill_button = QPushButton("关闭进程")
                    kill_button.clicked.connect(lambda _, p=proc.info['pid']: self.kill_process(p))

                    h_layout = QHBoxLayout()
                    h_layout.addWidget(icon_label)
                    h_layout.addWidget(pid_label)
                    h_layout.addWidget(kill_button)

                    container = QWidget()
                    container.setLayout(h_layout)
                    self.scroll_layout.addWidget(container)

            except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
                pass

这个方法遍历所有运行的进程,并显示它们的图标、PID和名称,同时提供关闭进程的按钮。

5. 运行应用程序

最后,运行应用程序:

if __name__ == '__main__':
    app = QApplication(sys.argv)
    manager = ProcessManager()
    manager.show()
    sys.exit(app.exec_())

这段代码创建并显示主窗口,并启动应用程序的事件循环。

通过这些步骤,你可以创建一个简单的任务管理器应用程序,显示当前运行的进程,并提供关闭进程的功能。

代码实现

下面是完整的代码:

import sys
import os
import ctypes
import psutil
import win32gui
import win32ui
import win32process
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QLabel, QPushButton, QWidget, QScrollArea, QHBoxLayout
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap, QImage
from PIL import Image

def extract_icon(exe_path):
    try:
        large, small = win32gui.ExtractIconEx(exe_path, 0)
        hdc = win32ui.CreateDCFromHandle(win32gui.GetDC(0))
        hbmp = win32ui.CreateBitmap()
        hbmp.CreateCompatibleBitmap(hdc, 32, 32)
        hdc = hdc.CreateCompatibleDC()
        hdc.SelectObject(hbmp)
        hdc.DrawIcon((0, 0), large[0])

        # 保存图标
        hbmpinfo = hbmp.GetInfo()
        hbmpstr = hbmp.GetBitmapBits(True)
        img = Image.frombuffer(
            'RGBA',
            (hbmpinfo['bmWidth'], hbmpinfo['bmHeight']),
            hbmpstr, 'raw', 'BGRA', 0, 1
        )

        # 释放资源
        win32gui.DestroyIcon(large[0])
        win32gui.DestroyIcon(small[0])

        return img
    except Exception as e:
        print(f"Error extracting icon from {exe_path}: {e}")
        return None

class ProcessManager(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.setGeometry(100, 100, 800, 600)
        self.setWindowTitle('任务管理器')

        self.central_widget = QWidget()
        self.layout = QVBoxLayout(self.central_widget)

        self.scroll_area = QScrollArea()
        self.scroll_area.setWidgetResizable(True)
        self.scroll_content = QWidget()
        self.scroll_layout = QVBoxLayout(self.scroll_content)

        self.scroll_area.setWidget(self.scroll_content)
        self.layout.addWidget(self.scroll_area)

        self.central_widget.setLayout(self.layout)
        self.setCentralWidget(self.central_widget)

        self.load_processes()

    def load_processes(self):
        # 清空现有布局
        for i in reversed(range(self.scroll_layout.count())):
            widget = self.scroll_layout.itemAt(i).widget()
            if widget is not None:
                widget.deleteLater()

        for proc in psutil.process_iter(['pid', 'name', 'exe']):
            try:
                exe_path = proc.info['exe']
                icon = extract_icon(exe_path)

                if icon:
                    qimage = self.pil2pixmap(icon)
                    icon_label = QLabel(self)
                    icon_label.setPixmap(qimage)

                    pid_label = QLabel(f"PID: {proc.info['pid']}, Name: {proc.info['name']}", self)

                    kill_button = QPushButton("关闭进程")
                    kill_button.clicked.connect(lambda _, p=proc.info['pid']: self.kill_process(p))

                    h_layout = QHBoxLayout()
                    h_layout.addWidget(icon_label)
                    h_layout.addWidget(pid_label)
                    h_layout.addWidget(kill_button)

                    container = QWidget()
                    container.setLayout(h_layout)
                    self.scroll_layout.addWidget(container)

            except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
                pass

    def pil2pixmap(self, im):
        im = im.convert("RGBA")
        data = im.tobytes("raw", "BGRA")
        qimage = QImage(data, im.size[0], im.size[1], QImage.Format_ARGB32)
        return QPixmap.fromImage(qimage)

    def kill_process(self, pid):
        try:
            proc = psutil.Process(pid)
            proc.terminate()
            proc.wait()  # 等待进程终止
            self.load_processes()  # 刷新进程列表
        except psutil.NoSuchProcess:
            print(f"No such process: {pid}")
        except psutil.AccessDenied:
            print(f"Access denied: {pid}")
        except Exception as e:
            print(f"Error terminating process {pid}: {e}")

if __name__ == '__main__':
    app = QApplication(sys.argv)
    manager = ProcessManager()
    manager.show()
    sys.exit(app.exec_())

代码详解

  1. 提取图标: 我们使用 win32guiwin32ui 提取可执行文件的图标。extract_icon 函数会返回提取到的图标图像。

  2. 创建主窗口ProcessManager 类继承自 QMainWindow,并在其中设置了布局和滚动区域,以便能够显示大量进程。

  3. 加载进程信息load_processes 方法会遍历所有运行中的进程,并为每个进程提取图标和显示信息。同时,还会添加一个按钮,用于终止进程。

  4. 转换图像格式pil2pixmap 方法用于将 PIL 图像转换为 PyQt5 可以显示的 QPixmap

  5. 终止进程kill_process 方法用于终止指定的进程,并在终止后刷新进程列表。

运行效果

        使用 Python 和 PyQt5 构建一个 带图标的任务管理器 附源码_第1张图片

运行该程序后,您会看到一个任务管理器窗口,显示当前所有运行中的进程。每个进程项包含进程的图标、进程 ID 和一个用于终止进程的按钮。点击按钮即可终止相应的进程,并且进程列表会自动刷新,显示当前的进程状态。

说明

这段代码实现了一个简单的任务管理器应用程序,使用 PyQt5 作为 GUI 框架,并结合了 psutil 库来获取系统进程信息。主要功能包括:

  1. 提取图标:从可执行文件中提取图标并转换为 PIL 图像。
  2. 显示进程信息:列出当前系统中的所有进程,包括进程 ID、名称和图标。
  3. 终止进程:提供按钮来终止选定的进程。

主要功能

  1. 提取图标

    • extract_icon(exe_path) 函数从指定的可执行文件中提取图标,并将其转换为 PIL 图像。
  2. 显示进程信息

    • load_processes() 方法遍历当前系统中的所有进程,提取其图标和信息,并在 GUI 中显示。
  3. 终止进程

    • kill_process(pid) 方法终止指定的进程,并刷新进程列表。

扩展

  1. 进程过滤和搜索

    • 添加一个搜索框,允许用户根据进程名称或 PID 过滤进程列表。
  2. 进程详细信息

    • 显示更多进程详细信息,如 CPU 和内存使用情况、启动时间等。
  3. 多语言支持

    • 使用 Qt 的翻译功能,支持多语言界面。
  4. 图标缓存

    • 缓存提取的图标,以减少重复提取的开销。

相关类型扩展

  1. 系统监控工具

    • 扩展为一个更全面的系统监控工具,显示 CPU、内存、磁盘和网络使用情况。
  2. 远程任务管理器

    • 实现远程任务管理功能,允许用户管理远程计算机上的进程。
  3. 进程优先级调整

    • 添加功能,允许用户调整进程的优先级。
  4. 进程树视图

    • 显示进程树视图,展示进程之间的父子关系。

   爬虫项目推荐

  • 使用 Python 指定内容 爬取百度引擎搜索结果-CSDN博客
  • 使用Python和Selenium爬取QQ新闻热榜-CSDN博客
  • 使用Selenium 和 Python 抓取快手网页大量评论-CSDN博客
  • 使用 Python 和 Selenium 爬取快手视频 附源码-CSDN博客
  • 如何使用Python、Selenium 爬取酷狗音乐网站的歌曲信息-CSDN博客
  • 使用Python 和 Selenium 抓取 酷狗 音乐专辑 附源码-CSDN博客

    其他项目推荐

  • 使用 TensorFlow 和 CIFAR-10 数据集进行图像分类-CSDN博客
  • 在 Python 中编写一个简单的文件搜索工具-CSDN博客
  • 使用Python从.exe文件中提取图标_提取文件图标-CSDN博客
  • Python 文件搜索程序详解与实现-CSDN博客
  • 使用Python 进行文本情感分析-CSDN博客
  • 使用 Python和PyQt5 打造 你的专属文件查询工具! 附源码-CSDN博客
  • 用Python和PyQt5打造你的专属音乐播放器!轻松创建带封面的音乐列表-CSDN博客

总结

这段代码展示了如何使用 PyQt5 创建一个图形用户界面,并结合 psutil 库来获取和管理系统进程。通过提取进程图标、显示进程信息以及提供终止进程的功能,这个任务管理器应用程序为用户提供了一个直观且实用的工具来管理系统进程。

结论

这段代码成功实现了一个基本的任务管理器应用程序,利用 PyQt5 提供图形用户界面,并结合 psutil 库获取和管理系统进程。通过提取进程图标、显示进程信息以及提供终止进程的功能,这个应用程序为用户提供了一个直观且实用的工具来管理系统进程。进一步的扩展和优化可以使其功能更加丰富和强大。

通过这个项目,您可以学到如何使用 Python 和 PyQt5 构建一个实用的桌面应用程序,并掌握一些处理系统进程和图标提取的技巧,欢迎在评论区留言。继续探索和学习,祝你在深度学习的旅程中取得更多的成果!


希望这个博客对你有所帮助!如果你有任何问题需要进一步的指导,请随时提问。继续加油!

你可能感兴趣的:(python,开发语言)