[源码]Python Tkiner 写的截图小工具 实现了大部分基础功能

  1. 最近在写一些小工具,因为是给别人用的需要界面,刚开始使用pyQT5  功能强大,但是打包后一个小工具 就有几十兆 有点蛋疼而且还很消耗资源;后面改用TK,TK明显简洁很多,功能同样也若很多!

  2. 因为有截图需求,就抽空写了这个工具,全当练习。过程当中遇到过好多蛋疼的事情,功能基本实现后发出来给大家分享一下,我个人还是比较喜欢python这门语言的!

  3. 实现思路:

    3.1.新建一个最小化窗口,利用线程启动监听"ctrl+a"启动截图窗口

    3.2.截图窗口初始化时利用  pyautogui.screenshot 截取全屏(类似PRTSC)作为子窗口的背景(在这搞了好久,后面没办法只有利用canvas设置背景),子窗口最大化取消菜单栏

    3.3.在主窗口上的canvas上用绑定鼠标事件,根据鼠标选取截图范围,和鼠标操作相关功能

    3.4.保存功能是根据截图范围重新截图生成文件保存

  4. 代码

  5. main_UI.py
  6. 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()
  7. Sc_Tool/Sc_Win.py
  8. 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.compile(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 Tkiner 写的截图小工具 实现了大部分基础功能

  • 源码因为打包了python环境比较大

  • 链接:https://pan.baidu.com/s/1hND-HARBPt6mumgnvvUtqA 

  • 提取码:WLWL 


上一篇:一分*最好用的邀请码06680838


下一篇:*每天轻松赚钱的高级邀请码93998000