Python MFC:更新静态文本以响应事件

Python MFC: Updating static text in response to events

我有以下 Python MFC 代码。我有一个列表框,其中填充了一些值,当用户单击这些值时,我希望静态文本控件使用当前选择进行更新。这段代码有两个问题。首先是文本控件中的值仅在我第一次单击列表框时更新。第二个是该值落后于列表框中的实际选定值,大概是因为控件在我的处理程序代码被调用后处理了点击。如果能帮助我解决这些问题,我将不胜感激。

一件奇怪的事情(也许是一个线索)是,当我将鼠标放在 'OK' 按钮上但移开鼠标向上时,静态文本确实会按照我的预期进行更新。

我已经在控件和对话框上尝试了 RedrawWindow()、UpdateWindow()、ShowWindow(),似乎没有任何区别。

import win32con
from pywin.mfc import dialog

IDC_LIST = 9000
IDC_TEXT = 9001

class ChooserDialog(dialog.Dialog):

  def __init__(self):
    DIALOGTEMPLATE = [  
      ["Test", (0, 0, 254, 199), win32con.WS_CAPTION | win32con.DS_MODALFRAME, None, (8, "MS SansSerif")],
      [128, "OK", win32con.IDOK, (197,178,50,14), win32con.BS_PUSHBUTTON | win32con.WS_VISIBLE],
      ["listbox", "List", IDC_LIST, (7,7,177,186), win32con.WS_VISIBLE],
      ["static", "", IDC_TEXT, (197,7,50,160), win32con.WS_CHILD | win32con.WS_VISIBLE]
    ]
    dialog.Dialog.__init__(self, DIALOGTEMPLATE)

  def OnInitDialog(self):
    rc = dialog.Dialog.OnInitDialog(self)
    for i in ["one", "two", "three"]:
      self.GetDlgItem(IDC_LIST).AddString(i)
    self.HookCommand(self.OnNotify, IDC_LIST)
    return rc

  def OnNotify(self, ctrl, action):
    if ctrl == IDC_LIST:
      selected = self.GetDlgItem(IDC_LIST).GetCurSel()
      self.SetDlgItemText(IDC_TEXT, "%d" % selected)
      self.GetDlgItem(IDC_TEXT).RedrawWindow()
    return 1

dia = ChooserDialog()
dia.DoModal()

代码的第一个问题是没有为列表框控件设置 win32con.LBS_NOTIFY 样式。如果未设置,您将不会收到来自 LB 的任何消息。我收到的几条消息是由于对话框中的其他事件造成的。

第二个问题是我使用了 HookCommand(),它会拦截命令,并允许您处理它们。相反,我希望 HookMes​​sage() 仅获取通知。似乎通知在控件更新后被调用,所以这正是我想要的。

根据 MSDN 文档,LBN_SELCHANGE 通知是通过 WM_COMMAND 消息接收的。看来我必须订阅对话框中的所有 WM_COMMAND 消息,然后在我的处理程序中过滤它们。 LBN_SELCHANGE 文档解释了传递的内容,结合 HookMes​​sage() Python 文档,您可以了解如何处理它。

这是工作代码:

    import win32con
    from pywin.mfc import dialog

    IDC_LIST = 9500
    IDC_TEXT = 9501

    class ChooserDialog(dialog.Dialog):

      def __init__(self):
        DIALOGTEMPLATE = [  
          ["Test", (0, 0, 254, 199), win32con.WS_CAPTION | win32con.DS_MODALFRAME, None, (8, "MS SansSerif")],
          [128, "OK", win32con.IDOK, (197,178,50,14), win32con.BS_PUSHBUTTON | win32con.WS_VISIBLE],
          ["listbox", "List", IDC_LIST, (7,7,177,186), win32con.WS_VISIBLE|win32con.LBS_NOTIFY],
          ["static", "", IDC_TEXT, (197,7,50,160), win32con.WS_CHILD | win32con.WS_VISIBLE]
        ]
        dialog.Dialog.__init__(self, DIALOGTEMPLATE)

      def OnInitDialog(self):
        rc = dialog.Dialog.OnInitDialog(self)
        for i in ["one", "two", "three"]:
          self.GetDlgItem(IDC_LIST).AddString(i)
        self.HookMessage(self.OnNotifyCommand, win32con.WM_COMMAND)
        return rc

      def OnNotifyCommand(self, data):
        msg_id = data[1]   # should always be WM_COMMAND
        wParam = data[2]
        lParam = data[3]
        list_id = wParam & 0xffff
        notification_code = (wParam & 0xffff0000) >> 16
        if list_id != IDC_LIST: return    # not our list box.
        if notification_code != win32con.LBN_SELCHANGE: return    # Not a change of selection
        selected = self.GetDlgItem(IDC_LIST).GetCurSel()
        self.SetDlgItemText(IDC_TEXT, "%d"%selected)

    dia = ChooserDialog()
    dia.DoModal()