在这篇博客中,我们将探讨如何使用 wxPython 构建一个简单的 Windows 进程管理器应用程序。这个应用程序允许用户列出当前系统上的所有进程,选择和终止进程,并将特定进程保存到文件中以供将来加载。
C:\pythoncode\new\manageprocess.py
全部代码
import wx
import psutil
import os
import signalclass 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 columnself.process_listview = wx.ListView(self.panel, style=wx.LC_REPORT | wx.LC_HRULES | wx.LC_VRULES)self.process_listview.InsertColumn(0, '', width=40) # Checkbox columnself.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 BoxSizersmain_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 signalclass 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 开发中的更多创意!