程序主要是用来对游戏计时的,当然其他的应用程序也是可以的,不过应该会有些Bug存在,因为在监控进程的时候,只取了匹配到的第一个PID,也就意味着无法区分是父进程还是子进程,不过对于监控游戏而言,这个问题应该影响不大...
用到的模块:
import tkinter as tk from tkinter import filedialog,Frame,messagebox import psutil import os import win32api from datetime import datetime import time from dateutil import parser
具体代码:
1 class GUI(Frame): 2 3 def __init__(self): 4 super().__init__() 5 self.exeFile = tk.Variable() 6 self.saveFile = tk.Variable() 7 8 self.start = None 9 self.end = None 10 self.sum = None 11 12 self.pid = None 13 14 self.time = tk.Variable() 15 self.time.set("游戏运行时间:00:00:00") 16 17 self.nowTime = tk.Variable() 18 self.nowTime.set(self.get_nowtime()) 19 self.startTime = tk.Variable() 20 self.startTime.set("游戏开始时间:0000-00-00 00:00:00") 21 self.endTime = tk.Variable() 22 self.endTime.set("游戏结束时间:0000-00-00 00:00:00") 23 24 self.set_gui() 25 26 def set_gui(self): 27 #设置控件 28 self.master.title("Running Time of The Game") 29 self.master.geometry("464x362+500+200") 30 self.pack() 31 32 frm1= Frame(self,width=400,height=90).pack(pady=17) 33 game_entry = tk.Entry(frm1, textvariable=self.exeFile, width=35).place(relx=0.19, rely=0.09) 34 save_entry = tk.Entry(frm1, textvariable=self.saveFile, width=35).place(relx=0.19, rely=0.21) 35 exe_button = tk.Button(frm1,text="载入程序",command=self.get_exe,width=7).place(relx=0.77,rely=0.077) 36 save_button = tk.Button(frm1,text="选择文本",command=self.start_time,width=7).place(relx=0.77,rely=0.2) 37 38 frm2 = Frame(self,width=400,height=180).pack() 39 label1 = tk.Label(frm2, textvariable = self.nowTime, width=50).place(relx=0.08, rely=0.36) 40 self.after(1000, self.reflash_nowtime) 41 label2 = tk.Label(frm2, textvariable = self.startTime, width=50).place(relx=0.08, rely=0.47) 42 label3 = tk.Label(frm2, textvariable=self.endTime, width=50).place(relx=0.08, rely=0.58) 43 label4 = tk.Label(frm2, textvariable=self.time, width=50).place(relx=0.08, rely=0.69) 44 45 frm3 = Frame(self,width=400,height=45).pack(pady=10) 46 run_button = tk.Button(frm3,text="运行",command=self.run,width=7).place(relx=0.2,rely=0.85) 47 exit_button = tk.Button(frm3,text="退出",command=self.quit,width=7).place(relx=0.8,rely=0.85) 48 statistics_button = tk.Button(frm3,text="统计",command=self.statistics_time,width=7).place(relx=0.5,rely=0.85) 49 50 def get_exe(self): 51 #在game_entry中显示游戏的路径 52 file = filedialog.askopenfilename() 53 self.exeFile.set(file) 54 55 def get_nowtime(self,flag=None): 56 #获取当前系统时间,flag用于区分是否点击了"运行按钮" 57 if flag is None: 58 now = datetime.now().strftime('%Y-%m-%d %H:%M:%S') 59 return "当前系统时间:" + now 60 else: 61 sum_time = "程序运行总时间:00:00:00" 62 return sum_time 63 64 def reflash_nowtime(self): 65 #利用after()方法达到定时器的作用,即:实现窗体时间按秒递加 66 self.nowTime.set(self.get_nowtime()) 67 self.after(1000, self.reflash_nowtime) 68 69 def statistics_time(self): 70 #统计时间文本中的总时间并保存至新文本 71 file = self.saveFile.get() 72 if file: 73 size = os.path.getsize(file) 74 if size>0: 75 sum = 0 76 with open(file,"r") as f: 77 for line in f.readlines(): 78 sum +=eval(line.split()[0]) 79 path = os.path.dirname(file) 80 savePath = path + '/总时间.txt' 81 with open(savePath,"a+") as f: 82 f.write(str(sum)+"\n") 83 messagebox.showwarning(title="成功", message="数据已保存!") 84 else: 85 messagebox.showwarning(title="错误", message="时间文本数据为空!") 86 else: 87 messagebox.showwarning(title="错误", message="未找到时间文本!") 88 89 def save(self): 90 #刷新运行总时间并保存至文本 91 self.end = datetime.now().strftime('%Y-%m-%d %H:%M:%S') 92 self.endTime.set("游戏结束时间:" + self.end) 93 self.start = parser.parse(self.start) 94 self.end = parser.parse(self.end) 95 self.sum = (self.end - self.start).total_seconds() 96 m, s = divmod(self.sum, 60) 97 h, m = divmod(m, 60) 98 self.time.set("游戏运行时间:%d:%02d:%02d" % (h, m, s)) 99 with open(self.saveFile.get(), "a+") as f: 100 f.write(str(self.sum/60)+"\n") 101 102 def is_run(self): 103 #不断刷新判断进程是否是运行状态 104 if psutil.pid_exists(self.pid): 105 self.after(1,self.is_run) 106 else: 107 self.save() 108 109 def start_time(self,flag=None): 110 # 在save_entry中显示保存时间文本的路径,flag用于区分是在选择文件还是点击了"运行"按钮 111 if flag is None: 112 # 获取并在save_entry中显示文件路径 113 file = filedialog.askopenfilename() 114 self.saveFile.set(file) 115 else: 116 #当exe程序运行时 117 self.start = time.strftime('%Y-%m-%d %H:%M:%S') 118 self.startTime.set("游戏开始时间:" + self.start) 119 self.is_run() 120 121 def get_pid(self,exe_file): 122 #根据程序名称获取进程号,以此判断是否为运行状态 123 win32api.ShellExecute(0, 'open',exe_file , '','',1) 124 time.sleep(0.5) 125 pl = psutil.pids() 126 f = os.path.basename(exe_file) 127 for pid in pl: 128 if psutil.Process(pid).name() != f: 129 continue 130 else: 131 self.pid = pid 132 self.start_time(self.pid) 133 """考虑到多进程问题,这里只获取匹配到的第一个pid,因为初衷是监测游戏运行时间,关闭游戏,即关闭父进程, 134 子进程也随之关闭,所以无论匹配的是子pid还是父pid,对程序的运行时没有影响的""" 135 break 136 137 def run(self): 138 # 当"运行"按钮被点击以后 139 exe_file = self.exeFile.get() 140 save_file = self.saveFile.get() 141 if exe_file: 142 result1 = os.path.basename(exe_file) 143 if result1.split(".")[-1] != "exe": 144 #并且如果选择的不是exe文件 145 messagebox.showwarning(title="错误",message="请打开一个exe文件!") 146 else: 147 if save_file: 148 result2 = os.path.basename(save_file) 149 if result2.split(".")[-1] != "txt": 150 messagebox.showwarning(title="错误", message="请选择一个txt文件进行保存!") 151 else: 152 self.get_pid(exe_file) 153 else: 154 messagebox.showwarning(title="错误", message="请选择一个txt文件进行保存!") 155 else: 156 messagebox.showwarning(title="错误",message="未找到程序!") 157 158 if __name__ == '__main__': 159 win = tk.Tk() 160 gui = GUI() 161 win.mainloop()
也是突然想写这么一个小程序,仓促学习了一下tkinter,有错误和需要改进的地方,还请评论指正~