设为首页 收藏本站
查看: 1260|回复: 0

[经验分享] Python天天美味(36)

[复制链接]

尚未签到

发表于 2015-4-19 05:01:28 | 显示全部楼层 |阅读模式
  Spy++是微软出品的用来获取Window窗口信息的一个小工具。实现的原理其实不难,通过调用某些特定的Windows API即可。于是,我打算用Python也实现一个功能简化版本的小工具,取名叫PySpy++。Python中调用Windows API一般使用pywin32这套库,界面库我使用PyQT4。
  
Spy++原理

    Spy++中,最常用的一个功能,就是识别窗口。其中主要需要用到的Windows API有:
  获取当前鼠标位置
  

BOOL GetCursorPos( LPPOINT lpPoint );  
  获取位于指定位置的窗口句柄
  

HWND WindowFromPoint( POINT Point );  
  获取窗口类别
  

int GetClassName( HWND hWnd, LPTSTR lpClassName, int nMaxCount );  
  获取窗口内容或标题
  方法一:
  

int GetWindowText( HWND hWnd, LPTSTR lpString, int nMaxCount );  
  这个API有时候不能取到某些控件的值,因此,使用方法二。
  方法二:
  给窗口发送WM_GETTEXT消息:
  

LRESULT SendMessage( HWND hWnd, UINT Msg, WPARAM  wParam, LPARAM lParam );  
  高亮选中的窗口
  先获取当前窗口的大小,然后画一个矩形框。

DSC0000.gif

BOOL GetWindowRect( HWND hWnd, LPRECT lpRect );
BOOL Rectangle(
    HDC hdc, // handle to DC
    int nLeftRect, // x-coord of upper-left corner of rectangle
    int nTopRect, // y-coord of upper-left corner of rectangle
    int nRightRect, // x-coord of lower-right corner of rectangle
    int nBottomRect // y-coord of lower-right corner of rectangle
);  鼠标移开窗口后,窗口需要恢复原状,需要重新刷新:


BOOL InvalidateRect(
    HWND hWnd, // handle to window
    CONST RECT* lpRect, // rectangle coordinates
    BOOL bErase // erase state
);
BOOL UpdateWindow(
    HWND hWnd // handle to window
);
BOOL RedrawWindow(
    HWND hWnd, // handle to window
    CONST RECT *lprcUpdate, // update rectangle
    HRGN hrgnUpdate, // handle to update region
    UINT flags // array of redraw flags
);  

PyWin32对应的函数
    在Python中调用Windows API,首先下载PyWin32,地址:http://pywin32.sourceforge.net/
  安装完成后,打开帮助文档Python for Windows Documentation,里面有所有需要的东西,随时用来查看。
  常用的API在win32api模块里,界面相关的API在win32gui模块里,API参数中定义的一些常量在win32con模块中。上面的Windows API对应PyWin32中的函数为:



(int, int) = win32gui.GetCursorPos()
int = win32gui.WindowFromPoint(point)
string = win32gui.GetClassName(hwnd)
string = win32gui.GetWindowText(hwnd)
int = win32gui.SendMessage(hwnd, message , wparam , lparam )
(left, top, right, bottom) = win32gui.GetWindowRect(hwnd)
win32gui.Rectangle(hdc, LeftRect, TopRect, RightRect, BottomRect)
win32gui.InvalidateRect(hWnd, Rect, Erase)
win32gui.UpdateWindow(hwnd)
win32gui.RedrawWindow(hWnd, rcUpdate, hrgnUpdate, flags)  

代码实现
    界面库使用PyQT4,参考资料可以从我之前的一篇博客里了解:PyQt4 学习资料汇总
  工具对话框窗口有两个控件,一个是QLabel控件,一个是QTextEdit控件。QLabel控件就是那个用来鼠标按下去后去捕捉窗口,QTextEdit控件用来显示窗口的信息。为了让QTextEdit响应自定义的鼠标事件,我创建了一个自定义QLabel控件SpyLabel,继承自QLabel。
  


class SpyLabel(QtGui.QLabel):
    def __init__(self, parent = None):
        QtGui.QLabel.__init__(self, parent)
        self.parent = parent
        self.spying = False
        self.rectanglePen = win32gui.CreatePen(win32con.PS_SOLID, 3, win32api.RGB(255, 0, 0))
        self.prevWindow = None
        self.setCursor(QtCore.Qt.SizeAllCursor)    SpyLabel中处理鼠标移动事件:


def mouseMoveEvent(self, event):
    if self.spying:
        curX, curY = win32gui.GetCursorPos()
        hwnd = win32gui.WindowFromPoint((curX, curY))
        if self.checkWindowValidity(hwnd):               
            if self.prevWindow:
                self.refreshWindow(self.prevWindow)
            self.prevWindow = hwnd
            self.highlightWindow(hwnd)
            self.displayWindowInformation(hwnd)  鼠标松开事件:


def mouseReleaseEvent(self, event):
    if self.spying:
        if self.prevWindow:
            self.refreshWindow(self.prevWindow)
        win32gui.ReleaseCapture()
        self.spying = False  高亮窗口的函数:


def highlightWindow(self, hwnd):
    left, top, right, bottom = win32gui.GetWindowRect(hwnd)
    windowDc = win32gui.GetWindowDC(hwnd)
    if windowDc:
        prevPen = win32gui.SelectObject(windowDc, self.rectanglePen)
        prevBrush = win32gui.SelectObject(windowDc, win32gui.GetStockObject(win32con.HOLLOW_BRUSH))
        win32gui.Rectangle(windowDc, 0, 0, right - left, bottom - top)
        win32gui.SelectObject(windowDc, prevPen)
        win32gui.SelectObject(windowDc, prevBrush)
        win32gui.ReleaseDC(hwnd, windowDc)  刷新窗口的函数:
  

def refreshWindow(self, hwnd):
    win32gui.InvalidateRect(hwnd, None, True)
    win32gui.UpdateWindow(hwnd)
    win32gui.RedrawWindow(hwnd,
        None,
        None,  
        win32con.RDW_FRAME|
            win32con.RDW_INVALIDATE|
            win32con.RDW_UPDATENOW|
            win32con.RDW_ALLCHILDREN)    显示窗口信息:



def displayWindowInformation(self, hwnd):
    className = win32gui.GetClassName(hwnd)
    buf_size = 1 + win32gui.SendMessage(hwnd, win32con.WM_GETTEXTLENGTH, 0, 0)
    buffer = win32gui.PyMakeBuffer(buf_size)
    win32gui.SendMessage(hwnd, win32con.WM_GETTEXT, buf_size, buffer)
    windowText = buffer[:buf_size]
    try:
        windowText = unicode(windowText, 'gbk')
    except:
        pass
    message = ['Handle:\t' + str(hwnd),
               'Class Name:\t' + className,
               'Window Text:\t' + windowText]
    self.output('\r\n'.join(message))  注意到上面SendMessage函数,需要传入一个分配的缓冲区,用于获取返回的内容。这里使用了:


buffer = win32gui.PyMakeBuffer(buf_size)    由于返回的内容中可能有中文,因此使用unicode(windowText, 'gbk')进行一下转换。   

  
演示

   DSC0001.png
DSC0002.png
  
  二进制下载:
  http://pyspyplusplus.googlecode.com/files/pyspy++.exe
  源代码:
  http://code.google.com/p/pyspyplusplus/
  
  
Python  天天美味系列(总)
Python  天天美味(31) - python数据结构与算法之插入排序    Python  天天美味(32) - python数据结构与算法之堆排序
  Python  天天美味(33) - 五分钟理解元类(Metaclasses)[转]
Python  天天美味(34) - Decorators详解   Python  天天美味(35) - 细品lambda

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-58423-1-1.html 上篇帖子: Python基础06 循环 下篇帖子: Python自省(反射)指南
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表