|
by Sergey Krotkikh
Senior Software Developer
QArea
We propose one of the ways to restore entry focus in a custom window after its activation.
Suppose, that only standard controls are used in a window.
They are WC_BUTTON, WC_COMBOBOX, WC_EDIT, WC_LISTBOX, WC_SCROLLBAR. After getting the idea of it, the method can be extended to any class of a child window that can be in entry focus.
For each of the controls stated above we create a superclass with the same name and a new window function. Window function will be uniform for all classes. It processes the message WM_SETFOCUS, at this stores the parameter of hWnd window and retrieves the control of parent class function.
Then the window function of a custom window, for which the focus is to be restored, in WM_ACTIVATE handler (or in WM_SETFOCUS) activates a function that restores focus on its element that was the last to receive message from WM_SETFOCUS.
Considering, that standard controls with WS_TABSTOP feature are compulsorily to receive WM_SETFOCUS message at Tab pressing, the method works perfectly.
Well, let us start with creating several structures:
typedef struct superclassdata
{ TCHAR ClassName[100]; /* Name of the class to be superclassed*/
WNDPROC fnWndProc; /* Window procedure of the parent class*/
}SCD;
SCD aSCD[MAX_SCD]; /* Array where we will store access points of window procedures*/
typedef struct parentwnd
{ HWND hWnd; /* Custom window for which we will restore focus*/
HWND hFocus; /* window element that is in focus*/
}PWND;
PWND aPWND[MAX_PWND]; /* Array where the element in focus for each custom window is stored.*/
|
BOOL CreateSuperClass(TCHAR* lpClassName); |
| | /* Function which creates a superclass for the specified class (with name lpClassName)*/ |
|
long CALLBACK SuperClassWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); |
| | /* Window function of superclasses (uniform for all)*/ |
|
VOID StartRestoreFocus(HWND hWnd, HWND hFocus); |
| | /*Launch the process. Function must be activated from WM_CREATE, or from another place, afterwards the procedure of focus restoration for hWnd window sets in. Parameter hFocus specifies an element which is the first to receive the focus. Parameter may not be specified, then function sets focus on the first child element that has WS_TABSTOP feature.*/ |
|
VOID StopRestoreFocus(HWND hWnd); |
| | /* Close up the process. Array element is discharged and the process of focus restoration for hWnd window is aborted.*/ |
| | /* Function should be activated at processing of WM_DESTROY or similar location in a custom window message processing function.*/ |
| | // Restore focus. |
|
VOID RestoreFocus(HWND hWnd); |
| | /* Function should be activated in WM_SETFOCUS handler or in WM_ACTIVATE handler of hWnd custom window. |
| | Function restores focus on the element that was the last to receive it when the window was active.*/ |
First of all, it is necessary to register new classes of windows in the program:
| | CreateSuperClass(WC_BUTTON); |
| | CreateSuperClass(WC_COMBOBOX); |
| | CreateSuperClass(WC_EDIT); |
| | CreateSuperClass(WC_LISTBOX); |
| | CreateSuperClass(WC_SCROLLBAR); |
Let us put down the code in application initialization part, in WinMain.
Next, for a new window we add the code to its function:
...
switch (message)
{
case WM_CREATE: |
{
...
StartRestoreFocus(hWnd,(HWND)NULL);
...
}
return 0; |
...
case WM_SETFOCUS: // Possible in WM_ACTIVATE |
{
RestoreFocus(hWnd);
break;
} |
...
case WM_DESTROY: // Possible in WM_ACTIVATE |
{
...
StopRestoreFocus(hWnd);
...
}
return 0;
|
...
} |
Finally, the functions themselves.
BOOL CreateSuperClass(TCHAR* lpClassName)
{
int i;
WNDCLASS WndClass;
WndClass.style=(UINT)0;
if(GetClassInfo(hInstGlobal,(LPSTR) lpClassName,&WndClass))
{
if(bSCDInit)
{
for(i = 0;i < MAX_SCD; i++)
{
aSCD[i].ClassName[0]=_T('\0');
}
for(i = 0;i < MAX_PWND; i++)
{
aPWND[i].hWnd=(HWND)NULL;
aPWND[i].hFocus=(HWND)NULL;
}
bSCDInit=FALSE;
}
for(i = 0; i < MAX_SCD; i++)
if(aSCD[i].ClassName[0]==_T('\0'))
{
WndClass.hInstance=hInstGlobal;
WndClass.lpszClassName=lpClassName;
_tcscpy(aSCD[i].ClassName,lpClassName);
aSCD[i].fnWndProc=WndClass.lpfnWndProc;
WndClass.lpfnWndProc=(WNDPROC)SuperClassWndProc;
RegisterClass(&WndClass);
return TRUE;
}
}
return FALSE;
}
VOID StartRestoreFocus(HWND hWnd, HWND hFocus)
{
int i;
for(i=0;i<MAX_PWND;i++)
{
if (aPWND[i].hWnd==(HWND)NULL)
{
aPWND[i].hWnd=hWnd;
if (hFocus)
aPWND[i].hFocus=hFocus;
else
aPWND[i].hFocus=GetNextDlgTabItem(hWnd,(HWND)NULL,FALSE);
break;
}
}
}
VOID StopRestoreFocus(HWND hWnd)
{
int i;
for(i=0;i<MAX_PWND;i++)
{
if (aPWND[i].hWnd==hWnd)
{
aPWND[i].hWnd=(HWND)NULL;
aPWND[i].hFocus=(HWND)NULL;
break;
}
}
}
VOID RestoreFocus(HWND hWnd)
{
int i;
for(i=0;i<MAX_PWND;i++)
{
if(aPWND[i].hWnd==hWnd)
{
SetFocus(aPWND[i].hFocus);
break;
}
}
return;
}
long CALLBACK SuperClassWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int i,j;
TCHAR t[MAX_PATH];
GetClassName(hWnd, t, MAX_PATH);
for(i=0;i<MAX_SCD;i++)
{
if(_tcscmp(aSCD[i].ClassName,t)==0)
{
switch(message)
{
case WM_SETFOCUS:
{
HWND hParent=hWnd;
BOOL bF=FALSE;
while (!bF && IsWindow(hParent))
{
for(j=0;j<MAX_PWND;j++)
{
if(aPWND[j].hWnd==hParent)
{
aPWND[j].hFocus=hWnd;
bF=TRUE;
break;
}
}
hParent=GetParent(hParent);
}
}
}
return CallWindowProc(aSCD[i].fnWndProc, hWnd, message, wParam, lParam);
}
}
return 0;
}
|