如何利用Python和win32编程避免重复性体力劳动(四)——下拉列表操作:CB_SETCURSEL、CBN_SELENDOK和CBN_SELCHANGE

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

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


Part 4:控件操作B

至于另存为图片,情况要稍微复杂一点,因为另存为图片的默认选项是BMP,特别不巧,我使用的FaceGen版本保存为BMP有BUG,不能成功保存,所以我们除了定位保存文件的路径以外,还需要对文件类型的下拉组合框(ComboBox进)行操作:

我们假设我们找到了组合框的句柄为CB_handle,我们可以用CB_SETCURSEL消息来更改当前的选项:

  • CB_SETCURSEL 消息
    • 描述:
    • 参数:
      • wParam:以0起始的待选选项的索引;如果该值为-1,将从组合框列表中删除当前选项,并使当前选项为空
      • lParam:未使用。
    • 返回值:
      • 更改选择成功将返回所设置选项的索引号。

只要给组合框发一个CB_SETCURSEL消息,你就会发现下拉列表的选项已经改变了。

这时,只要你点保存,你就会发现,这保存的跟之前的一样啊!根本没有变!

问题在哪里?

我们用鼠标或者键盘操作一下,是没有问题的,一旦更保存类型,保存窗口里的预览也会随之变化。所以,除了CB_SETCURSEL以外,一定还缺了点儿什么。

于是,我们可以调用Spy++的消息机制查看一下手动操作时,我们的下拉组合框发生的事情,好像除了渲染和点击,没有什么特别值得注意的。

那再看看父窗体呢?好像有点儿不太一样的东西:

  • CBN_SELENDOK 通知(notification code)
    • 描述:当用户选择了有效的列表项时发送,提示父窗体处理用户的选择。父窗体通过WM_COMMAND消息接收这个通知。
    • 参数:(作为WM_COMMAND的参数)
      • wParam:LOWORD为组合框的ID. HIWORD为CBN_SELENDOK的值。
      • lParam:组合框的句柄。
  • CBN_SELCHANGE 通知(notification code)
    • 描述:当用户更改了列表项的选择时发送,不论用户是通过鼠标选择或是通过方向键选择都会发送此通知。父窗体通过WM_COMMAND消息接收这个通知。
    • 参数:(作为WM_COMMAND的参数)
      • wParam:LOWORD为组合框的ID. HIWORD为CBN_SELCHANGE的值。
      • lParam:组合框的句柄。
  • 说明:他们是WM_COMMAND消息wParam的high word(wParam的16-31位,详情参见Part 2)的常数之一,在Python中可以用位移操作将其移动到高位上(a<<16),再用加法加上低位的内容。

继续查MSDN的资料,我们发现,对于一个有效的选择,一定会发送这两个通知,发送完CBNSELENDOK以后马上发送CBNSELCHANGE。而且,使用CBSETCURSEL消息时,CBNSELCHANGE通知是不会被送达的!

问题就在这里,加上这两个消息之后,就能正常操作下拉菜单了。完整函数如下

    def save_to_image(self, filePath, format="jpg"):
        format_dict = {
            "bmp": 0,  # Facegen的Bug导致无法保存bmp
            "jpg": 1,
            "tga": 2,
            "tif": 3,
        }
        Mhandle, confirmBTN_handle = self.menu_command('save_to_image')
        mhandle = find_subHandle(Mhandle, [("DUIViewWndClassName", 0), ("DirectUIHWND", 0)])
        EDIT_handle = find_subHandle(mhandle, [("FloatNotifySink", 0), ("ComboBox", 0), ("Edit", 0)])  # 定位保存地址句柄
        PCB_handle = find_subHandle(mhandle, [("FloatNotifySink", 1)])  # 定位下拉菜单父窗体句柄
        CB_handle = find_subHandle(PCB_handle, [("ComboBox", 0)])  # 定位下拉菜单窗体句柄
        wait_and_assert(EDIT_handle, find_subHandle(mhandle, [("FloatNotifySink", 0), ("ComboBox", 0), ("Edit", 0)]))
        # 以下3行皆为ComboBox的list中选择格式必要的Message操作
        if win32api.SendMessage(CB_handle, win32con.CB_SETCURSEL, format_dict[format], 0) == format_dict[format]:
            win32api.SendMessage(PCB_handle, win32con.WM_COMMAND, 0x90000, CB_handle)
            win32api.SendMessage(PCB_handle, win32con.WM_COMMAND, 0x10000, CB_handle)
        else:
            raise Exception("Change saving type failed")
        # 填入保存地址,确认
        if win32api.SendMessage(EDIT_handle, win32con.WM_SETTEXT, 0, os.path.abspath(filePath).encode('gbk')) == 1:
            return win32api.SendMessage(Mhandle, win32con.WM_COMMAND, 1, confirmBTN_handle)
        raise Exception("Set file opening path failed")

猜你喜欢

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