在本博客中,我将分享如何使用 Python 和 PyQt5 构建一个简单的任务管理器应用程序。此应用程序可以显示所有运行中的进程,并提供一个按钮来终止每个进程。此外,每个进程还显示其关联的图标。这将是一个非常有趣的项目,可以帮助您更好地理解 Python 和 PyQt5 的实际应用。
在开始之前,您需要确保安装了以下 Python 包:
psutil
Pillow
pywin32
PyQt5
您可以使用以下命令来安装这些包:
pip install psutil Pillow pywin32 PyQt5
首先,我们需要导入一些必要的库:
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
这些库包括系统操作、图形界面、进程管理等功能。
定义一个函数 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
图像对象。
定义一个 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()
这个类初始化了主窗口,并设置了滚动区域来显示进程信息。
定义一个 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和名称,同时提供关闭进程的按钮。
最后,运行应用程序:
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_())
提取图标: 我们使用 win32gui
和 win32ui
提取可执行文件的图标。extract_icon
函数会返回提取到的图标图像。
创建主窗口: ProcessManager
类继承自 QMainWindow
,并在其中设置了布局和滚动区域,以便能够显示大量进程。
加载进程信息: load_processes
方法会遍历所有运行中的进程,并为每个进程提取图标和显示信息。同时,还会添加一个按钮,用于终止进程。
转换图像格式: pil2pixmap
方法用于将 PIL 图像转换为 PyQt5 可以显示的 QPixmap
。
终止进程: kill_process
方法用于终止指定的进程,并在终止后刷新进程列表。
运行该程序后,您会看到一个任务管理器窗口,显示当前所有运行中的进程。每个进程项包含进程的图标、进程 ID 和一个用于终止进程的按钮。点击按钮即可终止相应的进程,并且进程列表会自动刷新,显示当前的进程状态。
这段代码实现了一个简单的任务管理器应用程序,使用 PyQt5 作为 GUI 框架,并结合了 psutil
库来获取系统进程信息。主要功能包括:
提取图标:
extract_icon(exe_path)
函数从指定的可执行文件中提取图标,并将其转换为 PIL 图像。显示进程信息:
load_processes()
方法遍历当前系统中的所有进程,提取其图标和信息,并在 GUI 中显示。终止进程:
kill_process(pid)
方法终止指定的进程,并刷新进程列表。进程过滤和搜索:
进程详细信息:
多语言支持:
图标缓存:
系统监控工具:
远程任务管理器:
进程优先级调整:
进程树视图:
这段代码展示了如何使用 PyQt5 创建一个图形用户界面,并结合 psutil
库来获取和管理系统进程。通过提取进程图标、显示进程信息以及提供终止进程的功能,这个任务管理器应用程序为用户提供了一个直观且实用的工具来管理系统进程。
这段代码成功实现了一个基本的任务管理器应用程序,利用 PyQt5 提供图形用户界面,并结合 psutil
库获取和管理系统进程。通过提取进程图标、显示进程信息以及提供终止进程的功能,这个应用程序为用户提供了一个直观且实用的工具来管理系统进程。进一步的扩展和优化可以使其功能更加丰富和强大。
通过这个项目,您可以学到如何使用 Python 和 PyQt5 构建一个实用的桌面应用程序,并掌握一些处理系统进程和图标提取的技巧,欢迎在评论区留言。继续探索和学习,祝你在深度学习的旅程中取得更多的成果!
希望这个博客对你有所帮助!如果你有任何问题需要进一步的指导,请随时提问。继续加油!