恋丶你的语 发表于 2023-9-25 15:31

方便快捷的桌面悬浮截图工具

本帖最后由 恋丶你的语 于 2023-9-25 15:41 编辑

最近正在学习Python,于是自己尝试着弄了一个:桌面悬浮截图工具。
亮点一:随时悬浮在桌面,方便对账
               这款截图工具具有独特的悬浮窗口设计,可以随时悬浮在您的桌面上。无论您是在浏览网页、编辑文档还是进行账目对账,只需轻轻点击,即可快速选择并截取所需区域。再也不用频繁切换窗口,工作更加高效!
亮点二:自定义截图区域,精确捕捉画面
               利用该工具,您可以自定义截图区域,精确捕捉所需的屏幕画面。通过简单的鼠标拖拽,即可快速框选所需区域,并即时展示截图的宽度和高度,让您轻松把握画面尺寸。
亮点三:丰富的功能,简单易用
该截图工具提供了多种功能,方便您在截图后进行进一步操作:

[*]保存截图:支持将截图保存为PNG格式的文件,并可自定义保存路径,方便后续查阅和使用。
[*]复制到剪贴板:一键将截图复制到剪贴板,随时粘贴到其他应用程序中,方便快捷。
[*]拖拽调整位置:截图后,您可以通过拖拽来调整截图窗口的位置,使其更符合您的工作需求。


不足一:还没有弄托盘图标
不足二:没有设置快捷方式截图
不足三:打包后程序体积很大,本来目标是状态10M以内,超过了所以不打包成品程序了。


import tkinter as tk
import io
from tkinter import Menu, messagebox, filedialog
from PIL import Image, ImageGrab, ImageTk
import pyperclip
import win32clipboard

class ScreenshotApp:    # 定义ScreenshotApp类
    def __init__(self):    # 初始化函数
      self.root = tk.Tk()
      self.root.attributes('-alpha', 0.3)
      self.root.attributes('-fullscreen', True)
      self.root.iconbitmap("icon.ico")
      self.root.title("截图图")
      self.root.bind("<Escape>", lambda event: self.on_escape())    # 绑定Esc键触发on_escape()函数

      self.x1, self.y1, self.x2, self.y2 = 0, 0, 0, 0    # 初始化坐标变量
      self.rect = None    # 初始化矩形对象
      self.text = None    # 初始化文本对象

      self.canvas = tk.Canvas(self.root, cursor='cross')    # 创建画布对象
      self.canvas.pack(fill='both', expand=True)    # 将画布填充窗口并展开

      self.canvas.bind('<ButtonPress-1>', self.on_mouse_down)    # 绑定鼠标左键按下事件
      self.canvas.bind('<B1-Motion>', self.on_mouse_move)    # 绑定鼠标左键拖动事件
      self.canvas.bind('<ButtonRelease-1>', self.on_mouse_up)    # 绑定鼠标左键释放事件
      
    def on_escape(self):    # 当按下Esc键时触发的函数
      exit()

    def run(self):    # 运行应用程序的函数
      self.root.mainloop()

    def on_mouse_down(self, event):    # 当鼠标左键按下时触发的函数
      self.x1, self.y1 = event.x, event.y
      self.rect = self.canvas.create_rectangle(self.x1, self.y1, self.x1, self.y1, outline='red')
      self.text = self.canvas.create_text(self.x1 + 5, self.y1 + 5, text='0x0', anchor='nw')

    def on_mouse_move(self, event):    # 当鼠标拖动时触发的函数
      self.x2, self.y2 = event.x, event.y
      self.canvas.coords(self.rect, self.x1, self.y1, self.x2, self.y2)
      width = abs(self.x2 - self.x1)    # 计算宽度
      height = abs(self.y2 - self.y1)    # 计算高度
      self.canvas.itemconfig(self.text, text=f'{width}x{height}')

    def on_mouse_up(self, event):    # 当鼠标左键释放时触发的函数
      self.x2, self.y2 = event.x, event.y
      self.canvas.coords(self.rect, self.x1, self.y1, self.x2, self.y2)
      self.capture_screenshot()
      self.root.quit()

    def capture_screenshot(self):    # 截图函数
      self.root.withdraw()

      left = min(self.x1, self.x2)
      top = min(self.y1, self.y2)
      right = max(self.x1, self.x2)
      bottom = max(self.y1, self.y2)

      image = ImageGrab.grab(bbox=(left, top, right, bottom))    # 截取屏幕上指定区域的图像
      self.create_new_window(image)    # 创建新窗口并显示截图

    def create_new_window(self, image):    # 创建新窗口并显示截图的函数
      new_window = tk.Toplevel(self.root)
      new_window.title("截图图")

      if self.x2 >= self.x1 and self.y2 >= self.y1:    # 如果从左上到右下拖动鼠标
            new_window.geometry(f"{image.width}x{image.height}+{self.x1}+{self.y1}")    # 设置窗口的宽度、高度和位置
      elif self.x2 >= self.x1 and self.y2 <= self.y1:
            new_window.geometry(f"{image.width}x{image.height}+{self.x1}+{self.y2}")
      elif self.x2 <= self.x1 and self.y2 <= self.y1:
            new_window.geometry(f"{image.width}x{image.height}+{self.x2}+{self.y2}")
      elif self.x2 <= self.x1 and self.y2 >= self.y1:
            new_window.geometry(f"{image.width}x{image.height}+{self.x2}+{self.y1}")

      image_tk = ImageTk.PhotoImage(image)    # 创建用于显示图片的PhotoImage对象
      label = tk.Label(new_window, image=image_tk)    # 创建标签对象并显示图片
      label.image = image_tk    # 保存图片对象的引用
      label.pack()    # 将标签添加到窗口中

      new_window.bind("<Button-1>", lambda event: self.start_drag(event, new_window))    # 绑定鼠标左键点击事件以触发拖拽
      label.bind('<B1-Motion>', lambda event: self.on_label_drag(event, new_window))    # 绑定标签的鼠标左键拖动事件

      new_window.overrideredirect(True)
      new_window.wm_attributes('-topmost', True)    # 将窗口置于最顶层
      new_window.configure(borderwidth=1, relief='solid')

      menu = Menu(new_window, tearoff=0)    # 创建菜单对象
      menu.add_command(label="保存", command=lambda: self.save_screenshot(image))    # 添加“保存”菜单项,并绑定保存截图函数
      menu.add_command(label="复制", command=lambda: self.copy_screenshot_to_clipboard(image))    # 添加“复制”菜单项,并绑定复制截图到剪贴板函数
      menu.add_separator()    # 添加分隔线
      #menu.add_command(label="取消", command=new_window.destroy)    # 添加“取消”菜单项,并绑定关闭窗口函数
      menu.add_command(label="取消", command=exit)    # 添加“取消”菜单项,并绑定退出程序函数
      label.bind('<Button-3>', lambda event: menu.post(event.x_root, event.y_root))    # 绑定标签的鼠标右键点击事件以显示菜单

      new_window.mainloop()    # 进入新窗口的主事件循环

    def save_screenshot(self, image):    # 保存截图函数
      filename = filedialog.asksaveasfilename(defaultextension=".png",
                                                filetypes=(("PNG files", "*.png"), ("All files", "*.*")))
      if filename:
            try:
                image.save(filename, "PNG")
                messagebox.showinfo("保存成功", "截图已保存。")
            except Exception as e:
                messagebox.showerror("保存失败", f"保存截图时出现错误:{str(e)}")

    def copy_screenshot_to_clipboard(self, image):    # 复制截图到剪贴板函数
      image = image.convert("RGB")

      with io.BytesIO() as output:
            try:
                image.save(output, format="BMP")
                data = output.getvalue()
                win32clipboard.OpenClipboard()
                win32clipboard.EmptyClipboard()
                win32clipboard.SetClipboardData(win32clipboard.CF_DIB, data)
                win32clipboard.CloseClipboard()
                messagebox.showinfo("复制成功", "截图已复制到剪贴板。")
            except Exception as e:
                messagebox.showerror("复制失败", f"复制到剪贴板时出现错误:{str(e)}")

    def start_drag(self, event, new_window):    # 开始拖拽函数
      new_window.drag_data = {}
      new_window.drag_data["x"] = event.x
      new_window.drag_data["y"] = event.y

    def on_label_drag(self, event, new_window):    # 标签拖拽函数
      dx = event.x - new_window.drag_data["x"]
      dy = event.y - new_window.drag_data["y"]
      new_x = new_window.winfo_x() + dx
      new_y = new_window.winfo_y() + dy
      new_window.geometry(f"+{new_x}+{new_y}")    # 根据位移更新窗口位置

if __name__ == "__main__":
    app = ScreenshotApp()    # 创建ScreenshotApp对象
    app.run()    # 运行截图应用程序

# 调用截图功能函数
app = ScreenshotApp()
app.run()


感觉逻辑有点乱,想了解有什么方法可以减少打包后体积。
打包的源码及图标:https://tars.lanzoue.com/iCpnV19v81of密码:3bew

超级黄金多拉 发表于 2023-9-25 17:57

感谢楼主分享

blindcat 发表于 2023-9-25 18:15

支持下楼主原创

REXLEE95 发表于 2023-9-25 18:23

pyinstaller打包,体积是挺大的,你可以试试创建一个干净的虚拟环境,只安装必须要的库,再进行打包。本地的库已经安装了许多第三方所以体积很大吧

moruye 发表于 2023-9-25 21:43

烟筱禹 发表于 2023-9-29 23:02

感谢楼主无私分享
页: [1]
查看完整版本: 方便快捷的桌面悬浮截图工具