python tkinter 制作任务管理器

以下是用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()

这个任务管理器有一个很大的问题就是卡,可是目前没有找到什么方法……

感谢阅读,欢迎批评指正!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值