【问题标题】:How to send a CBN_SELCHANGE message when using CB_SETCURSEL?使用 CB_SETCURSEL 时如何发送 CBN_SELCHANGE 消息?
【发布时间】:2009-09-23 19:42:11
【问题描述】:

使用 CB_SETCURSEL 消息时,不会发送 CBN_SELCHANGE 消息。

如何通知控件选择已更改?

附言

我在Sexchange 网站上发现了一个非常的黑客:

SendMessage( hwnd, 0x014F/*CB_SHOWDROPDOWN*/, 1, 0 );
SendMessage( hwnd, 0x014E/*CB_SETCURSEL*/, ItemIndex, 0 );
SendMessage( hwnd, 0x0201/*WM_LBUTTONDOWN*/, 0, -1 );
SendMessage( hwnd, 0x0202/*WM_LBUTTONUP*/, 0, -1 );

暂时可以...不是真的。

附言2

为了解决我的问题,我会在 cmets 中遵循 Ken 的建议。

【问题讨论】:

    标签: c++ winapi controls combobox message


    【解决方案1】:

    这可能会帮助下一个人:

    [DllImport("User32.dll", EntryPoint = "SendMessage")]
    private static extern int SendMessage(IntPtr hwnd, int msg, int wParam, int lParam);
    
    [DllImport("user32.dll", EntryPoint = "GetWindowLong")]
    private static extern IntPtr GetWindowLongPtr32(IntPtr hWnd, int nIndex);
    
    [DllImport("user32.dll", EntryPoint = "GetWindowLongPtr")]
    private static extern IntPtr GetWindowLongPtr64(IntPtr hWnd, int nIndex);
    
    public static IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex)
    {
       if (IntPtr.Size == 8)
            return GetWindowLongPtr64(hWnd, nIndex);
       else
            return GetWindowLongPtr32(hWnd, nIndex);
    }
    
    static int MakeWParam(int loWord, int hiWord)
    {
         return (loWord & 0xFFFF) + ((hiWord & 0xFFFF) << 16);
    }
    
    public const int CB_SETCURSEL = 0x014E;
    public const int CBN_SELCHANGE = 0x0001;
    
    public enum GWL
    {
                GWL_WNDPROC = (-4),
                GWL_HINSTANCE = (-6),
                GWL_HWNDPARENT = (-8),
                GWL_STYLE = (-16),
                GWL_EXSTYLE = (-20),
                GWL_USERDATA = (-21),
                GWL_ID = (-12)
    }
    
    public static IntPtr Hwnd_select_control_parent = IntPtr.Zero;
    public static IntPtr Hwnd_select_control = IntPtr.Zero;
    
    static void changeit()
    
    {
    
    // Google WinSpy for tips on how to figure out how to get window handles from known ctrl_id
    
       Hwnd_select_control = 14298; // or whatever the handle of the combo box is
    
    // Get the parent of the selectbox control
    
       Hwnd_select_control_parent = GetWindowLongPtr(service_window_control, (int)GWL.GWL_HWNDPARENT);
    
    // Get the control id of the selectbox if you don't already have it
    
       IntPtr nID = GetWindowLongPtr(Hwnd_select_control, (int)GWL.GWL_ID);
       int ctrl_id = nID.ToInt32();
    
    // Change the combo box to the value "My Value"
    
       SendMessage(Hwnd_select_control, CB_SETCURSEL, "My Value", null);
    
    // low ID is the ctrl_id of the combo box, high id is CBN_SELCHANGE
    
       int send_cbn_selchange = MakeWParam(ctrl_id, CBN_SELCHANGE); 
    
    // Send the WM_COMMAND to the parent, not the control itself
    
       SendMessage(Hwnd_serviceselect_control_parent, 0x111 /* WM_COMMAND */, send_cbn_selchange, Hwnd_serviceselect_control.ToInt32()); 
    
    
    }
    

    【讨论】:

    • 它确实对下一个人有很大帮助。我仍然不遵循 MakeWParam 方法中 loWord 和 hiWords 背后的理论,但它就像魔术一样工作!谢谢
    【解决方案2】:

    除非用户更改了选择,否则不应使用 CBN_SELCHANGE。

    您没有指明您使用的是什么语言;如果您这样做,它将更容易为您提供解决方法。

    在 Delphi 中,OnChange() 将与组合框相关联,您只需直接调用事件方法:

    // Send the CB_SETCURSEL message to the combobox
    PostMessage(ComboBox1.Handle, CB_SETCURSEL, Whatever, WhateverElse);
    
    // Directly call the OnChange() handler, which is the equivalent to CBN_SELCHANGE
    ComboBox1Change(nil);
    

    【讨论】:

    • 您是在使用 MFC 之类的 GUI 库,还是直接调用 Win32?如果是直接 Win32,请在消息处理程序循环中使用调试器。在您的代码上设置它以处理 CBN_SELCHANGE,并查看当您更改组合框中的项目时作为 WPARAM 和 LPARAM 传入的值(作为普通用户)。然后,您可以使用与我在上面显示的基本相同的 Delphi PostMessage() 代码,在发布 CBN_SETCURSEL 消息后立即以编程方式在您的代码中传递 WPARAM 和 LPARAM 的适当值。如果你使用 MFC,我无能为力(我很同情你)。
    • 我没有使用 MFC,但我在 MFC 中找到了很多代码 :( (stackoverflow.com/questions/59280/…)。
    • 正如我所说,你有我的同情。 我上一个建议的替代方法是使用您在事件处理程序中调用的单独函数来响应 CBN_SELCHANGE;而不是在发布 CBN_SETCURSEL 之后自己发布 CBN_SELCHANGE,然后您可以直接调用该函数。
    • 是的,我想我将重构我的代码,以便在发送 CB_SETCURSEL 消息和用户进行选择时具有相同的操作。感谢您提供有用的答案。
    【解决方案3】:

    我刚刚发现将这些 SendMessages 调用到 Combobox 两次有效...我知道这并不完美,但它对我有用。 (用VB6编写)

        For looper = 1 To 2
    
            bVal = SendMessage(inHandle, COMBO.CB_SHOWDROPDOWN, True, 0)
            count = SendMessage(inHandle, COMBO.CB_SETCURSEL, 1, 0)
            count = SendMessage(inHandle, WIND.WM_LBUTTONDOWN, 0, -1)
    
        Next
    

    【讨论】:

      猜你喜欢
      • 2016-08-03
      • 2021-02-24
      • 2021-03-11
      • 2015-12-20
      • 1970-01-01
      • 1970-01-01
      • 2014-04-30
      • 2021-09-10
      • 1970-01-01
      相关资源
      最近更新 更多