最近在写一些小工具,因为是给别人用的需要界面,刚开始使用pyQT5? 功能强大,但是打包后一个小工具 就有几十兆 有点蛋疼而且还很消耗资源;后面改用TK,TK明显简洁很多,功能同样也若很多!
因为有截图需求,就抽空写了这个工具,全当练习。过程当中遇到过好多蛋疼的事情,功能基本实现后发出来给大家分享一下,我个人还是比较喜欢python这门语言的!
实现思路:
3.1.新建一个最小化窗口,利用线程启动监听"ctrl+a"启动截图窗口
3.2.截图窗口初始化时利用? pyautogui.screenshot 截取全屏(类似PRTSC)作为子窗口的背景(在这搞了好久,后面没办法只有利用canvas设置背景),子窗口最大化取消菜单栏
3.3.在主窗口上的canvas上用绑定鼠标事件,根据鼠标选取截图范围,和鼠标操作相关功能
3.4.保存功能是根据截图范围重新截图生成文件保存
代码
main_UI.py
tkinter.messagebox?showinfo Sc_Tool.Sc_Win?* keyboard _thread (): ????showinfo(,?) scwd?=?win?=?Tk() win.wm_state() win.iconify() (): ????scwd ????scwd?=?windSc(win) ????scwd.newwind() (): ????() ????scwd.exit_sc(scwd) (): ????keyboard.add_hotkey(,?star_sc,?=(),=?) (): ????keyboard.add_hotkey(,?exit_sc,?=(),=?) : ????_thread.start_new_thread(startThread1,?()) ????_thread.start_new_thread(startThread2,?()) e: ????(e) win.mainloop() (): ????showinfo(,?) scwd?=?win?=?Tk() win.wm_state() win.iconify() (): ????scwd ????scwd?=?windSc(win) ????scwd.newwind() (): ????scwd.exit_sc(scwd) (): ????scwd.ctrl_z(scwd) (): ????keyboard.add_hotkey(,?star_sc,?=(),=?) (): ????keyboard.add_hotkey(,?exit_sc,?=(),=?) (): ????keyboard.add_hotkey(,?ctrl_z,?=(),?=?) : ????_thread.start_new_thread(startThread1,?()) ????_thread.start_new_thread(startThread2,?()) ????_thread.start_new_thread(startThread3,?()) e: ????(e) win.mainloop()
Sc_Tool/Sc_Win.py
import?os from?tkinter?import?* import?tkinter import?pyautogui?as?pyautogui from?PIL?import?Image,?ImageTk import?tkinter.font?as?tkFont import?time class?windSc: ????win,?file_path,im,?winAppSc,?mouEvent,?canvas?=?None,?None,?None,?None,?None,?None ????#窗口宽??窗口高??宽??高???截图起点x坐标??截图起点y坐标??绘图起点x坐标?绘图起点?y坐标 ????win_w,?win_h,?width,?height,?x,?y,?dx,?dy=?0,?0,?0,?0,?0,?0,?0,?0 ????#截图结束点坐标 ????end_x,?end_y?=?0,?0 ????#开始添加图形的起始坐标 ????cr_x,?cr_y?=0,?0 ????#记录按钮的状态、文本输入按钮状态 ????but1_stat,but_text_stat?=?False,?False ????#记录按钮类型??1矩形?2圆形 ????but_type?=?0 ????#tag标记?文本输入单击次数标记 ????i,p?=?1?,0 ????#?工具栏部件 ????but1,?but2,?but3,?but4,?buttext,text_lable?=?None,?None,?None,?None,?None,?None ????#?画笔大小,文本框行数 ????size,?row?=?1,?1 ????#?画笔颜色 ????color?=?"black" ????#?字体 ????font?=?None ????#?按钮图片 ????img1,?img2,?img3,?imgs,?imgp1,?imgp2,?imgp3?=?None,?None,?None,?None,?None,?None,?None ????imgred?,?imgwhite?,?imgblack,?imgblue,?imggreen,?imgyellow,?imgback?=?None,?None,?None,?None,?None,?None,?None ????#?工具按钮列表 ????but_list?=?[] ????#?图形id列表 ????ids?=?[] ????def?__init__(self,win): ????????self.win?=?win ????????#?获取屏幕分辨率 ????????self.width,?self.height?=?win.winfo_screenwidth(),?win.winfo_screenheight() ????????#?窗口宽度和高度 ????????self.win_w,?self.win_h?=?self.width,?self.height ????????image?=?pyautogui.screenshot(region=[0,?0,?self.width,?self.height]).resize((self.width,?self.height)) ????????self.im?=?ImageTk.PhotoImage(image) ????????self.img1?=?tkinter.PhotoImage(file="Sc_Tool/icon/1.png") ????????self.img2?=?tkinter.PhotoImage(file="Sc_Tool/icon/2.png") ????????self.img3?=?tkinter.PhotoImage(file="Sc_Tool/icon/3.png") ????????self.imgtext?=?tkinter.PhotoImage(file="Sc_Tool/icon/Text.png") ????????self.imgs?=?tkinter.PhotoImage(file="Sc_Tool/icon/s.png") ????????self.imgp1?=?tkinter.PhotoImage(file="Sc_Tool/icon/p1.png") ????????self.imgp2?=?tkinter.PhotoImage(file="Sc_Tool/icon/p2.png") ????????self.imgp3?=?tkinter.PhotoImage(file="Sc_Tool/icon/p3.png") ????????self.imgblack?=?tkinter.PhotoImage(file="Sc_Tool/icon/black.png") ????????self.imgwhite?=?tkinter.PhotoImage(file="Sc_Tool/icon/white.png") ????????self.imgred?=?tkinter.PhotoImage(file="Sc_Tool/icon/red.png") ????????self.imggreen?=?tkinter.PhotoImage(file="Sc_Tool/icon/green.png") ????????self.imgblue?=?tkinter.PhotoImage(file="Sc_Tool/icon/blue.png") ????????self.imgyellow?=?tkinter.PhotoImage(file="Sc_Tool/icon/yellow.png") ????????self.imgback?=?tkinter.PhotoImage(file="Sc_Tool/icon/b.png") ????def?newwind(self,event=''): ????????#?最小化主窗口 ????????self.win.wm_state('icon') ????????self.win.iconify() ????????self.winAppSc?=?Toplevel(self.win) ????????#winAppSc.attributes("-alpha",?1) ????????#删除标题栏 ????????self.winAppSc.overrideredirect(True) ????????self.winAppSc.geometry("%dx%d+%d+%d"?%(self.win_w,self.win_h,(self.width-self.win_w)/2,(self.height-self.win_h)/2)) ????????self.winAppSc.config(bg="white") ????????self.winAppSc.title('截屏') ????????self.winAppSc.attributes("-topmost",?True) ????????canvas?=?tkinter.Canvas(self.winAppSc, ????????????????????????????????width=self.win_w,??#?指定Canvas组件的宽度 ????????????????????????????????height=self.win_h,??#?指定Canvas组件的高度 ????????????????????????????????bg='red')??#?指定Canvas组件的背景色 ????????canvas.create_image(0,?0,?image=self.im,?anchor='nw',?tag=('r',?'r0')) ????????canvas.pack(fill='both',?expand='yes') ????????self.canvas?=?canvas ????????#工具栏部件 ????????self.but1?=?Button(self.winAppSc,?text="保存",?image=self.imgs) ????????self.but2?=?Button(self.winAppSc,?text="矩形",?image=self.img1) ????????self.but3?=?Button(self.winAppSc,?text="圆形",?image=self.img2) ????????self.but4?=?Button(self.winAppSc,?text="箭头",?image=self.img3) ????????self.buttext?=?Button(self.winAppSc,?text="文本",?image=self.imgtext) ????????self.but5?=?Button(self.winAppSc,?text="返回",?image=self.imgback) ????????#?画笔大小 ????????self.sizebut1?=??Button(self.winAppSc,?text="1",?image?=?self.imgp1) ????????self.sizebut2?=?Button(self.winAppSc,?text="5",?image?=?self.imgp2) ????????self.sizebut3?=?Button(self.winAppSc,?text="10",?image?=?self.imgp3) ????????#?画笔颜色 ????????self.color_red?=?Button(self.winAppSc,?text="red",?image?=?self.imgred) ????????self.color_green?=?Button(self.winAppSc,?text="red",?image=self.imggreen) ????????self.color_blue?=?Button(self.winAppSc,?text="red",?image=self.imgblue) ????????self.color_yellow?=?Button(self.winAppSc,?text="red",?image=self.imgyellow) ????????self.color_black?=?Button(self.winAppSc,?text="red",?image=self.imgblack) ????????self.color_white?=?Button(self.winAppSc,?text="red",?image=self.imgwhite) ????????#文本框 ????????self.text_entry?=?Text(self.winAppSc,bg=None,relief=None,height=self.row,width=4) ????????canvas.bind('<1>',?lambda?event:self.setxy(event,canvas)) ????????canvas.bind('<B1-Motion>',lambda?event:self.getxy(event,canvas)) ????????canvas.bind('<ButtonRelease-1>',?lambda?event:?self.setBtn(event,self.winAppSc)) ????????canvas.bind('<3>',?lambda?event:?self.clear(canvas)) ????????self.but1.bind('<1>',?lambda?event:?self.bu_save(event)) ????????self.but2.bind('<1>',?lambda?event:?self.bu_click(event,canvas,1)) ????????self.but3.bind('<1>',?lambda?event:?self.bu_click(event,?canvas,2)) ????????self.but4.bind('<1>',?lambda?event:?self.bu_click(event,?canvas,3)) ????????self.buttext.bind('<1>',?lambda?event:?self.bu_click_text(event,?canvas)) ????????self.sizebut1.bind('<1>',?lambda?event:?self.sizebut_click(1)) ????????self.sizebut2.bind('<1>',?lambda?event:?self.sizebut_click(5)) ????????self.sizebut3.bind('<1>',?lambda?event:?self.sizebut_click(10)) ????????self.color_red.bind('<1>',?lambda?event:?self.colorbut_click("red")) ????????self.color_green.bind('<1>',?lambda?event:?self.colorbut_click("green")) ????????self.color_blue.bind('<1>',?lambda?event:?self.colorbut_click("blue")) ????????self.color_yellow.bind('<1>',?lambda?event:?self.colorbut_click("yellow")) ????????self.color_white.bind('<1>',?lambda?event:?self.colorbut_click("white")) ????????self.color_black.bind('<1>',?lambda?event:?self.colorbut_click("black")) ????????self.text_entry.bind('<Key>',lambda?event:?self.entry(event)) ????????self.but5.bind('<1>',?lambda?event:?self.ctrl_z()) ????????#?先清空but_list?以防止下次截图时?还保存有之前的按钮??而之前的按钮的父窗口已经销毁 ????????self.but_list.clear() ????????self.but_list.append(self.but1) ????????self.but_list.append(self.but2) ????????self.but_list.append(self.but3) ????????self.but_list.append(self.but4) ????????self.but_list.append(self.buttext) ????????self.but_list.append(self.sizebut1) ????????self.but_list.append(self.sizebut2) ????????self.but_list.append(self.sizebut3) ????????self.but_list.append(self.color_red) ????????self.but_list.append(self.color_green) ????????self.but_list.append(self.color_blue) ????????self.but_list.append(self.color_yellow) ????????self.but_list.append(self.color_white) ????????self.but_list.append(self.color_black) ????????self.but_list.append(self.but5) ????#?鼠标点击调用初始化绘制截图的起点位置 ????def?setxy(self,event,canvas): ????????#清空上一次鼠标事件,并设置截图的起始位置 ????????self.mouEvent?=?None ????????if?(self.but1_stat): ????????????#如果超出截图区域改变起始坐标为截图起始坐标 ????????????if?(event.x?>?self.x?and?event.x?<?self.end_x): ????????????????self.dx?=?event.x ????????????if?(event.y?>?self.y?and?event.y?<?self.end_y): ????????????????self.dy?=?event.y ????????else: ????????????self.x,?self.y=event.x,?event.y ????????????for?but?in?self.but_list: ????????????????but.place_forget() ????????????canvas.delete(self,?'j0') ????????#文本输入操作 ????????if?(self.but_text_stat?and?self.but_type?==?4): ????????????self.p?=?self.p?+?1 ????????????if(?self.p%2?==?1): ????????????????self.text_entry.delete('1.0',?'end') ????????????????self.font?=?tkFont.Font(family='宋体',?size=(self.size+5)*3) ????????????????self.text_entry.config(?font=self.font,fg=self.color,width=4?,height=1) ????????????????self.text_entry.place(x=event.x,?y=event.y) ????????????else: ????????????????canvas.create_text(self.text_entry.winfo_x(),self.text_entry.winfo_y()+15,text=self.text_entry.get(1.0,?END),font=self.font,justify?=?LEFT,fill=self.color,anchor=?W) ????????????????self.text_entry.place_forget() ????????????#?获取所有图形对象 ????????self.ids?=?list(canvas.find_all()) ????def?PreventOutOfBounds(self,eventx,eventy): ????????if?(eventx?<?self.x): ????????????eventx?=?self.x ????????elif?(eventx?>?self.end_x): ????????????eventx?=?self.end_x ????????if?(eventy?<?self.y): ????????????eventy?=?self.y ????????elif?(eventy?>?self.end_y): ????????????eventy?=?self.end_y ????????return?eventx,eventy ????#?鼠标按下左键拖动时调用绘制截图的终点位置 ????def?getxy(self,event,canvas): ????????#?记录上一次的鼠标事件?,?如果按钮有按下不消除选取框矩形??没有按钮按下消除上一个选取矩形 ????????if?(self.but1_stat): ????????????if?self.but_type?==?1: ????????????????#?销毁上一个鼠标暂停点绘制的图形 ????????????????canvas.delete(self,?"j%d"?%(self.i)) ????????????????#?防止图形画出界 ????????????????event.x,?event.y?=?self.PreventOutOfBounds(event.x,event.y) ????????????????canvas.create_rectangle(self.dx,self.dy,event.x,event.y,width=self.size,outline=self.color,tag?=?('j',"j%d"?%(self.i))) ????????????elif?self.but_type?==?2: ????????????????canvas.delete(self,?"j%d"?%?(self.i)) ????????????????event.x,?event.y?=?self.PreventOutOfBounds(event.x,?event.y) ????????????????canvas.create_oval(self.dx,self.dy,event.x,event.y,width=self.size,outline=self.color,tag?=?('j',"j%d"?%(self.i))) ????????????elif?self.but_type?==?3: ????????????????canvas.delete(self,?"j%d"?%?(self.i)) ????????????????event.x,?event.y?=?self.PreventOutOfBounds(event.x,?event.y) ????????????????canvas.create_line(self.dx,self.dy,event.x,event.y,width=self.size,fill=self.color,arrow=tkinter.LAST,tag?=?('j',"j%d"?%(self.i))) ????????else: ????????????#新截图框 ????????????#print("销毁截图矩形") ????????????self.mouEvent?=?event ????????????#?删除上一个矩形 ????????????canvas.delete(self,"j0") ????????????#?绘制新矩形?并设置结束点坐标 ????????????canvas.create_rectangle(self.x,self.y,event.x,event.y,tag?=?('j','j0')) ????????????self.end_x,?self.end_y?=?event.x,?event.y ????????self.ids?=?list(canvas.find_all()) ????#?鼠标释放的时候绘制工具按钮??如果上次释放鼠标左键的上一个鼠标事件是拖动<B1-Motion>?则显示按钮 ????def?setBtn(self,event,winAppSc): ????????#?获取截图区域大小?如果长宽小于5个像素则不显示按钮 ????????w,?h?=?event.x?-?self.x,?event.y?-?self.y ????????if?(self.mouEvent?!=?None?and?w?>?5?and?h?>?5): ????????????x,?y?=?self.x,?event.y ????????????for?but?in?self.but_list: ????????????????but.place(x=x,y=y) ????????????????x=?x+35 ????????#释放鼠标新的图形动作tags标记变更 ????????self.i?=?self.i?+?1 ????def?bu_click(self,event,canvas,but_name): ????????#?按钮按下记录其状态为True ????????self.but1_stat?=?True ????????self.i?=?self.i?+?1 ????????self.but_type?=?but_name ????????#清除文本框 ????????self.text_entry.place_forget() ????#按下鼠标右键取消截图初始化参数 ????def?clear(self,canvas): ????????#print("取消截图") ????????self.i?=?1 ????????self.but1_stat?=?False ????????#销毁所有对象 ????????canvas.delete(ALL) ????????#从新加载IMG对象,此时依旧是之前的截图背景 ????????canvas.create_image(0,?0,?image=self.im,?anchor='nw',?tag=('r',?'r0')) ????????canvas.pack(fill='both',?expand='yes') ????????#?隐藏按钮?删除截图框 ????????for?but?in?self.but_list: ????????????but.place_forget() ????#?设置画笔大小 ????def?sizebut_click(self,size): ????????self.but1_stat?=?True ????????self.size?=?size ????????self.font?=?tkFont.Font(family='宋体',?size=(self.size?+?5)?*?3) ????????self.text_entry.config(font?=?self.font) ????#?设置画笔颜色 ????def?colorbut_click(self,?color): ????????self.but1_stat?=?True ????????self.color?=?color ????????self.text_entry.config(fg=self.color) ????#?退出窗口 ????def?exit_sc(self,scwd): ????????try: ????????????scwd.winAppSc.destroy() ????????except?Exception?as?e: ????????????print(e) ????def?bu_click_text(self,?event,?canvas): ????????#?输入文本框 ????????self.but1_stat?=?True ????????self.but_text_stat?=?True ????????self.but_type?=?4 ????def?entry(self,event): ????????keysym?=??event.keysym ????????if?keysym?==?"Return": ????????????self.row?=?self.row?+?1 ????????????self.text_entry.config(height=self.row) ????????elif?keysym?==?"BackSpace": ????????????text?=?self.text_entry.get("%d.0"?%?(self.row),?"%d.end"?%?(self.row)) ????????????if?len(text)?==?0: ????????????????self.row?=?self.row?-?1 ????????????????if?self.row?<?1: ????????????????????self.row?=?1 ????????????self.text_entry.config(height=self.row) ????????else: ????????????tmp?=?0 ????????????for?i?in?range(1,?self.row?+?1): ????????????????pattern?=?"[\u4e00-\u9fa5]+" ????????????????regex?=?re测试数据pile(pattern) ????????????????text?=?self.text_entry.get("%d.0"?%?(i),?"%d.end"?%?(i)) ????????????????ch?=?regex.findall(text) ????????????????chstr?=?''.join(ch) ????????????????text_len?=?len(text)?+?len(chstr) ????????????????if?text_len?>=?tmp:?tmp?=?text_len ????????????if?(tmp?>=?2):?self.text_entry.config(width=tmp?+?3) ????def?bu_save(self,?event): ????????image?=?pyautogui.screenshot(region=[self.x+1,?self.y+1,?self.end_x-self.x-1,?self.end_y-self.y-1]) ????????save_dir?=?"save" ????????if?not?os.path.exists(save_dir): ????????????os.makedirs(save_dir) ????????t?=?int(time.time()) ????????image.save("%s/%d.jpg"?%(save_dir,t)) ????????#?截图完成销毁窗口 ????????self.winAppSc.destroy() ????def?ctrl_z(self): ????????if?len(self.ids)?>?2: ????????????self.canvas.delete(self.ids[-1]) ????????????self.ids.pop()
截图
源码因为打包了python环境比较大
链接:https://pan.baidu测试数据/s/1hND-HARBPt6mumgnvvUtqA?
提取码:WLWL?
查看更多关于Python Tkiner 写的截图小工具 实现了大部分基础功能的详细内容...
声明:本文来自网络,不代表【好得很程序员自学网】立场,转载请注明出处:http://haodehen.cn/did125910