Window Management
All windows are inherited from wxTopLevelWindows
:
WXDLLIMPEXP_DATA_CORE(wxWindowList) wxTopLevelWindows;wxTopLevelWindows
frame window creation Process
When using the frame window, we typically inherit from Wxframe, which is created by invoking the Create
method:
debugWXFrame::debugWXFrame(wxWindow* parent,wxWindowID id){ ... Create(parent, id, wxEmptyString, wxDefaultPosition, ...); ...}
Let's look at wxFrame
the inheritance of the class:
wxFrame -> wxFrameBase -> wxTopLevelWindow -> -> wxTopLevelWindowMSW(wxTopLevelWindowNative) -> wxTopLevelWindowBase
Note: Wxtoplevelwindow inherits from Wxtoplevelwindownative, but wxtoplevelwindownative is a macro definition and is defined in the include/wx/toplevel.h
file as follows:
#if defined(__WXMSW__) #include "wx/msw/toplevel.h" #define wxTopLevelWindowNative wxTopLevelWindowMSW
We then look at the process of creating the window, wxFrame
invoking wxTopLevelWindow::Create
the creation of the implementation window:
- Add a window to the
wxTopLevelWindows
queue, this global variable holds pointers to all current Topwindow;
CreateBase
Used to set the basic parameters;
- Depending on the window type, the
CreateDialog
creation is called or CreateFrame
executed separately.
bool wxFrame::Create(wxWindow *parent, ...){ if ( !wxTopLevelWindow::Create(parent, id, title, pos, size, style, name) ) return false; ...}bool wxTopLevelWindowMSW::Create(wxWindow *parent, ...){ // notice that we should append this window to wxTopLevelWindows list // before calling CreateBase() as it behaves differently for TLW and // non-TLW windows wxTopLevelWindows.Append(this); bool ret = CreateBase(parent, id, pos, sizeReal, style, name); if ( !ret ) return false; if ( parent ) parent->AddChild(this); if ( GetExtraStyle() & wxTOPLEVEL_EX_DIALOG ) { ... ret = CreateDialog(dlgTemplate, title, pos, sizeReal); free(dlgTemplate); } else // !dialog { ret = CreateFrame(title, pos, sizeReal); } return ret;}
Continue to look CreateFrame
, according to the inheritance relationship we can find the actual call is wxTopLevelWindowMSW::CreateFrame
, this function call MSWCreate
implementation window creation:
bool wxTopLevelWindowMSW::CreateFrame(const wxString& title, const wxPoint& pos, const wxSize& size){ WXDWORD exflags; WXDWORD flags = MSWGetCreateWindowFlags(&exflags); const wxSize sz = IsAlwaysMaximized() ? wxDefaultSize : size; return MSWCreate(MSWGetRegisteredClassName(), title.t_str(), pos, sz, flags, exflags);}
Let's take a look at the parameters of this function, which is MSWGetRegisteredClassName
used to register the window class
Note: When creating a custom window, a Windows program needs to call:: RegisterClass registers the window class, creates a custom window class, registers the window class before using the window class, and registers the window class with RegisterClass.
MSWGetRegisteredClassName
wxApp::GetRegisteredClassName
to register by calling:
- First, query whether this window class already exists, if present, use registered;
- The name of the registered window class is
wxWindow
, the message handler function is wxWndProc
;
- After the registration is successful, put this type into
gs_regClassesInfo
the
Note: Two types of windows are registered here, one marked and the other without this tag, and when the window is created, it is CS_HREDRAW | CS_VREDRAW
wxFULL_REPAINT_ON_RESIZE
used without the tag window type, otherwise the window type with the tag is used:
Implementation code:
/* Static */const Wxchar *wxwindowmsw::mswgetregisteredclassname () {return wxapp::getregisteredclassname (WxT (" Wxwindow "), color_btnface);} Const Wxchar *wxapp::getregisteredclassname (const Wxchar *name, ...) {Const size_t count = Gs_regclassesinfo.size (); for (size_t n = 0; n < count; n++) {if (gs_regclassesinfo[n].regname = = name) return GS_REGCL Assesinfo[n].regname.c_str (); }//We need to register this class WNDCLASS wndclass; Wndclass.lpfnwndproc = (WNDPROC) Wxwndproc; Wndclass.style = Cs_hredraw | Cs_vredraw | cs_dblclks | Extrastyles; Classreginfo Regclass (name); Wndclass.lpszclassname = RegClass.regname.t_str (); if (!::registerclass (&wndclass)) ... wndclass.style &= ~ (Cs_hredraw | Cs_vredraw); Wndclass.lpszclassname = RegClass.regnameNR.t_str (); if (!::registerclass (&wndclass)) ... gs_regclassesinfo.push_back (regclass); Return Gs_regclassesinfo.back (). Regname.t_str ();}
Continue to look at the actual creation function of the window MSWCreate
:
- Depending on whether the window tag has a
wxFULL_REPAINT_ON_RESIZE
decision to use that window class;
- Called
::CreateWindowEx
to create a real window, the window handle saved in m_hWnd
.
- Note that there is a more important function here to
SubclassWin(m_hWnd)
Save this window handle to the system, after the app received the message, through this handle to find which Wxwindow associated with this handle, will be detailed later.
bool wxWindowMSW::MSWCreate(const wxChar *wclass, ...){ int x, y, w, h; (void)MSWGetCreateWindowCoords(pos, size, x, y, w, h); int controlId = style & WS_CHILD ? GetId() : 0; wxString className(wclass); if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE) ) { className += wxApp::GetNoRedrawClassSuffix(); } wxWindowCreationHook hook(this); m_hWnd = (WXHWND)::CreateWindowEx ( extendedStyle, className.t_str(), ... ); SubclassWin(m_hWnd); return true;}
Another call for attention is that wxWindowCreationHook hook(this);
this class is used to write the current window's pointer to a global variable, which is used in the gs_winBeingCreated
wxWinProc
function, as described below.
wxWindowCreationHook::wxWindowCreationHook(wxWindowMSW *winBeingCreated){ gs_winBeingCreated = winBeingCreated;}
Window Global Management
Wxwidgets is a Windows-based Win32API to implement window operations, including the message mechanism, there is a question is how Wxwindow class associated with the Win32 window class?
In fact, the implementation of wxwidgets is very simple, through a global map table to save, the index is HWND, the target is the Wxwindow pointer, so you can Win32 handle directly find Wxwindow.
wxGUIEventLoop::PreProcessMessage
We see the following code:
bool wxGUIEventLoop::PreProcessMessage(WXMSG *msg){ HWND hwnd = msg->hwnd; wxWindow *wndThis = wxGetWindowFromHWND((WXHWND)hwnd);
Which wxGetWindowFromHWND
is used to map from the HWND to the Wxwindow pointer, this function implementation, through the call to wxFindWinFromHandle
get the corresponding window, there is also processing is if the current HWND cannot find the window, then use the window's parent window to find.
extern wxWindow *wxGetWindowFromHWND(WXHWND hWnd){ HWND hwnd = (HWND)hWnd; wxWindow *win = NULL; if ( hwnd ) { win = wxFindWinFromHandle(hwnd); } while ( hwnd && !win ) { hwnd = ::GetParent(hwnd); win = wxFindWinFromHandle(hwnd); } return win;}
Continue to look, wxFindWinFromHandle
it is through in the gs_windowHandles
search, and then we look at gs_windowHandles
the definition, he is a hashmap table, similar to std::map
the function, the implementation can be self-looking code:
wxWindow *wxFindWinFromHandle(HWND hwnd){ WindowHandles::const_iterator i = gs_windowHandles.find(hwnd); return i == gs_windowHandles.end() ? NULL : i->second;}WX_DECLARE_HASH_MAP(HWND, wxWindow *, wxPointerHash, wxPointerEqual, WindowHandles);WindowHandles gs_windowHandles;
Window HWND timing associated with Wxwindows
Management mechanism Yes, let's see when this window was registered. In general, there are two times when the HWND is associated with the Wxwindows window:
- The link is called when the window is created
wxWindowMSW::SubclassWin
;
- Associated in a message handler function
wxWndProc
.
After you create a complete association
After the window is created, the call puts SubclassWin
this window into the global variable, and the gs_windowHandles
wxAssociateWinWithHandle
associated HWND and Wxwindow are called in the function:
void wxWindowMSW::SubclassWin(WXHWND hWnd){ wxAssociateWinWithHandle(hwnd, this); // we‘re officially created now, send the event wxWindowCreateEvent event((wxWindow *)this); (void)HandleWindowEvent(event);}
Keep Tracking wxAssociateWinWithHandle
, this is a global function, which is to associate the data together:
void wxAssociateWinWithHandle(HWND hwnd, wxWindowMSW *win){ gs_windowHandles[hwnd] = (wxWindow *)win;}
Associating in Wxwndproc
The window message processing function is unified wxWndProc
, this function in the first after entering the wxwindows based on the HWND, find not to directly associate this HWND to the newly created window.
The key global variable gs_winbeingcreated, which is called in Wxwindowmsw::mswcreate, writes itself to the Gs_ by Wxwindowcreationhook constructor when creating the window. Winbeingcreated this is associated with the first time a message is received and the wxwindows corresponding to the HWND is not found.
// Main window procLRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){ wxWindowMSW *wnd = wxFindWinFromHandle(hWnd); // 关联HWND和wxWindows if ( !wnd && gs_winBeingCreated ) { wxAssociateWinWithHandle(hWnd, gs_winBeingCreated); wnd = gs_winBeingCreated; gs_winBeingCreated = NULL; wnd->SetHWND((WXHWND)hWnd); } LRESULT rc; if ( wnd && wxGUIEventLoop::AllowProcessing(wnd) ) rc = wnd->MSWWindowProc(message, wParam, lParam); else rc = ::DefWindowProc(hWnd, message, wParam, lParam); return rc;}
Why does it appear in two places?
In a Windows system, once the call to the CreateEx function Creation window is complete, the window will immediately receive the message, which is called wxWndProc
for processing, the problem is that there is no call wxWindowMSW::SubclassWin
to associate, so the solution is to use the right time to perform the association, This associated window is passed through a global variable.
Summarize
Wxwidgets provides a complete window management mechanism, effectively combined with the Windows system to form a good middle layer, completely shielding the WIN32API, so that users no matter on which platform to write GUI code, no need to know the platform information.
Wxwidgets Source Analysis (5)-Window management