wxWidgets/samples/mfc/mfctest.cpp
Vadim Zeitlin 8e05886313 Allow MFC have idle events too in the MFC sample
Call MFC base class method from our overridden one.

Closes #15252.
2016-03-06 19:38:05 +01:00

468 lines
13 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: mfctest.cpp
// Purpose: Sample to demonstrate mixing MFC and wxWidgets code
// Author: Julian Smart
// Copyright: (c) Julian Smart
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// This sample pops up an initial wxWidgets frame, with a menu item
// that allows a new MFC window to be created. Note that CDummyWindow
// is a class that allows a wxWidgets window to be seen as a CWnd
// for the purposes of specifying a valid main window to the
// MFC initialisation.
//
// You can easily modify this code so that an MFC window pops up
// initially as the main frame, and allows wxWidgets frames to be
// created subsequently.
//
// (1) Make MyApp::OnInit not create a main window.
// (2) Make MFC's InitInstance create a main window, and remove
// creation of CDummyWindow.
//
// This can be accomplished by setting START_WITH_MFC_WINDOW to 1 below.
#define START_WITH_MFC_WINDOW 0
// NOTES:
//
// * You should link with MFC DLL, not static libraries: or, to use static
// run-time libraries, use this command for both building wxWidgets and
// the sample:
//
// nmake -f makefile.vc BUILD=debug SHARED=0 DEBUG_RUNTIME_LIBS=0 RUNTIME_LIBS=static all
//
// Unless the run-time library settings match for wxWidgets and MFC, you
// will get link errors for symbols such as __mbctype, __argc, and __argv
//
// * If you see bogus memory leaks within the MSVC IDE on exit, in this
// sample or in your own project, you must be using __WXDEBUG__ +
// WXUSINGDLL + _AFXDLL
// Unfortunately this confuses the MSVC/MFC leak detector. To do away with
// these bogus memory leaks, add this to the list of link objects, make it
// first: mfc[version][u]d.lib
// - [version] -> 42 or 70 or 80 etc
// - u if using Unicode
// Disable deprecation warnings from headers included from stdafx.h for VC8+
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
// Also define WINVER to avoid warnings about it being undefined from the
// platform SDK headers (usually this is not necessary because it is done by wx
// headers but here we include the system ones before them)
#ifndef WINVER
#define WINVER 0x0600
#endif
#include "stdafx.h"
// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
#include "wx/evtloop.h"
#include "wx/nativewin.h"
#include "wx/spinctrl.h"
#include "resource.h"
#include "mfctest.h"
/////////////////////////////////////////////////////////////////////////////
// theApp:
// Just creating this application object runs the whole application.
//
CTheApp theApp;
// wxWidgets elements
// Define a new application type
class MyApp: public wxApp
{
public:
virtual bool OnInit();
// we need to override this as the default behaviour only works when we're
// running wxWidgets main loop, not MFC one
virtual void ExitMainLoop();
wxFrame *CreateFrame();
};
class MyCanvas: public wxScrolledWindow
{
public:
MyCanvas(wxWindow *parent, const wxPoint& pos, const wxSize& size);
void OnPaint(wxPaintEvent& event);
void OnMouseEvent(wxMouseEvent& event);
wxDECLARE_EVENT_TABLE();
};
class MyChild: public wxFrame
{
public:
MyChild(wxFrame *frame, const wxString& title, const wxPoint& pos, const wxSize& size, const long style);
virtual ~MyChild();
void OnQuit(wxCommandEvent& event);
void OnNew(wxCommandEvent& event);
void OnActivate(wxActivateEvent& event);
MyCanvas *canvas;
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
#define HELLO_QUIT 1
#define HELLO_NEW 2
wxDECLARE_APP(MyApp);
// Notice use of wxIMPLEMENT_APP_NO_MAIN() instead of the usual wxIMPLEMENT_APP!
wxIMPLEMENT_APP_NO_MAIN(MyApp);
#ifdef _UNICODE
// In Unicode build MFC normally requires to manually change the entry point to
// wWinMainCRTStartup() but to avoid having to modify the project options to do
// it we provide an adapter for it.
extern "C" int wWinMainCRTStartup();
int WINAPI WinMain(HINSTANCE, HINSTANCE, char *, int)
{
wWinMainCRTStartup();
}
#endif // _UNICODE
CMainWindow::CMainWindow()
{
LoadAccelTable( wxT("MainAccelTable") );
Create( NULL, wxT("Hello Foundation Application"),
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()
{
CString s = wxT("Hello, Windows!");
CPaintDC dc( this );
CRect rect;
GetClientRect( rect );
dc.SetTextAlign( TA_BASELINE | TA_CENTER );
dc.SetTextColor( ::GetSysColor( COLOR_WINDOWTEXT ) );
dc.SetBkMode(TRANSPARENT);
dc.TextOut( ( rect.right / 2 ), ( rect.bottom / 2 ),
s, s.GetLength() );
}
void CMainWindow::OnAbout()
{
CDialog about( wxT("AboutBox"), this );
about.DoModal();
}
void CMainWindow::OnTest()
{
wxMessageBox(wxT("This is a wxWidgets message box.\nWe're about to create a new wxWidgets frame."), wxT("wxWidgets"), wxOK);
wxGetApp().CreateFrame();
}
// CMainWindow message map:
// Associate messages with member functions.
//
// It is implied that the ON_WM_PAINT macro expects a member function
// "void OnPaint()".
//
// It is implied that members connected with the ON_COMMAND macro
// receive no arguments and are void of return type, e.g., "void OnAbout()".
//
BEGIN_MESSAGE_MAP( CMainWindow, CFrameWnd )
//{{AFX_MSG_MAP( CMainWindow )
ON_WM_PAINT()
ON_COMMAND( IDM_ABOUT, OnAbout )
ON_COMMAND( IDM_TEST, OnTest )
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
BOOL CTheApp::InitInstance()
{
if ( !CWinApp::InitInstance() )
return FALSE;
// TODO: cmd line parsing
WXDLLIMPEXP_BASE void wxSetInstance(HINSTANCE hInst);
wxSetInstance(m_hInstance);
wxApp::m_nCmdShow = m_nCmdShow;
int argc = 0;
wxChar **argv = NULL;
wxEntryStart(argc, argv);
if ( !wxTheApp || !wxTheApp->CallOnInit() )
return FALSE;
#if START_WITH_MFC_WINDOW
// Demonstrate creation of an initial MFC main window.
m_pMainWnd = new CMainWindow();
m_pMainWnd->ShowWindow( m_nCmdShow );
m_pMainWnd->UpdateWindow();
#else
// Demonstrate creation of an initial wxWidgets main window.
// Wrap wxWidgets window in a dummy MFC window and
// make the main window.
if (wxTheApp && wxTheApp->GetTopWindow())
{
m_pMainWnd = new CDummyWindow((HWND) wxTheApp->GetTopWindow()->GetHWND());
}
#endif
return TRUE;
}
int CTheApp::ExitInstance()
{
#if !START_WITH_MFC_WINDOW
delete m_pMainWnd;
#endif
if ( wxTheApp )
wxTheApp->OnExit();
wxEntryCleanup();
return CWinApp::ExitInstance();
}
// Override this to provide wxWidgets message loop compatibility
BOOL CTheApp::PreTranslateMessage(MSG *msg)
{
wxEventLoop * const
evtLoop = static_cast<wxEventLoop *>(wxEventLoop::GetActive());
if ( evtLoop && evtLoop->PreProcessMessage(msg) )
return TRUE;
return CWinApp::PreTranslateMessage(msg);
}
BOOL CTheApp::OnIdle(LONG lCount)
{
BOOL moreIdle = CWinApp::OnIdle(lCount);
if ( wxTheApp && wxTheApp->ProcessIdle() )
moreIdle = TRUE;
return moreIdle;
}
/*********************************************************************
* wxWidgets elements
********************************************************************/
bool MyApp::OnInit()
{
if ( !wxApp::OnInit() )
return false;
#if !START_WITH_MFC_WINDOW
// as we're not inside wxWidgets main loop, the default logic doesn't work
// in our case and we need to do this explicitly
SetExitOnFrameDelete(true);
(void) CreateFrame();
#endif
return true;
}
void MyApp::ExitMainLoop()
{
// instead of existing wxWidgets main loop, terminate the MFC one
::PostQuitMessage(0);
}
wxFrame *MyApp::CreateFrame()
{
MyChild *subframe = new MyChild(NULL, wxT("Canvas Frame"), wxPoint(10, 10), wxSize(300, 300),
wxDEFAULT_FRAME_STYLE);
subframe->SetTitle(wxT("wxWidgets canvas frame"));
// Give it a status line
subframe->CreateStatusBar();
// Make a menubar
wxMenu *file_menu = new wxMenu;
file_menu->Append(HELLO_NEW, wxT("&New MFC Window"));
file_menu->Append(HELLO_QUIT, wxT("&Close"));
wxMenuBar *menu_bar = new wxMenuBar;
menu_bar->Append(file_menu, wxT("&File"));
// Associate the menu bar with the frame
subframe->SetMenuBar(menu_bar);
int width, height;
subframe->GetClientSize(&width, &height);
MyCanvas *canvas = new MyCanvas(subframe, wxPoint(0, 0), wxSize(width, height));
canvas->SetCursor(wxCursor(wxCURSOR_PENCIL));
subframe->canvas = canvas;
subframe->Show(true);
// Return the main frame window
return subframe;
}
wxBEGIN_EVENT_TABLE(MyCanvas, wxScrolledWindow)
EVT_PAINT(MyCanvas::OnPaint)
EVT_MOUSE_EVENTS(MyCanvas::OnMouseEvent)
wxEND_EVENT_TABLE()
// Define a constructor for my canvas
MyCanvas::MyCanvas(wxWindow *parent, const wxPoint& pos, const wxSize& size)
: wxScrolledWindow(parent, -1, pos, size)
{
}
// Define the repainting behaviour
void MyCanvas::OnPaint(wxPaintEvent& WXUNUSED(event))
{
wxPaintDC dc(this);
dc.SetFont(* wxSWISS_FONT);
dc.SetPen(* wxGREEN_PEN);
dc.DrawLine(0, 0, 200, 200);
dc.DrawLine(200, 0, 0, 200);
dc.SetBrush(* wxCYAN_BRUSH);
dc.SetPen(* wxRED_PEN);
dc.DrawRectangle(100, 100, 100, 50);
dc.DrawRoundedRectangle(150, 150, 100, 50, 20);
dc.DrawEllipse(250, 250, 100, 50);
dc.DrawLine(50, 230, 200, 230);
dc.DrawText(wxT("This is a test string"), 50, 230);
}
// This implements a tiny doodling program! Drag the mouse using
// the left button.
void MyCanvas::OnMouseEvent(wxMouseEvent& event)
{
static long s_xpos = -1;
static long s_ypos = -1;
wxClientDC dc(this);
dc.SetPen(* wxBLACK_PEN);
wxPoint pos = event.GetPosition();
if (s_xpos > -1 && s_ypos > -1 && event.Dragging())
{
dc.DrawLine(s_xpos, s_ypos, pos.x, pos.y);
}
s_xpos = pos.x;
s_ypos = pos.y;
}
wxBEGIN_EVENT_TABLE(MyChild, wxFrame)
EVT_MENU(HELLO_QUIT, MyChild::OnQuit)
EVT_MENU(HELLO_NEW, MyChild::OnNew)
EVT_ACTIVATE(MyChild::OnActivate)
wxEND_EVENT_TABLE()
MyChild::MyChild(wxFrame *frame, const wxString& title, const wxPoint& pos, const wxSize& size, const long style)
: wxFrame(frame, -1, title, pos, size, style)
{
canvas = NULL;
}
MyChild::~MyChild()
{
if ( IsLastBeforeExit() )
PostQuitMessage(0);
}
void MyChild::OnQuit(wxCommandEvent& WXUNUSED(event))
{
Close(true);
}
void MyChild::OnNew(wxCommandEvent& WXUNUSED(event))
{
CMainWindow *mainWin = new CMainWindow();
mainWin->ShowWindow( TRUE );
mainWin->UpdateWindow();
}
void MyChild::OnActivate(wxActivateEvent& event)
{
if (event.GetActive() && canvas)
canvas->SetFocus();
}
// Dummy MFC window for specifying a valid main window to MFC, using
// a wxWidgets HWND.
CDummyWindow::CDummyWindow(HWND hWnd)
{
Attach(hWnd);
}
// Don't let the CWnd destructor delete the HWND
CDummyWindow::~CDummyWindow()
{
Detach();
}