ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

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

2021-05-16 17:51:20  阅读:127  来源: 互联网

标签:canvas Tkiner Python text self None but 源码 event


  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()
  • 截图

    image.png

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

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

  • 提取码:WLWL 


标签:canvas,Tkiner,Python,text,self,None,but,源码,event
来源: https://blog.51cto.com/u_13466287/2779414

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有