子窗口组合框行为 [英] Child window combobox behaviour

查看:78
本文介绍了子窗口组合框行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

温柔的人,
我只是不明白...
有一个组合框子窗口.如果将焦点设置到此组合框,则可以输入所需的文本,该文本会显示在框中,但无法检查用户是否已完成输入. IE.我在WM_COMMAND下收到所有CB通知,但在WM_CHAR或WM_KEYDOWN中没有.另一方面,如果我禁用了此组合框的SetFocus,则无法输入文本. IE.在WM_COMMAND下我没有收到任何CB通知,但是WM_CHAR或WM_KEYDOWN效果很好...

有人可以解释一下,让我知道如何进行吗?任何帮助将不胜感激!

以下简单的代码段已显示了此行为:

Gentle people,
I simply just don''t understand ...
There is a Combobox child window. If I set the focus to this combobox, I can enter the desired text and it is shown in the box, but I am unable to check whether the user has completed his entry. I.e. I get all CB notifications under WM_COMMAND, but none in WM_CHAR or WM_KEYDOWN. On the other hand if I inactivate the SetFocus to this combobox, I am unable to enter text. I.e. I get none of the CB notifications under WM_COMMAND, but WM_CHAR or WM_KEYDOWN work well ...

Could somebody please explain and give me an idea how to proceed? Any help will be appreciated!

The following simple piece of code already shows this behaviour:

int APIENTRY _tWinMain (HINSTANCE hInstance,
                        HINSTANCE hPrevInstance,
                        LPTSTR    lpCmdLine,
                        int       nCmdShow)
{           :
  	    :
  	    :
// Create Main window  	    	
  LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
  hWnd  = CreateWindow (szWindowClass,szTitle,
                        WS_TILED | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU,
                        100,100,905,667,NULL,NULL,hInstance,NULL);  
// Create Combobox Child window  	    	                        
  LoadString(hInstance, IDC_CMB, szClass, MAX_LOADSTRING);
  hListtitel = CreateWindow(szClass,"",
                        WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | _VSCROLL,   
                        200, 170, 540, 400,hWnd,NULL,hInstance,NULL);   
  InvalidateRect(hWnd,NULL,TRUE); 
  ShowWindow(hWnd, SW_SHOWNORMAL);
  UpdateWindow(hWnd);
  SetFocus(hListtitel);       <----------------------------------
  
  while (GetMessage(&msg, NULL, 0, 0))
  {
    if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
    {
      TranslateMessage(&msg);
      DispatchMessage(&msg); 
    }
  }
  return (int) msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
  switch (message)
  {         :
  	    :
  	    :
    case WM_CHAR: 
     /*     do something     */
      break; 
            :
  	    :
  	    :
    case WM_COMMAND:
      wmEvent = HIWORD(wParam);
      if ((hListtitel != 0) && (lParam == (LPARAM)hListtitel))
      {
        switch (wmEvent)
			  {
       	  case CBN_EDITUPDATE: 
     /*     do something     */
            break; 
       	  case CBN_KILLFOCUS:  
     /*     do something     */
            break; 
          case CBN_SELCHANGE:  
     /*     do something     */
            break; 
          }	
        break; 
      }
  }
  return DefWindowProc(hWnd, message, wParam, lParam);


}

推荐答案

Gday,

此行为的原因是(默认)组合框不已发送向其父级发送WM_CHAR或WM_KEYDOWN/WM_KEYUP的通知.

当您将焦点放在对话框上时,它是给您WM_CHAR WM_KEYxxxx消息而不是组合框的对话框.


解决此问题的方法是对组合框进行子分类,就像对应用程序窗口进行子分类一样.然后,您将拥有自己的WindowProc函数,无论ComboBox发生任何事情,都将调用该函数.从那里,您可以处理所有感兴趣的消息,然后再将所有消息传递给组合框的默认窗口proc.

自从我进行任何子类化以来已经有很多年了,所以我对来龙去脉的记忆已经大大减弱了. :(
但是, [
Gday there,

The reason for this behaviour is that the (default) Combo Box doesn''t sent send notifications of WM_CHAR or WM_KEYDOWN/WM_KEYUP to it''s parent.

When you give focus to the dialog, it''s the dialog that''s giving you the WM_CHAR WM_KEYxxxx messages, NOT the Combo Box.


The way around this is to sub-class the combo box, just the same way that you sub-class the app''s window. Then, you''ll have your own WindowProc function that''s called whenever anything happens with the ComboBox. From there, you process any messages you''re interested in, before passing all messages to the default window proc for the Combo Box.

It''s been ages since I did any sub-classing, so my memory of the ins and outs have faded considerably. :(
However, this[^] example looks like it will be helpful.


对不起!我必须道歉!你一直都是对的!

在准备用最少的代码来显示问题的代码并一直重新编译以检查问题是否仍然存在时,事情突然奇迹般地开始正常工作.请不要问我罪魁祸首-我只能假定我的代码中存在一个缺陷,该缺陷已通过我的准备得以纠正...

抱歉,再次感谢您的耐心配合和宝贵的帮助!
恩斯特

注意:我只找到有问题或评论"或添加您的解决方案",但没有回复" ...

这是组合框不参与对话的有效解决方案:
Sorry! I do have to apologize! You were right all the time!

While preparing the code to show the problem with the least amount of code and recompiling all the time to check whether the problem still exists, the thing suddenly miraculously started working properly. Please don''t ask me what the culprit was - I only can assume there was a flaw in my code, which was rectified by my preparations ...

Sorry about that and thank you again for your patience and for your valuable help!
Ernst

NB: I only find "Have a question or comment" or "Add your solution", but no "reply" ...

This is the working solution for a combobox not being part of a dialogue:
//#include "stdafx.h"
#include "TestCombo.h"
#include "resource.h"
#include <string.h>
#include <stdio.h>
#include <tchar.h>
#include <windows.h>

#define MAX_LOADSTRING 100
#define WM_TAB (WM_USER) 
#define WM_ESC (WM_USER + 1) 
#define WM_ENTER (WM_USER + 2) 

WNDCLASSEX  wcex;
WNDPROC     lpfnParProc;
HACCEL      hAccelTable;
TCHAR       szClass[MAX_LOADSTRING];
TCHAR       szTitle[MAX_LOADSTRING];       
TCHAR       szWindowClass[MAX_LOADSTRING]; 
MSG         msg;  
HWND        hMain;
HWND        hListtitel;
HWND        hEdittitel; 
HDC         hdc;
HINSTANCE   hInst;
RECT        rt;
PAINTSTRUCT ps;
POINT       pt; 
int         wmId;
int         wmEvent;
int         lmId;
int         lmEvent;

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK ChldProc(HWND, UINT, WPARAM, LPARAM);

int APIENTRY _tWinMain (HINSTANCE hInstance,
                        HINSTANCE hPrevInstance,
                        LPTSTR    lpCmdLine,
                        int       nCmdShow)
{
	hInst = hInstance;
  hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_TESTCOMBO));
  LoadString(hInstance, IDC_TESTCOMBO, szWindowClass, MAX_LOADSTRING);
  wcex.cbSize        = sizeof(WNDCLASSEX);
  wcex.style         = CS_HREDRAW | CS_VREDRAW;
  wcex.lpfnWndProc   = WndProc;
  wcex.cbClsExtra    = 0;
  wcex.cbWndExtra    = 0;
  wcex.hInstance     = hInstance;
  wcex.hIcon         = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_TESTCOMBO));
  wcex.hCursor       = LoadCursor(NULL, IDC_ARROW);
  wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
  wcex.lpszMenuName  = MAKEINTRESOURCE(IDC_TESTCOMBO);
  wcex.lpszClassName = szWindowClass;
  wcex.hIconSm       = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
  if (!RegisterClassEx(&wcex))
  { return FALSE; }
  
  hMain  = CreateWindow (szWindowClass,"Test Combobox",
               WS_TILED | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU,
               100,100,905,667,NULL,NULL,hInstance,NULL);  
               
  hListtitel = CreateWindow("COMBOBOX","",
               WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | WS_VSCROLL | CBS_HASSTRINGS, 
               200, 170, 540, 400,hMain,NULL,hInst,NULL);  
               
  hEdittitel = FindWindowEx(hListtitel,NULL,"EDIT",NULL);
  lpfnParProc = (WNDPROC) SetWindowLong(hEdittitel,GWL_WNDPROC, (DWORD) ChldProc);
  
  InvalidateRect(hMain,NULL,TRUE); 
  ShowWindow(hMain, SW_SHOWNORMAL);
  UpdateWindow(hMain);
  SetFocus(hListtitel);
  
  while (GetMessage(&msg, NULL, 0, 0))
  {
    if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
    {
      TranslateMessage(&msg);
      DispatchMessage(&msg); 
    }
  }
  return (int) msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
  switch (message)
  {
    case WM_PAINT:
      hdc = BeginPaint(hwnd, &ps);
      EndPaint(hwnd, &ps);
      break;
    case WM_DESTROY:
      PostQuitMessage(0);
      break;        
    case WM_TAB: 
                                       // Do something
      break; 
    case WM_ESC: 
                                       // Do something 
      break;
    case WM_ENTER: 
                                       // Do something
      break; 
    case WM_COMMAND:
      wmEvent = HIWORD(wParam);
      if ((hListtitel != 0) && (lParam == (LPARAM)hListtitel))
      {
        switch (wmEvent)
			  {
       	  case CBN_EDITUPDATE: 
		                                	  // Do something
            break; 
       	  case CBN_KILLFOCUS:  
		    	                              // Do something
            break; 
          case CBN_SELCHANGE:  
		    	                              // Do something
            break; 
          }	
        break; 
      }
    default:
    	return DefWindowProc(hwnd, message, wParam, lParam);
  }
  return 0;
}

LRESULT CALLBACK ChldProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  switch (msg)
  {        
  	case WM_KEYDOWN: 
      switch (wParam) 
      { 
        case VK_TAB: 
          SendMessage(hMain, WM_TAB, 0, 0); 
          return 0; 
        case VK_ESCAPE:  
          SendMessage(hMain, WM_ESC, 0, 0); 
          return 0; 
        case VK_RETURN: 
          SendMessage(hMain, WM_ENTER, 0, 0); 
          return 0; 
       } 
       break; 
  } 
  return CallWindowProc(lpfnParProc, hwnd, msg, wParam, lParam); 


好吧,我回到第一个问题...
添加了
Well, I am back to square one ...
Added
  hListtitel = CreateWindow("COMBOBOX","",
               WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | WS_VSCROLL | CBS_HASSTRINGS, 
               200, 170, 540, 400,hWnd,NULL,hInst,NULL);          
  pt.x = 1; 
  pt.y = 1; 
// get the handle to the edit part of the combobox
  hEdittitel = ChildWindowFromPoint(hListtitel, pt); 
// set pointer to the desired procedure
  lpfnParProc = (WNDPROC) SetWindowLong(hEdittitel,GWL_WNDPROC, (DWORD) ChldProc); 

如上面的代码示例中所述,并且还添加了一个"ChldProc",类似于所提到的文章,用于处理来自组合框的编辑部分的所有消息.

我在ChldProc中收到大量消息,但对于WM_CHAR或WM_KEYDOWN没有消息...
:O(((!Sob ...

as in code sample above and added also a "ChldProc", similar to the article mentioned, to process all the messages coming from the edit part of the combobox.

I get loads of messages in ChldProc, but none for WM_CHAR or WM_KEYDOWN ...
:O(((! Sob ...


这篇关于子窗口组合框行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆