Thread: Subclassed edit not doing what it's supposed to

  1. #1
    Registered User
    Join Date
    May 2002
    Posts
    132

    Subclassed edit not doing what it's supposed to

    I have subclassed and edit box. Here is the code:

    Code:
    // get ready for user input
    err = ListView_GetSubItemRect(expHwnds.hLV_Wnd, 0, 0, LVIR_LABEL, &rect);
    if( err == 0 )
    {
    	sprintf(error, "Unable to get dimensions of first item. %u", GetLastError());
    	MessageBox(NULL, error, "Error", MB_ICONEXCLAMATION);
    	return(-1);
    }
    else
    {
    	expHwnds.hEdit = CreateWindow("EDIT", "MM/DD/YYYY",
                    WS_CHILD | WS_BORDER | WS_VISIBLE | ES_MULTILINE | ES_WANTRETURN,
                    rect.left, rect.top + 30, rect.right - rect.left,
                    rect.bottom - rect.top, hwnd, NULL, g_hInst, NULL);
    	if( expHwnds.hEdit == NULL )
    	{
    		sprintf(error, "Unable to initialize user input for Expense module. (Error 0027; %u)", GetLastError());
    		MessageBox(NULL, error, "Error", MB_ICONEXCLAMATION);
    		return(-1);
    	}
    }
    
    // TODO: subclass editbox (to get ENTER/TAB key when pressed)
    oldProc = (WNDPROC)SetWindowLongPtr(expHwnds.hEdit, GWLP_WNDPROC, (LONG_PTR)ExpInputWndProc);
    SetWindowLongPtr(expHwnds.hEdit, GWLP_USERDATA, (LONG_PTR)oldProc);
    SetFocus(expHwnds.hEdit);
    Now the editbox seems to get focused (based on output given from this editbox's new windows procedure). However, no text is seen within the editbox (such as the "MM/DD/YYYY" that is supposed to be initially seen within the edit). Nor does it show any text is that is typed into it. Here is the subclassed windows procedure for the editbox.

    Code:
    LRESULT CALLBACK ExpInputWndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
    {
    	WNDPROC oldProc;
    
    	switch(Message)
    	{
    		case WM_KEYDOWN:
    
    			// information was entered (user done)
    			if( wParam == VK_RETURN )
    			{
    				MessageBox(NULL, "Enter key was pressed.", "Keypress", MB_OK);
    				// get data in edit control
    				// empty edit control
    				// hide edit control
    				// make next edit control visible
    				// copy above steps for VK_TAB
    				return(0);
    			}
    
    			// same as VK_RETURN
    			else if( wParam == VK_TAB )
    			{
    				MessageBox(NULL, "Tab key was pressed.", "Keypress", MB_OK);
    				return(0);
    			}
    
    			// never will the '/'s in the editbox be erased
    			else if( wParam == VK_BACK )
    			{
    				MessageBox(NULL, "Backspace key was pressed.", "Keypress", MB_OK);
    				// get current cursor position in text
    				// determine if backspacing will erase a '/'
    				// if not break;
    				// else simply move cursor position back one instead of backspacing
    				return(0);
    			}
    			break;
    	}
    
    	oldProc = (WNDPROC)GetWindowLongPtr(hwnd, GWLP_USERDATA);
    	return(CallWindowProc(oldProc, hwnd, Message, wParam, lParam));
    }
    If anyone can tell me why this isn't showing the text, then please let me know. I have been unable to figure it out. Also does anyone know how to get rid of the warning messages that are coming up for the lines where I am calling GetWindowLongPtr() and SetWindowLongPtr()? There are warnings for setting oldProc to (WNDPROC)... says that possible loss of data setting 'LONG' to 'WNDPROC' of greater size. As well as with SetWindowLongPtr() I'm getting warnings with setting 'LONG_PTR' to 'LONG' also possible loss of data. If you can help with that as well, its a pet peave of mine to have any sort of warnings whatsoever when I am done a project (I get worried that it will cause problems).

    Thanks,
    Tyouk

  2. #2
    Handy Andy andyhunter's Avatar
    Join Date
    Dec 2004
    Posts
    540
    Here is a basic program that subclasses the edit control on the main window. I've commented all the relevant pieces of code. If you have any questions let me know.

    Code:
    #include <windows.h>
    
    #define ID_EDIT     1
    
    WNDPROC oldEditProc; //used to store old edit procedure address
    
    LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
    LRESULT CALLBACK subclassProc(HWND, UINT, WPARAM, LPARAM); //used for new edit window proc
    
    
    TCHAR szAppName[] = TEXT ("Subclassing Proc") ;
    
    int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                        PSTR szCmdLine, int iCmdShow)
    {
         HWND     hwnd ;
         MSG      msg ;
         WNDCLASS wndclass ;
         
         wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
         wndclass.lpfnWndProc   = WndProc ;
         wndclass.cbClsExtra    = 0 ;
         wndclass.cbWndExtra    = 0 ;
         wndclass.hInstance     = hInstance ;
         wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
         wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
         wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
         wndclass.lpszMenuName  = NULL ;
         wndclass.lpszClassName = szAppName ;
         
         if (!RegisterClass (&wndclass))
         {
              MessageBox (NULL, TEXT ("Could not register class"),
                          szAppName, MB_ICONERROR) ;
              return 0 ;
         }
         
         hwnd = CreateWindow (szAppName, szAppName,
                              WS_OVERLAPPEDWINDOW,
                              CW_USEDEFAULT, CW_USEDEFAULT,
                              CW_USEDEFAULT, CW_USEDEFAULT,
                              NULL, NULL, hInstance, NULL) ;
         
         ShowWindow (hwnd, iCmdShow) ;
         UpdateWindow (hwnd) ; 
         
         while (GetMessage (&msg, NULL, 0, 0))
         {
              TranslateMessage (&msg) ;
              DispatchMessage (&msg) ;
         }
         return msg.wParam ;
    }
    
    LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
         static HWND hwndEdit ;
         
         switch (message)
         {
         case WM_CREATE :
              
    		 //create the edit control
    		 hwndEdit = CreateWindow (TEXT ("edit"), NULL,
                             WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL |
                                       WS_BORDER | ES_LEFT | ES_MULTILINE |
                                       ES_AUTOHSCROLL | ES_AUTOVSCROLL,
                             0, 0, 0, 0, hwnd, (HMENU) ID_EDIT,
                             ((LPCREATESTRUCT) lParam) -> hInstance, NULL) ;
              
    		  //subclass edit control
    		  oldEditProc = (WNDPROC)SetWindowLongPtr(hwndEdit, GWLP_WNDPROC, (LONG_PTR)subclassProc);
    
    		  return 0 ;
              
         case WM_SETFOCUS :
              SetFocus (hwndEdit) ;
              return 0 ;
              
         case WM_SIZE : 
              MoveWindow (hwndEdit, 0, 0, LOWORD (lParam), HIWORD (lParam), TRUE) ;
              return 0 ;
              
         case WM_COMMAND :
              if (LOWORD (wParam) == ID_EDIT)
                   if (HIWORD (wParam) == EN_ERRSPACE || 
                             HIWORD (wParam) == EN_MAXTEXT)
    
                        MessageBox (hwnd, TEXT ("Edit control out of space."),
                                    szAppName, MB_OK | MB_ICONSTOP) ;
              return 0 ;
                   
         case WM_DESTROY :
              PostQuitMessage (0) ;
              return 0 ;
         }
         return DefWindowProc (hwnd, message, wParam, lParam) ;
    }
    //new edit procedure
    LRESULT CALLBACK subclassProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
    
    	switch(message) {
    
    		case WM_KEYDOWN:
    
    			if(wParam == VK_TAB) {
    
    				MessageBox(NULL, TEXT("Pressed Tab"), TEXT("subclass notification"), MB_ICONINFORMATION);
    				return 0;
    			}
    			break;
    	}
    	return CallWindowProc(oldEditProc, hwnd, message, wParam, lParam);
    }
    Happy Coding!!

    edit - BTW I do not recieve any warning messages.
    i don't think most standard compilers support programmers with more than 4 red boxes - Misplaced

    It is my sacred duity to stand in the path of the flood of ignorance and blatant stupidity... - quzah

    Such pointless tricks ceased to be interesting or useful when we came down from the trees and started using higher level languages. - Salem

  3. #3
    Registered User
    Join Date
    May 2002
    Posts
    132
    I looked over your example and compared it to my own code. I find that I have everything except that I could not place the code in my main windows procedure for the WM_SETFOCUS message as is in your example because the main windows procedure doesn't have access to my edit's HWND. Now I did try using SetFocus(expHwnds.hEdit); and the edit does indeed get focus. I've proven that to myself. Now my problem is with the displaying of text within that edit. It just isn't there. I've even tried SetWindowText, yet nothing seems to work in order to get the text to display. Now could my problem be in the fact that my main window is filled first off by a tab control created using CreateWindowEx and then as one tab is clicked on (as is this case), a ListView is display (created at runtime) which is also a child of the main window. Then on top of the ListView an edit control is supposed to be displayed. Now I have the editbox displaying in the right spot. However, the edit isn't displaying any text. Now on first display the carrot actually shows at the start of the edit, however, as soon as I hit a key a beep sounds and the carrot vanishes. Do you know what could be causing this? The code is above for the edit, if you need code for the tabs or the listview then just let me know.

  4. #4
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    Do you get any msgs in the ExpInputWndProc()?

    try....

    setting the edit to a child of the listview

    and/or...

    Ensure that all the child controls of the main window have different ID numbers by setting the HMENU param in the create to an int.

    MSDN on CreateWindow()
    "For a child window, hMenu specifies the child-window identifier, an integer value used by a dialog box control to notify its parent about events. The application determines the child-window identifier; it must be unique for all child windows with the same parent window."

    (Could be that the LV and edit (and TAB ect) all have the ID number NULL (and same parent) and are so conflicting.)


    I also process WM_KILLFOCUS msgs and set the edited LV item to 'selected', destroy the edit and return focus to the LV.

    On create I use SendMessage() with WM_SETTEXT (and EM_SETSEL 0,-1), then with the edits hwnd ShowWindow(), UpdateWindow() and SetFocus()



    EDIT: I have working code for exactly this in MFC and WIN32 C. The number of controls 'stacked' on top of each other is not a problem.
    Let me know if you are still having problems.
    Last edited by novacain; 01-18-2005 at 01:50 AM.
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

  5. #5
    Registered User
    Join Date
    May 2002
    Posts
    132
    I tried all your suggestions. However, none have worked so far. I really can't figure this one out. I made sure that all resource IDs (childs of the main window) are all not using the same resource IDs. I tried setting the edit as a child of the LV. I processed for the WM_KILLFOCUS message, as well as on creation using the WM_SETTEXT, and EM_SETSEL message.

    Any other suggestions? Thanks if you have any.
    Tyouk

  6. #6
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    OK.....hmmmmmm.

    If you create the edit somewhere else, as a child of the dlg,

    can you set the text in the edit?

    That is can you use this code to create a 'normal' edit?

    >>Do you get any msgs in the ExpInputWndProc()?

    Place a breakpoint at the begining of the edits callback, ExpInputWndProc().

    Does it ever get called ie msgs passing thru the callback?
    Last edited by novacain; 01-19-2005 at 12:38 AM.
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

  7. #7
    Registered User
    Join Date
    May 2002
    Posts
    132
    I am definitely getting messages through the edit's callback. I have it setup to catch three specific inputs. VK_RETURN, VK_TAB and VK_BACK. Each displaying a message such as "Enter key was pressed.", respectfully for the keys being watched for. I have it break and call the regular callback using CallWindowProc for anything else pressed. All I get is beeps when any other keys are pressed. Is this because I'm not handling the keypresses how I should be?

    Here is an example of how my ExpInputWndProc() looks:

    Code:
    LRESULT CALLBACK ExpInputWndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
    {
    	switch(Message)
    	{
    		case WM_KEYDOWN:
    
    			// information was entered (user done)
    			if( wParam == VK_RETURN )
    			{
    				MessageBox(NULL, "Enter key was pressed.", "Keypress", MB_OK);
    				return(0); // stop normal operation
    			}
    			break;
    	}
    
    	return(CallWindowProc(oldEditProc, hwnd, Message, wParam, lParam));
    }
    oldEditProc is a global WNDPROC set when I used SetWindowLongPtr in order to subclass the control. Now thats just for user input. I also have the code to handle the WM_KILLFOCUS as you suggested I do earlier. Would this be the wrong way of handling this message in order to allow user input as normal except when certain keys are pressed?

    Thanks,
    Tyouk

  8. #8
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    Have a look at this....

    is a standard WIN32 app made with the MSVC IDE.
    I have included only the main .cpp file, should be all you need.

    Not 100% but close....
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

  9. #9
    Registered User
    Join Date
    May 2002
    Posts
    132
    I looked over the code. I decided to rewrite the program because of the problems I have been having. I am going to implement each control, one at a time. Testing each out thouroughly to make sure that I have the control as I need it before moving on to the next. I have made notes based on the code you posted so that should assist me in making sure this gets done right this time.

    Thanks,
    Tyouk

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Multiline Edit Box Parser
    By The Brain in forum Windows Programming
    Replies: 6
    Last Post: 11-01-2005, 07:15 PM
  2. Replies: 3
    Last Post: 07-23-2005, 08:00 AM
  3. Capture Enter key press in EDIT Box
    By richiev in forum Windows Programming
    Replies: 4
    Last Post: 07-14-2005, 12:03 AM
  4. edit controls
    By ZerOrDie in forum Windows Programming
    Replies: 11
    Last Post: 04-08-2003, 12:09 PM
  5. Difficulty superclassing EDIT window class
    By cDir in forum Windows Programming
    Replies: 7
    Last Post: 02-21-2002, 05:06 PM