Fix destruction of wxNativeContainerWindow in wxMSW.

WM_CLOSE was not processed at all for native windows wrapped by
wxNativeContainerWindow because we don't handle it ourselves at wxWindow level
but still mark it as processed in order to prevent DefWindowProc() from
destroying the window. Unfortunately this also prevented the original handler
for this message in the native window from being called.

Calling just the original handler and not the wxWidgets one is not ideal
neither but is much better as it allows to e.g. close MFC frames wrapped in
wxNativeContainerWindow whereas before this didn't work at all as WM_CLOSE was
completely ignored.

Also call the original handler for WM_DESTROY to avoid similar potential
problems with this message, even if it doesn't seem to create any with MFC.

Extend the mfc sample to show how a wxPanel can be embedded into the existing
CFrameWnd.
This commit is contained in:
Vadim Zeitlin
2015-07-09 20:06:48 +02:00
parent 394b04b7e4
commit 9be928d6fb
3 changed files with 65 additions and 3 deletions

View File

@@ -70,6 +70,8 @@
#endif #endif
#include "wx/evtloop.h" #include "wx/evtloop.h"
#include "wx/nativewin.h"
#include "wx/spinctrl.h"
#include "resource.h" #include "resource.h"
@@ -121,6 +123,38 @@ public:
wxDECLARE_EVENT_TABLE(); wxDECLARE_EVENT_TABLE();
}; };
class MyPanel : public wxPanel
{
public:
MyPanel(wxWindow *parent, const wxPoint& pos)
: wxPanel(parent, wxID_ANY, pos)
{
wxSizer* const sizer = new wxFlexGridSizer(2, wxSize(5, 5));
sizer->Add(new wxStaticText(this, wxID_ANY, "Enter your &name:"),
wxSizerFlags().Center().Right());
m_textName = new wxTextCtrl(this, wxID_ANY);
m_textName->SetHint("First Last");
sizer->Add(m_textName, wxSizerFlags().Expand().CenterVertical());
sizer->Add(new wxStaticText(this, wxID_ANY, "And your &age:"),
wxSizerFlags().Center().Right());
m_spinAge = new wxSpinCtrl(this, wxID_ANY);
sizer->Add(m_spinAge, wxSizerFlags().Expand().CenterVertical());
wxStaticBoxSizer* const
box = new wxStaticBoxSizer(wxVERTICAL, this, "wxWidgets box");
box->Add(sizer, wxSizerFlags(1).Expand());
SetSizer(box);
// We won't be resized automatically, so set our size ourselves.
SetSize(GetBestSize());
}
private:
wxTextCtrl* m_textName;
wxSpinCtrl* m_spinAge;
};
// ID for the menu quit command // ID for the menu quit command
#define HELLO_QUIT 1 #define HELLO_QUIT 1
#define HELLO_NEW 2 #define HELLO_NEW 2
@@ -147,6 +181,18 @@ CMainWindow::CMainWindow()
LoadAccelTable( wxT("MainAccelTable") ); LoadAccelTable( wxT("MainAccelTable") );
Create( NULL, wxT("Hello Foundation Application"), Create( NULL, wxT("Hello Foundation Application"),
WS_OVERLAPPEDWINDOW, rectDefault, NULL, wxT("MainMenu") ); WS_OVERLAPPEDWINDOW, rectDefault, NULL, wxT("MainMenu") );
// Create a container representing the MFC window in wxWidgets window
// hierarchy.
m_containerWX = new wxNativeContainerWindow(m_hWnd);
// Now we can create children of this container as usual.
new MyPanel(m_containerWX, wxPoint(5, 5));
// An ugly but necessary workaround to prevent the container TLW from
// resizing the panel to fit its entire client area as it would do if it
// were its only child.
new wxWindow(m_containerWX, wxID_ANY, wxPoint(4, 4), wxSize(1, 1));
} }
void CMainWindow::OnPaint() void CMainWindow::OnPaint()

View File

@@ -26,6 +26,9 @@ public:
//}}AFX_MSG //}}AFX_MSG
DECLARE_MESSAGE_MAP() DECLARE_MESSAGE_MAP()
private:
class wxNativeContainerWindow* m_containerWX;
}; };
// A dummy CWnd pointing to a wxWindow's HWND // A dummy CWnd pointing to a wxWindow's HWND

View File

@@ -69,11 +69,24 @@ WXLRESULT wxNativeContainerWindow::MSWWindowProc(WXUINT nMsg,
WXWPARAM wParam, WXWPARAM wParam,
WXLPARAM lParam) WXLPARAM lParam)
{ {
if ( nMsg == WM_DESTROY ) switch ( nMsg )
{ {
OnNativeDestroyed(); case WM_CLOSE:
// wxWindow itself, unlike wxFrame, doesn't react to WM_CLOSE and
// just ignores it without even passing it to DefWindowProc(),
// which means that the original WM_CLOSE handler wouldn't be
// called if we didn't explicitly do it here.
return MSWDefWindowProc(nMsg, wParam, lParam);
return 0; case WM_DESTROY:
// Send it to the original handler which may have some cleanup to
// do as well. Notice that we must do it before calling
// OnNativeDestroyed() as we can't use this object after doing it.
MSWDefWindowProc(nMsg, wParam, lParam);
OnNativeDestroyed();
return 0;
} }
return wxTopLevelWindow::MSWWindowProc(nMsg, wParam, lParam); return wxTopLevelWindow::MSWWindowProc(nMsg, wParam, lParam);