以下是用tkinter实现的一个任务管理器:
import tkinter as tk
from tkinter import ttk
import ctypes
import struct
import sys
import os
import time
import json
import psutil
from functools import partial
from cutool import systemTool
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.ticker import MultipleLocator
from threading import Thread as td
#获取任务栏高度
def get_taskbar_height():
user32 = ctypes.windll.user32
SPI_GETWORKAREA = 48
rect = ctypes.create_string_buffer(16)
user32.SystemParametersInfoA(SPI_GETWORKAREA, 0, rect, 0)
_, _, _, bottom = struct.unpack("4i", rect.raw)
screen_height = user32.GetSystemMetrics(1)
taskbar_height = screen_height - bottom
return taskbar_height
# ------------------------------功能实现-info显示------------------------------ #
def showInfoFrame():
cpus = psutil.cpu_percent()
mems = systemTool.GetMemInfo()["memRealUsed"] / systemTool.GetMemInfo()["memTotal"] * 100
dsks = systemTool.GetIoReadWrite()
dsks = (dsks["read"] + dsks["write"]) / 1024 / 1024
nets = systemTool.GetNetWork()
nets = (nets["up"] + nets["down"]) / 1024
cpuInfo.config(text = f"CPU: %.2f" % cpus + "%")
memInfo.config(text = "内存: %.2f" % mems + "%")
dskInfo.config(text = "硬盘: %.2fMB" % dsks)
netInfo.config(text = "网络: %.2fMB" % nets)
pidInfo.config(text = f"进程: {len(psutil.pids())}")
#win.after(0,valueGet,cpus,mems,dsks,nets)
td(target = valueGet,args = (cpus,mems,dsks,nets),daemon = True).start()
#td(target = getPid).start()
#getPid()
win.after(0,getPid)
win.update()
time.sleep(updateInterval / 1000)
#td(target = showInfoFrame).start()
win.after(updateInterval,showInfoFrame)
# ------------------------------功能实现-进程获取------------------------------ #
'''def getPid():
pidlist = []
pl = [[o,*pidtree.item(o)["values"]] for o in pidtree.get_children()]
for i in psutil.pids():
if pl == []:
pidlist.append((psutil.Process(i).name(),i))
for o in pl:
#print(f"pidi:{i},pido:{o}")
if not i != o[1:]:
pidtree.delete(o[0])
pidlist.append((psutil.Process(i).name(),i))
pidlist.sort()
for i in pidlist:
pidtree.insert("",tk.END,value = i)'''
def getPid():
tree = pidtree
dolist = []
for process in psutil.process_iter(['pid', 'name', 'cpu_percent', 'memory_info', 'io_counters', 'num_threads']):
try:
pid = process.info['pid']
name = process.info['name']
cpu_percent = process.info['cpu_percent']
memory_info = process.info['memory_info'].rss / (1024 * 1024)
io_counters = process.info['io_counters']
threads = process.info['num_threads']
# Check if the process is already in the treeview
item = tree.get_children()
found = False
for i in item:
if tree.item(i)["values"][0] == pid:
found = True
#print("item:",i,pid)
if tree.item(i)["values"] != (pid, name, cpu_percent, memory_info, io_counters.read_bytes + io_counters.write_bytes, threads):
dolist.append({"type":"item","value":[i,[pid, name, cpu_percent, memory_info, io_counters.read_bytes + io_counters.write_bytes, threads]]})
break
if not found:
dolist.append({"type":"insert","value":["","end",[pid, name, cpu_percent, memory_info, io_counters.read_bytes + io_counters.write_bytes, threads]]})
#print("insert:",pid)
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
print("Error")
for i in dolist:
cmd = i["value"]
if i["type"] == "item":
pidtree.item(cmd[0],values = cmd[1])
else:
pidtree.insert(*cmd[:2],value = cmd[2])
# ------------------------------功能实现-参数监视------------------------------ #
def valueGet(cpu,mem,dsk,net):
#cpu
cpuPlot.append(cpu)
cpuPlot.pop(0)
cpuAx.clear()
cpuAx.plot(cpuPlot, color="lightgreen")
cpuAx.set_yticks([0,100])
cpuAx.grid(zorder=0, linewidth="0.0", linestyle="-", color=(0,0,0))
cpuCanvas.draw()
#mem
memPlot.append(mem)
memPlot.pop(0)
memAx.clear()
memAx.plot(memPlot, color="b")
memAx.set_yticks([0,100])
memAx.grid(zorder=0, linewidth="0.0", linestyle="-", color=(0,0,0))
memCanvas.draw()
#dsk
dskPlot.append(dsk)
dskPlot.pop(0)
dskAx.clear()
dskAx.plot(dskPlot, color="cyan")
dskAx.set_yticks([0,20])
dskAx.grid(zorder=0, linewidth="0.0", linestyle="-", color=(0,0,0))
dskCanvas.draw()
#net
netPlot.append(net)
netPlot.pop(0)
netAx.clear()
netAx.plot(netPlot, color="orange")
netAx.set_yticks([0,20])
netAx.grid(zorder=0, linewidth="0.0", linestyle="-", color=(0,0,0))
netCanvas.draw()
print(cpu,mem,dsk,net)
win = tk.Tk()
win.title("任务管理器")
winsize = (800,600)
scrsize = (win.winfo_screenwidth(),win.winfo_screenheight())
win.geometry("{}x{}+{}+{}".format(*winsize,(scrsize[0] - winsize[0]) // 2,(scrsize[1] - winsize[1] - get_taskbar_height()) // 2))
win.minsize(780,100)
#告诉操作系统使用程序自身的dpi适配
ctypes.windll.shcore.SetProcessDpiAwareness(1)
#获取屏幕的缩放因子
ScaleFactor=ctypes.windll.shcore.GetScaleFactorForDevice(0)
#设置程序缩放
win.tk.call('tk', 'scaling', ScaleFactor/75)
#------------------------------窗口主菜单------------------------------#
updateInterval = 500 # ms,min:200,max:2000
def menuDraw():
def setColorViewm():
cwin = tk.Toplevel(win)
cwin.geometry("600x400")
cwin.resizable(0,0)
cwin.title("任务管理器-设置颜色")
#主菜单
wmenu = tk.Menu(win)
win.config(menu = wmenu)
#副菜单
filem = tk.Menu(wmenu,tearoff = 0) # 文件
#monim = tk.Menu(wmenu,tearoff = 0) # 监视器
optim = tk.Menu(wmenu,tearoff = 0) # 选项
viewm = tk.Menu(wmenu,tearoff = 0) # 视图
searm = tk.Menu(wmenu,tearoff = 0) # 搜索
helpm = tk.Menu(wmenu,tearoff = 0) # 帮助
#绑定副菜单
wmenu.add_cascade(label = "文件",menu = filem)
wmenu.add_cascade(label = "选项",menu = optim)
wmenu.add_cascade(label = "搜索",menu = searm)
wmenu.add_cascade(label = "帮助",menu = helpm)
#文件-副菜单
filem.add_command(label = "导出进程列表")
filem.add_separator()
filem.add_command(label = "退出")
#选项-副菜单
optim.add_checkbutton(label = "随系统启动")
optim.add_checkbutton(label = "只允许一个实例启动")
optim.add_separator()
optim.add_checkbutton(label = "窗口置顶")
optim.add_checkbutton(label = "通知栏图标显示")
optim.add_checkbutton(label = "最小化时隐藏")
optim.add_separator()
optim.add_checkbutton(label = "结束进程时确认操作")
optim.add_checkbutton(label = "创建进程时确认操作")
optim.add_cascade(label = "刷新速度")
#搜索-父菜单
#帮助-父菜单
menuDraw()
#窗口下部信息显示栏
infoFrame = tk.Frame(win,relief = "solid",bd = 1) # flat, groove, raised, ridge, solid, or sunken
cpuInfo = tk.Label(infoFrame,text = "CPU: -%")
memInfo = tk.Label(infoFrame,text = "内存: -%")
dskInfo = tk.Label(infoFrame,text = "硬盘: -KB")
netInfo = tk.Label(infoFrame,text = "网络: -KB")
pidInfo = tk.Label(infoFrame,text = "进程: -")
sizeGrip = ttk.Sizegrip(infoFrame)
cpuInfo.grid(row = 0,column = 0,sticky = "w")
ttk.Separator(infoFrame,orient = tk.VERTICAL).grid(row = 0,column = 1,sticky = "ns")
memInfo.grid(row = 0,column = 2,sticky = "w")
ttk.Separator(infoFrame,orient = tk.VERTICAL).grid(row = 0,column = 3,sticky = "ns")
dskInfo.grid(row = 0,column = 4,sticky = "w")
ttk.Separator(infoFrame,orient = tk.VERTICAL).grid(row = 0,column = 5,sticky = "ns")
pidInfo.grid(row = 0,column = 6,sticky = "w")
ttk.Separator(infoFrame,orient = tk.VERTICAL).grid(row = 0,column = 7,sticky = "ns")
netInfo.grid(row = 0,column = 8,sticky = "w")
ttk.Separator(infoFrame,orient = tk.VERTICAL).grid(row = 0,column = 9,sticky = "ns")
sizeGrip.grid(row = 0,column = 10,sticky = "se")
infoFrame.grid(row = 1,column = 0,sticky = "we")
infoFrame.columnconfigure(0,minsize = 120)
infoFrame.columnconfigure(2,minsize = 120)
infoFrame.columnconfigure(4,minsize = 120)
infoFrame.columnconfigure(6,minsize = 100)
infoFrame.columnconfigure(8,minsize = 120)
infoFrame.columnconfigure(10,weight = 1)
win.rowconfigure(0,weight = 1)
win.columnconfigure(0,weight = 1)
# ------------------------------窗口主要控件------------------------------ #
notebook = ttk.Notebook(win)
#进程列表
pidtreeFrame = tk.Frame(notebook)
pidtree = ttk.Treeview(pidtreeFrame,show = "headings",columns = list(range(7)))
titlenamelist = ['名称','PID','CPU使用率(%)','内存(MB)','磁盘读(KB)','磁盘写(KB)','线程数']
titlewidthlist = [100,50,80,100,80,80,50]
titleanchorlist = ["w","e","e","e","e","e","e"]
for i in range(7):
pidtree.column(i,anchor = tk.CENTER,width = titlewidthlist[i])
pidtree.heading(i,text = titlenamelist[i],anchor = titleanchorlist[i])
pidtreeScrollx = ttk.Scrollbar(pidtreeFrame,orient = tk.HORIZONTAL,command = pidtree.xview)
pidtreeScrolly = ttk.Scrollbar(pidtreeFrame,orient = tk.VERTICAL,command = pidtree.yview)
pidtreeScrollTab = tk.Frame(pidtreeFrame) # 填充右下角的空白
pidtree.configure(xscrollcommand = pidtreeScrollx.set)
pidtree.configure(yscrollcommand = pidtreeScrolly.set)
pidtreeScrollTab.grid(row = 1,column = 1,sticky = "nsew")
pidtreeScrollx.grid(row = 1,column = 0,sticky = "nsew")
pidtreeScrolly.grid(row = 0,column = 1,sticky = "nsew")
pidtreeFrame.rowconfigure(0,weight = 1)
pidtreeFrame.columnconfigure(0,weight = 1)
pidtree.grid(row = 0,column = 0,sticky = "nsew")
pidtreeFrame.grid(row = 0,column = 0,sticky = "nsew")
notebook.add(pidtreeFrame,text = "进程列表" + " " * 4)
#参数监视
historyListLen = 100
canvasSize = (200,160)
valueFrame = tk.Frame(notebook)
pandFrame = tk.PanedWindow(valueFrame,orient = tk.HORIZONTAL)
pandcmdn = tk.PanedWindow(pandFrame,orient = tk.VERTICAL)
pandcm = tk.PanedWindow(pandcmdn,orient = tk.HORIZONTAL)
panddn = tk.PanedWindow(pandcmdn,orient = tk.HORIZONTAL)
vif = tk.Frame(pandFrame)
cpuf = ttk.Labelframe(vif,text = "CPU")
memf = ttk.Labelframe(vif,text = "内存")
dskf = ttk.Labelframe(vif,text = "硬盘")
netf = ttk.Labelframe(vif,text = "网络")
class Vif:
class Cpuf:
cpus = systemTool.GetCpuInfo()
cpuName = cpus["cpu_name"]
cpuCount = cpus["cpu_count"]
cpuThreads = cpus["cpu_threads"]
cpuCore = cpus["cpu_core"]
cpuNamel = tk.Label(cpuf,text = "名称:")
cpuCountl = tk.Label(cpuf,text = "物理个数:")
cpuThreadsl = tk.Label(cpuf,text = "逻辑核心数:")
cpuCorel = tk.Label(cpuf,text = "物理核心数:")
cpuNamev = tk.Label(cpuf,text = cpuName)
cpuCountv = tk.Label(cpuf,text = cpuCount)
cpuThreadsv = tk.Label(cpuf,text = cpuThreads)
cpuCorev = tk.Label(cpuf,text = cpuCore)
cpuNamel.grid(row = 0,column = 0,sticky = "w")
cpuCountl.grid(row = 1,column = 0,sticky = "w")
cpuThreadsl.grid(row = 2,column = 0,sticky = "w")
cpuCorel.grid(row = 3,column = 0,sticky = "w")
cpuNamev.grid(row = 0,column = 1,sticky = "e")
cpuCountv.grid(row = 1,column = 1,sticky = "e")
cpuThreadsv.grid(row = 2,column = 1,sticky = "e")
cpuCorev.grid(row = 3,column = 1,sticky = "e")
class Memf:
mems = systemTool.GetMemInfo()
memTotal = mems["memTotal"]
memTotall = tk.Label(memf,text = "内存总数(MB)")
memTotalv = tk.Label(memf,text = memTotal)
memTotall.grid(row = 0,column = 0,sticky = "w")
memTotalv.grid(row = 0,column = 1,sticky = "e")
class Dskf:
dsks = systemTool.GetDiskInfo()
dsklf = tk.Frame(dskf,height = 50)
tree = ttk.Treeview(dsklf,show = "headings",columns = list(range(5)))
titlenamelist = ["盘符","总大小(GB)","已用空间(GB)","可用空间(GB)","格式"]
titlewidthlist = [50,100,100,100,70]
titleanchorlist = ["w","e","e","e","w"]
for i in range(5):
tree.column(i,anchor = tk.CENTER,width = titlewidthlist[i])
tree.heading(i,text = titlenamelist[i],anchor = titleanchorlist[i])
treeScrollx = ttk.Scrollbar(dsklf,orient = tk.HORIZONTAL,command = tree.xview)
treeScrolly = ttk.Scrollbar(dsklf,orient = tk.VERTICAL,command = tree.yview)
treeScrollTab = tk.Frame(dsklf) # 填充右下角的空白
tree.configure(xscrollcommand = treeScrollx.set)
tree.configure(yscrollcommand = treeScrolly.set)
treeScrollTab.grid(row = 1,column = 1,sticky = "nsew")
treeScrollx.grid(row = 1,column = 0,sticky = "nsew")
treeScrolly.grid(row = 0,column = 1,sticky = "nsew")
dsklf.rowconfigure(0,weight = 1)
dsklf.columnconfigure(0,weight = 1)
tree.grid(row = 0,column = 0,sticky = "nsew")
for i in dsks:
dskpath = i["path"]
dsktotal = "%.2f" % (i["size"]["total"] / 1073741824)
dskused = "%.2f" % (i["size"]["used"] / 1073741824)
dskfree = "%.2f" % (i["size"]["free"] / 1073741824)
dskfstype = i["fstype"]
tree.insert("",tk.END,values = (dskpath,dsktotal,dskused,dskfree,dskfstype))
dsklf.grid(row = 0,column = 0)
cpuf.grid(row = 0,column = 0,sticky = "nswe")
memf.grid(row = 1,column = 0,sticky = "nswe")
dskf.grid(row = 2,column = 0,sticky = "nswe")
netf.grid(row = 3,column = 0,sticky = "nswe")
pandcm.grid(row = 0,column = 0,sticky = "nsew")
panddn.grid(row = 1,column = 0,sticky = "nsew")
pandcmdn.grid(row = 0,column = 0,sticky = "nsew")
pandFrame.grid(row = 0,column = 0,sticky = "nsew")
valueFrame.rowconfigure(0,weight = 1)
valueFrame.columnconfigure(0,weight = 1)
#cpu
cpupFrame = tk.Frame(pandcm,bd = 1,relief = "sunken")
mempFrame = tk.Frame(pandcm,bd = 1,relief = "sunken")
dskpFrame = tk.Frame(panddn,bd = 1,relief = "sunken")
netpFrame = tk.Frame(panddn,bd = 1,relief = "sunken")
cpupFrame.rowconfigure(1,weight = 1)
mempFrame.rowconfigure(1,weight = 1)
dskpFrame.rowconfigure(1,weight = 1)
netpFrame.rowconfigure(1,weight = 1)
cpupFrame.columnconfigure(0,weight = 1)
mempFrame.columnconfigure(0,weight = 1)
dskpFrame.columnconfigure(0,weight = 1)
netpFrame.columnconfigure(0,weight = 1)
win.update()
tk.Label(cpupFrame,text = "CPU(%)").grid(row = 0,column = 0,sticky = "w",padx = 10,pady = 5)
tk.Label(mempFrame,text = "内存(%)").grid(row = 0,column = 0,sticky = "w",padx = 10,pady = 5)
tk.Label(dskpFrame,text = "硬盘(MB)").grid(row = 0,column = 0,sticky = "w",padx = 10,pady = 5)
tk.Label(netpFrame,text = "网络(MB)").grid(row = 0,column = 0,sticky = "w",padx = 10,pady = 5)
cpuFig,cpuAx = plt.subplots()
memFig,memAx = plt.subplots()
dskFig,dskAx = plt.subplots()
netFig,netAx = plt.subplots()
cpuCanvas = FigureCanvasTkAgg(cpuFig,master = cpupFrame)
memCanvas = FigureCanvasTkAgg(memFig,master = mempFrame)
dskCanvas = FigureCanvasTkAgg(dskFig,master = dskpFrame)
netCanvas = FigureCanvasTkAgg(netFig,master = netpFrame)
cpuCanvas.get_tk_widget().grid(row = 1,column = 0,padx = 10,pady = 5)
memCanvas.get_tk_widget().grid(row = 1,column = 0,padx = 10,pady = 5)
dskCanvas.get_tk_widget().grid(row = 1,column = 0,padx = 10,pady = 5)
netCanvas.get_tk_widget().grid(row = 1,column = 0,padx = 10,pady = 5)
cpuFig.set_facecolor((0,0,0))
memFig.set_facecolor((0,0,0))
dskFig.set_facecolor((0,0,0))
netFig.set_facecolor((0,0,0))
cpuAx.set_facecolor((0,0,0))
memAx.set_facecolor((0,0,0))
dskAx.set_facecolor((0,0,0))
netAx.set_facecolor((0,0,0))
cpuAx.tick_params(axis="x", labelcolor="black")
memAx.tick_params(axis="x", labelcolor="black")
dskAx.tick_params(axis="x", labelcolor="black")
netAx.tick_params(axis="x", labelcolor="black")
cpuAx.tick_params(axis="y", labelcolor="black")
memAx.tick_params(axis="y", labelcolor="black")
dskAx.tick_params(axis="y", labelcolor="black")
netAx.tick_params(axis="y", labelcolor="black")
cpuAx.yaxis.set_major_locator(MultipleLocator(10))
memAx.yaxis.set_major_locator(MultipleLocator(10))
dskAx.yaxis.set_major_locator(MultipleLocator(10))
netAx.yaxis.set_major_locator(MultipleLocator(10))
cpuCanvas.get_tk_widget()#.config(width = canvasSize[0], height = canvasSize[1])
memCanvas.get_tk_widget()#.config(width = canvasSize[0], height = canvasSize[1])
dskCanvas.get_tk_widget()#.config(width = canvasSize[0], height = canvasSize[1])
netCanvas.get_tk_widget()#.config(width = canvasSize[0], height = canvasSize[1])
cpuPlot = [0 for _ in range(historyListLen)]
memPlot = [0 for _ in range(historyListLen)]
dskPlot = [0 for _ in range(historyListLen)]
netPlot = [0 for _ in range(historyListLen)]
cpupFrame.grid(row = 0,column = 0,sticky = "nsew",padx = 1,pady = 1)
mempFrame.grid(row = 0,column = 0,sticky = "nsew",padx = 1,pady = 1)
dskpFrame.grid(row = 0,column = 0,sticky = "nsew",padx = 1,pady = 1)
netpFrame.grid(row = 0,column = 0,sticky = "nsew",padx = 1,pady = 1)
pandcm.add(cpupFrame,width = 280)
pandcm.add(mempFrame,width = 280)
panddn.add(dskpFrame,width = 280)
panddn.add(netpFrame,width = 280)
pandcmdn.add(pandcm,height = 270)
pandcmdn.add(panddn,height = 270)
pandFrame.add(pandcmdn)
pandFrame.add(vif)
notebook.add(valueFrame,text = "参数监视" + " " * 4)
notebook.grid(row = 0,column = 0,sticky = "nsew")
win.update()
getPid()
win.after(0,showInfoFrame)
win.mainloop()
这个任务管理器有一个很大的问题就是卡,可是目前没有找到什么方法……
感谢阅读,欢迎批评指正!