Win10有一截屏程序,可截全屏和截取屏幕选定区域截屏。如截取屏幕指定区域的图像时,整个屏幕似被雾遮住,在雾下可见屏幕上图像和文字。用鼠标拖动画矩形选择截屏区域,选择部分的雾被去除,当鼠标抬起,所选截图显示到主窗体,雾全部消失。可将图像保存。本文所设计的截屏程序要实现这些功能。先看本文所设计程序的效果图。
图1是程序运行后的主窗体。有4个按钮,标题分别是:定位截屏、截全屏、保存图像和帮助。这是本程序实现的4个功能。拷贝图像是一个重要功能。但要希望将图像粘贴到window系统的其它程序,例如画图程序,必须把图像拷贝到系统的剪贴板,需要调用window系统API,比较复杂,本人怕麻烦,没有加。网上有介绍这方面内容的网页,需要可自己增加。 单击“定位截屏”按钮后,出现的界面如图2。实现具体方法是,首先将主窗体最小化,以免影响截屏(第7条语句)。打开一个非模式窗体(第8条),使窗体半透明(第9条),使窗体无标题栏(第10条),使窗体和屏幕同宽同高(第11-14条)。这样使整个屏幕就似被雾遮住,在雾下可见屏幕上图像和文字。还在右侧中间位置增加了一个关闭按钮(第19条),方便关闭这个非模式窗体,后边将看到,如希望不截屏退出非模式窗体,只能使用这个按钮。为了在窗体画矩形,在此窗体增加Canvas实例(第17条),使该实例和窗体的宽和高同步变化(第18条)。为了使所画矩形内的雾消失,所画矩形的填充色和外轮廓是透明的,因此定义了一个透明灰色(第15-16条)。为拖动画矩形,为鼠标绑定了3个事件函数(第20-22条)。 所谓拖动鼠标画矩形,首先响应鼠标左键单击事件(第26-29条),记住矩形左上角坐标保持不变(第28条),画一个小矩形(第29条);保持鼠标按下并移动,响应鼠标移动事件(第45-47条),矩形左上角坐标保持不变,将矩形右下角坐标变为鼠标当前坐标,消去旧矩形,画新矩形(第47条),随着鼠标移动,看到矩形左上角位置保持不变,矩形形状大小不断变化,矩形内雾消失,使使用者直观看到所选截屏区域,见图3;鼠标抬起,响应鼠标抬起事件(第30-44条),画矩形结束。如截取的图像太小无意义,可能是误操作,删除这个误操作所画矩形,不截屏,否则从所选区域截屏。为了截屏,必须得到所选区域的屏幕坐标系的坐标(第35-38条),然后截屏(第39条)。然后将所截图像在主窗体显示(第40-42条),关闭非模式窗体(第43条),雾消失,使主窗体正常显示(第44条),见图4。 截全屏很好理解,但有一个问题是,如在“截全屏”按钮的事件函数中完成截屏,虽然主窗体已最小化(第49条),主窗体仍然被截取,这是不允许的。首先想到让截屏在另一方法中完成,因此创建一个自定义事件,在“截全屏”按钮的事件函数中发自定义事件,在自定义事件函数中截屏,主窗体仍然被截取。观察程序最小化时,似乎有一个动画效果,不是马上消失,而是慢慢消失。因此现在采用延迟方法。 完整程序如下:
import tkinter as tk
from PIL import ImageGrab,Image,ImageTk
from threading import Timer
import tkinter.filedialog,tkinter.messagebox
def screenGrab():
global f1,cv,TRANSCOLOUR #在Toplevel窗口和主窗口可以互相使用对方的变量和方法。
root.state('icon') #主窗体最小化。icon:最小化,normal:正常显示,zoomed:最大化。或root.iconify()
f1 = tk.Toplevel(root) #用Toplevel类创建独立主窗口的新窗口,非模式窗体
f1.wm_attributes("-alpha", 0.6) #设置窗体透明度(0.0~1.0)
f1.overrideredirect(True) #设置窗体无标题栏
ws = f1.winfo_screenwidth() #屏幕长和宽
hs = f1.winfo_screenheight()
s=str(ws)+'x'+str(hs)+'+0+0'
f1.geometry(s) #Toplevel窗体充满屏幕,整个屏幕似乎被雾遮住,点击屏幕任意处,将使该窗体退出
TRANSCOLOUR = 'gray'
f1.wm_attributes('-transparentcolor', TRANSCOLOUR) #设置灰色为透明颜色
cv = tk.Canvas(f1) #在Toplevel窗体增加Canvas实例,用来画透明矩形
cv.pack(fill=tk.BOTH, expand=tk.Y) #使Canvas实例自动充满Toplevel窗体
tk.Button(cv,text="关闭", command=closeDialog).pack(side='right') #该按钮将出现在屏幕右侧中间位置
cv.bind("",StartMove) #绑定鼠标左键按下事件,为在Toplevel窗体上拖动鼠标画矩形做准备
cv.bind("",StopMove) #绑定鼠标左键松开事件
cv.bind("", OnMotion) #绑定鼠标左键被按下时移动鼠标事件
def closeDialog():
f1.destroy() #关闭对话框
root.state('normal') #使主窗体正常显示
def StartMove(event): #为拖动画矩形做准备
global first_x,first_y,cv
first_x,first_y = event.x,event.y #拖动鼠标画矩形其左上角坐标必须记住,保持不变
cv.create_rectangle(first_x,first_y,event.x+1,event.y+1,fill=TRANSCOLOUR, outline=TRANSCOLOUR,tags=('L'))
def StopMove(event): #鼠标抬起,截取所选择屏幕区域图像
global first_x,first_y,cv,f1,img,p
if abs(first_x-event.x) |