pywin32在画图中绘制图形
获取画图的窗口句柄
-
由于画图程序的特殊性,与之前的浏览器窗口不同,其在主窗口下还有多个子窗口,我通过spy++软件找到了绘图区窗口的信息。
-
可以看出这个绘图子窗口的caption为空,只有一个class(这个值也是会变的),尝试了几次使用FindWindow()函数并没有什么用,直接将handle值赋值后下次开机有是不同的句柄号。于是我们只能通过找画图这个父句柄来获取绘图子窗口的句柄
-
因为绘图子窗口句柄会变化所以我们需要找到不变化的它的上一级即class为’MSPaintView’的窗口再获取到它子窗口句柄组的第一个。
''' 获得parent的所有子窗口句柄 返回子窗口句柄列表 ''' def get_child_windows(parent): if not parent: return hwndChildList = [] win32gui.EnumChildWindows(parent, lambda hwnd, param: param.append(hwnd), hwndChildList) return hwndChildList hwnd0 = win32gui.FindWindow( None,"无标题 - 画图") #获取画图窗口句柄 for childh in get_child_windows(hwnd0): clsname = win32gui.GetClassName(childh) if clsname == 'MSPaintView': hwnd = get_child_windows(childh)[0] break #获取绘图区子窗口句柄
-
这样我们就获取到了绘图区的窗口句柄了,下面就是让它画图,我们拿鼠标画图的时候按住左键,然后再拖动鼠标,这里要考虑到我们绘制图形的连续性比较复杂,这里就简单地用快速画点的方式去绘制吧。
点击事件
-
鼠标点击大致有两种方式.一种就是真实地移动你的物理鼠标即模拟你使用鼠标移动和点击等等行为,第二种是向窗口发送鼠标事件,显然我们会更喜欢后者。(只是懒得找移动鼠标代码了)
def clickLeftCur(mX, mY): #在(mX,mY)处单击一哈 win32gui.PostMessage(hwnd, win32con.WM_LBUTTONDOWN, 0, mX + mY * 65536)#左键按下 time.sleep(0.00000001) #象征性地延时100ns不过对于电脑来说还是挺长的呢 win32gui.PostMessage(hwnd, win32con.WM_LBUTTONUP, 0, mX + mY * 65536)#左键起来
绘制图形
-
现在万事具备了,我们来绘制一个圆吧,
R=100 #半径 cX=300 cY=300 #圆心坐标 for i in range(1000): #将圆分为1000个点 clickLeftCur(int(cX+R*math.sin(2*math.pi*(i/1000))),int(cY+R*math.cos(2*math.pi*(i/1000)))) cv2.imshow('paint',window_capture(hwnd))#再用上次学的显示一下图片
完整代码
import win32gui, win32ui, win32con, win32api
import cv2
import numpy as np
import math
import time
def clickLeftCur(mX, mY): #单击
win32gui.PostMessage(hwnd, win32con.WM_LBUTTONDOWN, 0, mX + mY * 65536)
time.sleep(0.000000001)
win32gui.PostMessage(hwnd, win32con.WM_LBUTTONUP, 0, mX + mY * 65536)
def window_capture(hwnd):
hwndDC = win32gui.GetWindowDC(hwnd)
# 根据窗口句柄获取窗口的设备上下文DC(Divice Context)
mfcDC = win32ui.CreateDCFromHandle(hwndDC)
# 根据窗口的DC获取mfcDC
saveDC = mfcDC.CreateCompatibleDC()
# mfcDC创建可兼容的DC
saveBitMap = win32ui.CreateBitmap()
# 创建bigmap准备保存图片
rctA = win32gui.GetWindowRect(hwnd)
w = rctA[2] - rctA[0]
h = rctA[3] - rctA[1]
#获取图片大小
# 截取从左上角(0,0)长宽为(w,h)的图片
saveBitMap.CreateCompatibleBitmap(mfcDC, w, h)
# 为bitmap开辟空间
saveDC.SelectObject(saveBitMap)
# 高度saveDC,将截图保存到saveBitmap中
saveDC.BitBlt((0, 0), (w, h), mfcDC, (0, 0), win32con.SRCCOPY)
signedIntsArray = saveBitMap.GetBitmapBits(True)
img = np.frombuffer(signedIntsArray, dtype="uint8")
img.shape = (h, w, 4)
#bit图转mat图
win32gui.DeleteObject(saveBitMap.GetHandle())
mfcDC.DeleteDC()
saveDC.DeleteDC()
#释放内存
return cv2.cvtColor(img, cv2.COLOR_RGBA2RGB) #转为RGB图返回
def get_child_windows(parent):
'''
获得parent的所有子窗口句柄
返回子窗口句柄列表
'''
if not parent:
return
hwndChildList = []
win32gui.EnumChildWindows(parent, lambda hwnd, param: param.append(hwnd), hwndChildList)
return hwndChildList
hwnd0 = win32gui.FindWindow( None,"无标题 - 画图") #获取画图窗口句柄
for childh in get_child_windows(hwnd0):
clsname = win32gui.GetClassName(childh)
if clsname == 'MSPaintView':
hwnd = get_child_windows(childh)[0]
break
#获取绘图区子窗口句柄
R=100
cX=300
cY=300
for i in range(1000):
clickLeftCur(int(cX+R*math.sin(2*math.pi*(i/1000))),int(cY+R*math.cos(2*math.pi*(i/1000))))
cv2.imshow('paint',window_capture(hwnd))