如何利用Python和win32编程避免重复性体力劳动(二)——菜单操作:GetMenu,GetSubMenu,GetMenuItemID以及wParam的HIWORD&LOWORD

本博客正逐步迁移至OrangeCube四次元

请移步至这里以获得更加的排版和阅读体验,谢谢您


Part 2:菜单操作

有了句柄,我们就可以操作FaceGen了!嗯,要先打开文件,File→Open,然后再File→Save Image(很悲剧,Save Image没有快捷键,所以不得不进行菜单操作)。现在我们有了FindWindow和FindWindowEx,要怎么操作菜单呢?

哦,抱歉,靠他俩还做不到。

窗口的菜单就像窗口的标题栏一样,是窗口自身的一部分,不是其他窗体控件,也就没有办法用FindWindow和FindWindowEx返回句柄。所以要对菜单进行操作的话,我们需要新的函数,也就是GetMenu,GetSubMenu和GetMenuItemID,它们也都属于win32gui模块。怎么用呢,结合下图来说:


  • GetMenu(hwnd)
    • 描述:获取窗口的菜单句柄。
    • 参数:
      • hwnd:整型,需要获取菜单的窗口的句柄。
    • 说明:获取的是插图中黄色的部分。
  • GetSubMenu(hMenu, nPos)
    • 描述:获取菜单的下拉菜单或者子菜单。
    • 参数:
      • hMenu:整型,菜单的句柄,从GetMenu获得。
      • nPos:整型,下拉菜单或子菜单的的索引,从0算起。
    • 说明:这个可以获取插图中蓝色的部分z;如描述所述,这个不仅可以获取本例中的下拉菜单,还可以获取子菜单。
  • GetMenuItemID(hMenu, nPos)
    • 描述:获取菜单中特定项目的标识符。
    • 参数:
      • hMenu:整型,包含所需菜单项的菜单句柄,从GetSubMenu获得。
      • nPos:整型,菜单项的索引,从0算起。
    • 说明:这个获取的就是红色区域中的项目啦,注意,分隔符是被编入索引的,所以Open的索引是2而非1,而Exit的索引是9而非6。

找到这个菜单项的标识符有什么用呢?找到以后我们就可以告诉应用程序:我们要执行这个菜单项的命令!怎么告诉呢?这就要涉及消息机制了,我们要给应用程序发个消息,让它执行所需菜单项的命令。假设之前获取的Open的标识符是open_ID,那么只需要这样:

win32gui.PostMessage(self.Mhandle, win32con.WM_COMMAND, open_ID, 0)

就会有一个打开文件的对话框出现啦。

解释一下:

  • PostMessage(hWnd, Msg, wParam, lParam)
    • 描述:在消息队列中加入为指定的窗体加入一条消息,并马上返回,不等待线程对消息的处理。
    • 参数:
      • hWnd:整型,接收消息的窗体句柄
      • Msg:整型,要发送的消息,这些消息都是windows预先定义好的,可以参见系统定义消息(System-Defined Messages))
      • wParam:整型,消息的wParam参数
      • lParam:整型,消息的lParam参数
    • 说明:简单说,就是给指定程序发一个消息,这些消息都用整型编好号,作为windows的常量可以查询的。在这里,我们用的就是win32con这个库里定义的WM_COMMAND这个消息,具体的wParam和lParam是根据消息的不同而不同的。具体请根据MSDN查阅。

关于wParam的low word和high word:

    

查阅MSDN的消息时,会发现有的wParam定义了low word和high word,这是什么呢?wParam的定义是32位整型,high word就是他的31至16位,low word是它的15至0位,如图。当参数超过两个,wParam和lParam不够用时,可以将wParam就给拆成两个int16来使用。这种时候在python里记得用把HIWORD的常数向左移16位,再加LOWORD,即wParam = HIWORD<<16+LOWORD。

更新一下我们定义的类,把菜单添加进去:

class FaceGenWindow(object):
    def __init__(self, fgFilePath=None):
        self.Mhandle = win32gui.FindWindow("FaceGenMainWinClass", None)
        self.menu = win32gui.GetMenu(self.Mhandle)
        self.menu = win32gui.GetSubMenu(self.menu, 0)
        print "FaceGen initialization compeleted"


    # 然后定义一个菜单操作的方法:


    def menu_command(self, command):
        """
        菜单操作
        返回弹出的打开或保存的对话框的句柄 dig_handle
        返回确定按钮的句柄 confBTN_handle
        """
        command_dict = {  # [目录的编号, 打开的窗口名]
            "open": [2, u"打开"],
            "save_to_image": [5, u"另存为"],
        }
        cmd_ID = win32gui.GetMenuItemID(self.menu, command_dict[command][0])
        win32gui.PostMessage(self.Mhandle, win32con.WM_COMMAND, cmd_ID, 0)
        for i in range(10):
            if win32gui.FindWindow(None, command_dict[command][1]): 
                break  # 如果找到了打开或者另存为的对话框,就跳出循环
            else:
                win32api.Sleep(200)  # 利用这个函数等待200ms,就不需要再额外导入time模块了
        dig_handle = win32gui.FindWindow(None, command_dict[command][1])
        confBTN_handle = win32gui.FindWindowEx(dig_handle, 0, "Button", None)
        return dig_handle, confBTN_handle

在这里顺便返回了弹出来的对话框的句柄和确定按钮的句柄,后面操作会用到。

猜你喜欢

转载自blog.csdn.net/seele52/article/details/17542265