在这篇博客中,我们将探讨如何使用 wxPython 构建一个简单的 Windows 进程管理器应用程序。这个应用程序允许用户列出当前系统上的所有进程,选择和终止进程,并将特定进程保存到文件中以供将来加载。
C:\pythoncode\new\manageprocess.py
全部代码
import wx
import psutil
import os
import signal
class ProcessManager(wx.Frame):
def __init__(self, parent, title):
super(ProcessManager,self).__init__(parent, title=title, size=(800, 500))
self.panel = wx.Panel(self)
self.search_box = wx.TextCtrl(self.panel, style=wx.TE_PROCESS_ENTER)
self.Bind(wx.EVT_TEXT_ENTER, self.OnSearchProcess, self.search_box)
self.btn_list_processes = wx.Button(self.panel, label='List All Processes')
# Create ListView1 with a checkbox column
self.process_listview = wx.ListView(self.panel, style=wx.LC_REPORT | wx.LC_HRULES | wx.LC_VRULES)
self.process_listview.InsertColumn(0, '', width=40) # Checkbox column
self.process_listview.InsertColumn(1, 'Process Name', width=200)
self.process_listview.InsertColumn(2, 'PID', width=100)
self.process_listview.InsertColumn(3, 'CPU %', width=100)
self.process_listview.InsertColumn(4, 'RAM %', width=100)
self.selected_listview = wx.ListView(self.panel, style=wx.LC_REPORT)
self.selected_listview.InsertColumn(0, 'Process Name', width=200)
self.selected_listview.InsertColumn(1, 'PID', width=100)
self.btn_select_all = wx.Button(self.panel, label='Select All')
self.btn_deselect_all = wx.Button(self.panel, label='Deselect All')
self.btn_add_to_listview2 = wx.Button(self.panel, label='Add to ListView2')
self.btn_kill_processes = wx.Button(self.panel, label='Kill Selected Processes')
self.btn_kill_by_name = wx.Button(self.panel, label='Kill by Name')
self.btn_save = wx.Button(self.panel, label='Save')
self.btn_load = wx.Button(self.panel, label='Load')
self.btn_delete_selected = wx.Button(self.panel, label='Delete Selected')
# Organize layout with BoxSizers
main_sizer = wx.BoxSizer(wx.VERTICAL)
search_sizer = wx.BoxSizer(wx.HORIZONTAL)
listview1_sizer = wx.BoxSizer(wx.VERTICAL)
button_sizer = wx.BoxSizer(wx.HORIZONTAL)
listview2_sizer = wx.BoxSizer(wx.VERTICAL)
search_sizer.Add(self.search_box, 1, wx.EXPAND | wx.ALL, 5)
search_sizer.Add(self.btn_list_processes, 0, wx.EXPAND | wx.ALL, 5)
listview1_sizer.Add(search_sizer, 0, wx.EXPAND | wx.ALL, 5)
listview1_sizer.Add(self.process_listview, 1, wx.EXPAND | wx.ALL, 5)
button_sizer.Add(self.btn_select_all, 0, wx.EXPAND | wx.ALL, 5)
button_sizer.Add(self.btn_deselect_all, 0, wx.EXPAND | wx.ALL, 5)
button_sizer.Add(self.btn_add_to_listview2, 0, wx.EXPAND | wx.ALL, 5)
listview1_sizer.Add(button_sizer, 0, wx.ALIGN_CENTER | wx.ALL, 5)
listview2_sizer.Add(self.selected_listview, 1, wx.EXPAND | wx.ALL, 5)
listview2_sizer.Add(self.btn_kill_processes, 0, wx.EXPAND | wx.ALL, 5)
listview2_sizer.Add(self.btn_kill_by_name, 0, wx.EXPAND | wx.ALL, 5)
listview2_sizer.Add(self.btn_save, 0, wx.EXPAND | wx.ALL, 5)
listview2_sizer.Add(self.btn_load, 0, wx.EXPAND | wx.ALL, 5)
listview2_sizer.Add(self.btn_delete_selected, 0, wx.EXPAND | wx.ALL, 5)
main_sizer.Add(listview1_sizer, 1, wx.EXPAND | wx.ALL, 5)
main_sizer.Add(listview2_sizer, 1, wx.EXPAND | wx.ALL, 5)
self.panel.SetSizer(main_sizer)
self.Bind(wx.EVT_BUTTON, self.OnListProcesses, self.btn_list_processes)
self.Bind(wx.EVT_BUTTON, self.OnKillProcesses, self.btn_kill_processes)
self.Bind(wx.EVT_BUTTON, self.OnKillProcessesByName, self.btn_kill_by_name)
self.Bind(wx.EVT_BUTTON, self.OnSaveProcesses, self.btn_save)
self.Bind(wx.EVT_BUTTON, self.OnLoadProcesses, self.btn_load)
self.Bind(wx.EVT_BUTTON, self.OnSelectAll, self.btn_select_all)
self.Bind(wx.EVT_BUTTON, self.OnDeselectAll, self.btn_deselect_all)
self.Bind(wx.EVT_BUTTON, self.OnAddToListView2, self.btn_add_to_listview2)
self.Bind(wx.EVT_BUTTON, self.OnDeleteSelected, self.btn_delete_selected)
self.Show()
def OnListProcesses(self,event):
self.process_listview.DeleteAllItems()
for proc in psutil.process_iter(['pid', 'name', 'cpu_percent', 'memory_percent']):
index = self.process_listview.InsertItem(self.process_listview.GetItemCount(), '')
self.process_listview.SetItem(index, 1, proc.info['name'])
self.process_listview.SetItem(index, 2, str(proc.info['pid']))
self.process_listview.SetItem(index, 3, f"{proc.info['cpu_percent']:.1f}")
self.process_listview.SetItem(index, 4, f"{proc.info['memory_percent']:.1f}")
def OnSearchProcess(self,event):
search_query = self.search_box.GetValue().lower()
self.process_listview.DeleteAllItems()
for proc in psutil.process_iter(['pid', 'name', 'cpu_percent', 'memory_percent']):
if search_query in proc.info['name'].lower():
index = self.process_listview.InsertItem(self.process_listview.GetItemCount(), '')
self.process_listview.SetItem(index, 1, proc.info['name'])
self.process_listview.SetItem(index, 2, str(proc.info['pid']))
self.process_listview.SetItem(index, 3, f"{proc.info['cpu_percent']:.1f}")
self.process_listview.SetItem(index, 4, f"{proc.info['memory_percent']:.1f}")
def OnKillProcesses(self,event):
count = self.process_listview.GetItemCount()
for i in range(count):
if self.process_listview.GetItemState(i, wx.LIST_STATE_SELECTED):
pid = int(self.process_listview.GetItemText(i, 2))
try:
os.kill(pid, signal.SIGTERM)
except Exception as e:
wx.MessageBox(f"Error killing process {pid}: {str(e)}", "Error", wx.OK | wx.ICON_ERROR)
self.OnListProcesses(event)
def OnKillProcessesByName(self,event):
process_names = [self.selected_listview.GetItemText(i) for i in range(self.selected_listview.GetItemCount())]
for proc in psutil.process_iter(['name', 'pid']):
if proc.info['name'] in process_names:
try:
os.kill(proc.info['pid'], signal.SIGTERM)
except Exception as e:
wx.MessageBox(f"Error killing process {proc.info['pid']}: {str(e)}", "Error", wx.OK | wx.ICON_ERROR)
def OnSaveProcesses(self,event):
with open("processes.txt","w") as file:
count = self.selected_listview.GetItemCount()
for i in range(count):
process_name = self.selected_listview.GetItemText(i)
process_pid = self.selected_listview.GetItemText(i, 1)
file.write(f"{process_name},{process_pid}\n")
def OnLoadProcesses(self,event):
self.selected_listview.DeleteAllItems()
if os.path.exists("processes.txt"):
with open("processes.txt","r") as file:
for line in file:
process_name, process_pid = line.strip().split(',')
index = self.selected_listview.InsertItem(self.selected_listview.GetItemCount(), process_name)
self.selected_listview.SetItem(index, 1, process_pid)
def OnSelectAll(self,event):
count = self.process_listview.GetItemCount()
for i in range(count):
self.process_listview.SetItemState(i, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED)
def OnDeselectAll(self,event):
count = self.process_listview.GetItemCount()
for i in range(count):
self.process_listview.SetItemState(i, 0, wx.LIST_STATE_SELECTED)
def OnAddToListView2(self,event):
count = self.process_listview.GetItemCount()
for i in range(count):
if self.process_listview.GetItemState(i, wx.LIST_STATE_SELECTED):
process_name = self.process_listview.GetItemText(i, 1)
process_pid = self.process_listview.GetItemText(i, 2)
index = self.selected_listview.InsertItem(self.selected_listview.GetItemCount(), process_name)
self.selected_listview.SetItem(index, 1, process_pid)
def OnDeleteSelected(self,event):
count = self.selected_listview.GetItemCount()
for i in range(count - 1, -1, -1):
if self.selected_listview.GetItemState(i, wx.LIST_STATE_SELECTED):
self.selected_listview.DeleteItem(i)
if __name__ == "__main__":
app = wx.App(False)
frame = ProcessManager(None, "Process Manager")
app.MainLoop()
项目概述
我们的目标是构建一个图形用户界面 (GUI) 应用程序,主要功能包括:
- 列出所有进程:列出当前系统上的所有进程,并显示进程名、PID、CPU 和内存占用情况。
- 搜索进程:通过输入框搜索指定进程名称,并显示匹配结果。
- 选择和终止进程:通过复选框选择多个进程并终止它们。
- 保存和加载进程列表:将选定的进程保存到文本文件中,并从文件加载这些进程。
- 进程管理:添加功能来按名称终止进程,并从列表中删除选中的项。
准备工作
在开始之前,确保你已经安装了 Python 和 wxPython。你可以通过以下命令安装 wxPython:
pip install wxPython
构建应用程序
下面是我们将要实现的完整代码。你可以直接复制到你的 IDE 中并运行。
import wx
import psutil
import os
import signal
class ProcessManager(wx.Frame):
def __init__(self, parent, title):
super(ProcessManager, self).__init__(parent, title=title, size=(800, 500))
self.panel = wx.Panel(self)
# 搜索框
self.search_box = wx.TextCtrl(self.panel, style=wx.TE_PROCESS_ENTER)
self.Bind(wx.EVT_TEXT_ENTER, self.OnSearchProcess, self.search_box)
# 列出所有进程按钮
self.btn_list_processes = wx.Button(self.panel, label='List All Processes')
# 创建 ListView1 并添加复选框列
self.process_listview = wx.ListView(self.panel, style=wx.LC_REPORT | wx.LC_HRULES | wx.LC_VRULES)
self.process_listview.InsertColumn(0, '', width=40) # 复选框列
self.process_listview.InsertColumn(1, 'Process Name', width=200)
self.process_listview.InsertColumn(2, 'PID', width=100)
self.process_listview.InsertColumn(3, 'CPU %', width=100)
self.process_listview.InsertColumn(4, 'RAM %', width=100)
self.selected_listview = wx.ListView(self.panel, style=wx.LC_REPORT)
self.selected_listview.InsertColumn(0, 'Process Name', width=200)
self.selected_listview.InsertColumn(1, 'PID', width=100)
# 各种功能按钮
self.btn_select_all = wx.Button(self.panel, label='Select All')
self.btn_deselect_all = wx.Button(self.panel, label='Deselect All')
self.btn_add_to_listview2 = wx.Button(self.panel, label='Add to ListView2')
self.btn_kill_processes = wx.Button(self.panel, label='Kill Selected Processes')
self.btn_kill_by_name = wx.Button(self.panel, label='Kill by Name')
self.btn_save = wx.Button(self.panel, label='Save')
self.btn_load = wx.Button(self.panel, label='Load')
self.btn_delete_selected = wx.Button(self.panel, label='Delete Selected')
# 使用 BoxSizers 组织布局
main_sizer = wx.BoxSizer(wx.VERTICAL)
search_sizer = wx.BoxSizer(wx.HORIZONTAL)
listview1_sizer = wx.BoxSizer(wx.VERTICAL)
button_sizer = wx.BoxSizer(wx.HORIZONTAL)
listview2_sizer = wx.BoxSizer(wx.VERTICAL)
# 将搜索框和按钮添加到布局中
search_sizer.Add(self.search_box, 1, wx.EXPAND | wx.ALL, 5)
search_sizer.Add(self.btn_list_processes, 0, wx.EXPAND | wx.ALL, 5)
# 将 ListView1 和按钮添加到布局中
listview1_sizer.Add(search_sizer, 0, wx.EXPAND | wx.ALL, 5)
listview1_sizer.Add(self.process_listview, 1, wx.EXPAND | wx.ALL, 5)
button_sizer.Add(self.btn_select_all, 0, wx.EXPAND | wx.ALL, 5)
button_sizer.Add(self.btn_deselect_all, 0, wx.EXPAND | wx.ALL, 5)
button_sizer.Add(self.btn_add_to_listview2, 0, wx.EXPAND | wx.ALL, 5)
listview1_sizer.Add(button_sizer, 0, wx.ALIGN_CENTER | wx.ALL, 5)
# 将 ListView2 和其他按钮添加到布局中
listview2_sizer.Add(self.selected_listview, 1, wx.EXPAND | wx.ALL, 5)
listview2_sizer.Add(self.btn_kill_processes, 0, wx.EXPAND | wx.ALL, 5)
listview2_sizer.Add(self.btn_kill_by_name, 0, wx.EXPAND | wx.ALL, 5)
listview2_sizer.Add(self.btn_save, 0, wx.EXPAND | wx.ALL, 5)
listview2_sizer.Add(self.btn_load, 0, wx.EXPAND | wx.ALL, 5)
listview2_sizer.Add(self.btn_delete_selected, 0, wx.EXPAND | wx.ALL, 5)
main_sizer.Add(listview1_sizer, 1, wx.EXPAND | wx.ALL, 5)
main_sizer.Add(listview2_sizer, 1, wx.EXPAND | wx.ALL, 5)
self.panel.SetSizer(main_sizer)
# 绑定事件处理
self.Bind(wx.EVT_BUTTON, self.OnListProcesses, self.btn_list_processes)
self.Bind(wx.EVT_BUTTON, self.OnKillProcesses, self.btn_kill_processes)
self.Bind(wx.EVT_BUTTON, self.OnKillProcessesByName, self.btn_kill_by_name)
self.Bind(wx.EVT_BUTTON, self.OnSaveProcesses, self.btn_save)
self.Bind(wx.EVT_BUTTON, self.OnLoadProcesses, self.btn_load)
self.Bind(wx.EVT_BUTTON, self.OnSelectAll, self.btn_select_all)
self.Bind(wx.EVT_BUTTON, self.OnDeselectAll, self.btn_deselect_all)
self.Bind(wx.EVT_BUTTON, self.OnAddToListView2, self.btn_add_to_listview2)
self.Bind(wx.EVT_BUTTON, self.OnDeleteSelected, self.btn_delete_selected)
self.Show()
def OnListProcesses(self, event):
self.process_listview.DeleteAllItems()
for proc in psutil.process_iter(['pid', 'name', 'cpu_percent', 'memory_percent']):
index = self.process_listview.InsertItem(self.process_listview.GetItemCount(), '')
self.process_listview.SetItem(index, 1, proc.info['name'])
self.process_listview.SetItem(index, 2, str(proc.info['pid']))
self.process_listview.SetItem(index, 3, f"{proc.info['cpu_percent']:.1f}")
self.process_listview.SetItem(index, 4, f"{proc.info['memory_percent']:.1f}")
def OnSearchProcess(self, event):
search_query = self.search_box.GetValue().lower()
self.process_listview.DeleteAllItems()
for proc in psutil.process_iter(['pid', 'name', 'cpu_percent', 'memory_percent']):
if search_query in proc.info['name'].lower():
index = self.process_listview.InsertItem(self.process_listview.GetItemCount(), '')
self.process_listview.SetItem(index, 1, proc.info['name'])
self.process_listview.SetItem(index, 2, str(proc.info['pid']))
self.process_listview.SetItem(index, 3, f"{proc.info['cpu_percent']:.1f}")
self.process_listview.SetItem(index, 4, f"{proc.info['memory_percent']:.1f}")
def OnKillProcesses(self, event):
count = self.process_listview.GetItemCount()
for i in range(count):
if self.process_listview.GetItemState(i, wx.LIST_STATE_SELECTED):
pid = int(self.process_listview.GetItemText(i, 2))
try:
os.kill(pid, signal.SIGTERM)
except Exception as e:
wx.MessageBox(f"Error killing process {pid}: {str(e)}", "Error", wx.OK | wx.ICON_ERROR)
self.OnListProcesses(event)
def OnKillProcessesByName(self, event):
process_names = [self.selected_listview.GetItemText(i) for i in range(self.selected_listview.GetItemCount())]
for proc in psutil.process_iter(['name', 'pid']):
if proc.info['name'] in process_names:
try:
os.kill(proc.info['pid'], signal.SIGTERM)
except Exception as e:
wx.MessageBox(f"Error killing process {proc.info['pid']}: {str(e)}", "Error", wx.OK | wx.ICON_ERROR)
def OnSaveProcesses(self, event):
with open
('saved_processes.txt', 'w') as f:
for i in range(self.selected_listview.GetItemCount()):
process_name = self.selected_listview.GetItemText(i)
process_pid = self.selected_listview.GetItemText(i, 1)
f.write(f"{process_name},{process_pid}\n")
def OnLoadProcesses(self, event):
self.selected_listview.DeleteAllItems()
try:
with open('saved_processes.txt', 'r') as f:
for line in f.readlines():
process_name, process_pid = line.strip().split(',')
index = self.selected_listview.InsertItem(self.selected_listview.GetItemCount(), process_name)
self.selected_listview.SetItem(index, 1, process_pid)
except FileNotFoundError:
wx.MessageBox("No saved processes found.", "Error", wx.OK | wx.ICON_ERROR)
def OnSelectAll(self, event):
count = self.process_listview.GetItemCount()
for i in range(count):
self.process_listview.CheckItem(i)
def OnDeselectAll(self, event):
count = self.process_listview.GetItemCount()
for i in range(count):
self.process_listview.CheckItem(i, False)
def OnAddToListView2(self, event):
count = self.process_listview.GetItemCount()
for i in range(count):
if self.process_listview.IsItemChecked(i):
process_name = self.process_listview.GetItemText(i, 1)
process_pid = self.process_listview.GetItemText(i, 2)
index = self.selected_listview.InsertItem(self.selected_listview.GetItemCount(), process_name)
self.selected_listview.SetItem(index, 1, process_pid)
def OnDeleteSelected(self, event):
count = self.selected_listview.GetItemCount()
for i in range(count - 1, -1, -1):
if self.selected_listview.GetItemState(i, wx.LIST_STATE_SELECTED):
self.selected_listview.DeleteItem(i)
if __name__ == "__main__":
app = wx.App(False)
frame = ProcessManager(None, "Process Manager")
app.MainLoop()
代码解释
1. 初始化界面
在 ProcessManager
类的 __init__
方法中,我们设置了窗口的基本布局,并添加了所有必要的控件,包括 ListView
、按钮和搜索框。我们还绑定了所有按钮的事件处理方法。
2. 列出所有进程
在 OnListProcesses
方法中,我们使用 psutil.process_iter
获取所有正在运行的进程,并将它们显示在 ListView1
中。我们显示了进程名称、PID、CPU 使用率和内存使用率。
3. 搜索进程
OnSearchProcess
方法通过搜索框输入的内容进行过滤,并在 ListView1
中显示匹配的进程。
4. 选择和终止进程
我们可以使用复选框选择一个或多个进程,并通过 OnKillProcesses
和 OnKillProcessesByName
方法终止它们。
5. 保存和加载进程列表
OnSaveProcesses
方法将选中的进程保存到一个文本文件中,而 OnLoadProcesses
方法则从文件加载这些进程并显示在 ListView2
中。
6. 全选和全不选
通过 OnSelectAll
和 OnDeselectAll
方法,我们可以选择或取消选择 ListView1
中的所有项。
效果如下
总结
这个小型的进程管理器应用程序展示了如何使用 wxPython 构建一个功能强大的桌面应用。通过整合 psutil 和 wxPython,我们可以轻松地管理和监控系统进程,为用户提供了便捷的工具。
你可以进一步扩展这个应用程序,例如添加更多的进程管理功能,或者优化界面布局和用户体验。希望这篇博客对你有所帮助,并激发你在 Python 开发中的更多创意!