First: C++ Using MFC

C++ programs that use the Microsoft Foundation Class (MFC) application framework can be easily created with Fastgraph's MFC AppWizard for Visual C++ 5.0 or later. To use Fastgraph's MFC AppWizard, copy the file FGwiz.awx from the Fastgraph utilities directory to your Visual C++ Template directory. Once installed, "Fastgraph MFC AppWizard" will be one of the options listed when you create a new Visual C++ project. If you wish to uninstall the AppWizard, just delete FGwiz.awx from the Template directory.

MFC programs consist of application and window class declarations (both derived from MFC base classes), a global application object, message response functions (event handlers), and possibly your own additional functions. Like programs that use the Windows API, MFC programs have a WinMain() function, a WindowProc() function, and a message loop, but they are hidden inside MFC.

Our first example is a single-window program without a menu (such programs are called simple frame window applications in MFC). For this example, Fastgraph's MFC AppWizard created First.cpp, First.h, MainFrame.cpp, MainFrame.h, and other files. First.cpp instantiates the application object theApp from the CFirstApp class (CFirstApp is derived from MFC's CWinApp base class). MainFrame.cpp contains "canned" message response functions for the Windows events we typically must handle in a Fastgraph program. We can, of course, modify these message response functions as needed.

On program startup, Windows calls MFC's built-in WinMain() function, which in turn calls the CFirstApp::InitInstance() and CWinApp::Run() member functions. The CFirstApp::InitInstance() function instantiates the frame window object pFrame from the CMainFrame class (CMainFrame is derived from MFC's CFrameWnd base class). The pFrame object's Create() member function creates the program's main window (this also generates the WM_CREATE message), while its ShowWindow() and UpdateWindow() member functions initially display and paint the main window. CWinApp::Run() is hidden in MFC's CWinApp base class and implements the Windows message loop. The message loop retrieves messages Windows sends to the program and in turn sends these to the message response functions for processing. The message loop executes until the user exits the program. Here is the First.cpp file for our first example program:

/****************************************************************************\
*                                                                            *
*  First.cpp                                                                 *
*                                                                            *
*  This is the first Fastgraph for Windows example program. It demonstrates  *
*  tasks common to most Fastgraph for Windows programs and serves as a       *
*  template for building the other examples.                                 *
*                                                                            *
\****************************************************************************/
// First.cpp : Defines the class behaviors for the application.
//
#include "stdafx.h"
#include "First.h"
#include "MainFrame.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CFirstApp
BEGIN_MESSAGE_MAP(CFirstApp, CWinApp)
   //{{AFX_MSG_MAP(CFirstApp)
   //}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CFirstApp construction
CFirstApp::CFirstApp()
{
}
/////////////////////////////////////////////////////////////////////////////
// The one and only CFirstApp object
CFirstApp theApp;
/////////////////////////////////////////////////////////////////////////////
// CFirstApp initialization
BOOL CFirstApp::InitInstance()
{
   // Standard initialization
   // Change the registry key under which our settings are stored.
   SetRegistryKey(_T("Local AppWizard-Generated Applications"));
   m_pMainWnd = NULL;
   CMainFrame* pFrame = new CMainFrame;
   if (!pFrame->Create(NULL,"First Fastgraph for Windows Program"))
      return FALSE;
   m_pMainWnd = pFrame;
   pFrame->ShowWindow(m_nCmdShow);
   pFrame->UpdateWindow();
   return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CFirstApp message handlers

The message response functions, where most of the action takes place, provide our first look at some Fastgraph functions. Note that our program does not explicitly call the message response functions. Instead, they are called by CWinApp::Run() in response to events such as creating or resizing the window. Our program's MainFrame.cpp file includes message response functions for the WM_CREATE, WM_PAINT, WM_SETFOCUS, WM_SIZE, and WM_DESTROY messages, among others. MainFrame.cpp is shown here:

// MainFrame.cpp : implementation of the CMainFrame class
//
#include "stdafx.h"
#include "First.h"
#include "MainFrame.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CMainFrame
IMPLEMENT_DYNAMIC(CMainFrame, CFrameWnd)
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
   //{{AFX_MSG_MAP(CMainFrame)
   ON_WM_SIZE()
   ON_WM_SETFOCUS()
   ON_WM_QUERYNEWPALETTE()
   ON_WM_PALETTECHANGED()
   ON_WM_PAINT()
   //}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CMainFrame construction/destruction
CMainFrame::CMainFrame()
{
   m_hDC = NULL;
   m_hPal = NULL;
   m_hVB = -1;
   m_cxClient = 0;
   m_cyClient = 0;
}
CMainFrame::~CMainFrame()
{
   if (m_hVB >= 0)
   {
      fg_vbclose();
      fg_vbfree(m_hVB);
   }
   fg_vbfin();
   if (m_hPal)
   {
      DeleteObject(m_hPal);
      m_hPal = NULL;
   }
   if (m_hDC)
   {
      ::ReleaseDC(m_hWnd, m_hDC);
      m_hDC = NULL;
   }
}
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
   if (!CFrameWnd::PreCreateWindow(cs))
      return FALSE;
   cs.style = WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE;
   cs.dwExStyle &= ~WS_EX_CLIENTEDGE;
   cs.lpszClass = AfxRegisterWndClass(CS_OWNDC|CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS,
      LoadCursor(NULL,IDC_ARROW), NULL, NULL);
   return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CMainFrame diagnostics
#ifdef _DEBUG
void CMainFrame::AssertValid() const
{
   CFrameWnd::AssertValid();
}
void CMainFrame::Dump(CDumpContext& dc) const
{
   CFrameWnd::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CMainFrame message handlers
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
   BOOL bRet = CFrameWnd::OnCreateClient(lpcs, pContext);
   if (bRet)
   {
      m_hDC = ::GetDC(m_hWnd);
      fg_setdc(m_hDC);
      m_hPal = fg_defpal();
      fg_realize(m_hPal);
      fg_vbinit();
      m_hVB = fg_vballoc(640,480);
      fg_vbopen(m_hVB);
      fg_vbcolors();
      fg_setcolor(19);
      fg_fillpage();
   }
   return bRet;
}
void CMainFrame::OnPaint()
{
   CPaintDC dc(this); // device context for painting
   fg_vbscale(0,fg_getmaxx(),0,fg_getmaxy(),0,m_cxClient-1,0,m_cyClient-1);
}
void CMainFrame::OnSize(UINT, int cx, int cy)
{
   m_cxClient = cx;
   m_cyClient = cy;
}
void CMainFrame::OnSetFocus(CWnd* pOldWnd)
{
   OnQueryNewPalette();
}
BOOL CMainFrame::OnQueryNewPalette()
{
   fg_realize(m_hPal);
   Invalidate();
   return TRUE;
}
void CMainFrame::OnPaletteChanged(CWnd* pFocusWnd)
{
   if ((pFocusWnd != this) && (!IsChild(pFocusWnd)))
      OnQueryNewPalette();
}

Windows generates a WM_CREATE message when it first creates the program's window. Only one WM_CREATE message typically occurs per program instance, so it is a good place for any application-specific initialization code. In an MFC program, the CMainFrame::OnCreateClient() message response function serves as the WM_CREATE handler. Our OnCreateClient() function begins by calling the base class OnCreateClient() function:

BOOL bRet = CFrameWnd::OnCreateClient(lpcs, pContext);

If successful, it calls the Windows API function GetDC() to obtain a device context to the window's client area, and then fg_setdc() to make the device context available to other Fastgraph functions:

m_hDC = ::GetDC(m_hWnd);
fg_setdc(m_hDC);

Note how we use the :: global scope resolution operator to guarantee that we call the Windows API version of GetDC(). We'll use this technique whenever we call a Windows API function in an MFC program. Next, CMainFrame::OnCreateClient() creates and realizes the default logical palette:

m_hPal = fg_defpal();
fg_realize(m_hPal);

CMyWindow::OnCreate() then initializes Fastgraph's virtual buffer environment, creates a 640x480 virtual buffer and makes it the active virtual buffer, and assigns the logical palette colors to the virtual buffer:

fg_vbinit();
m_hVB = fg_vballoc(640,480);
fg_vbopen(m_hVB);
fg_vbcolors();

Finally, we fill the virtual buffer with blue pixels (color 19 is blue when using Fastgraph's default 256-color virtual buffers with the default logical palette):

fg_setcolor(19);
fg_fillpage();

Windows generates a WM_PAINT message when the window's client area must be repainted. In an MFC program, the CMainFrame::OnPaint() message response function serves as the WM_PAINT handler. Our CMainFrame::OnPaint() function does little more than call fg_vbscale() to display the contents of the 640x480 virtual buffer scaled to the size of the client area.

Windows generates a WM_SETFOCUS message when the window gains the input focus. This most often happens when the window becomes the active or top-level window. In an MFC program, the CMainFrame::OnSetFocus() message response function serves as the WM_SETFOCUS handler. Our CMainFrame::OnSetFocus() function merely calls CMainFrame::OnQueryNewPalette(), which first calls fg_realize() to activate the program's logical palette (in case another program has changed the logical palette colors), then calls the Invalidate() member function to force a WM_PAINT message to redraw the client area.

Windows generates a WM_SIZE message whenever the size of the window changes, and also upon creation of a window. In an MFC program, the CMainFrame::OnSize() message response function serves as the WM_SIZE handler. Our CMainFrame::OnSize() function simply saves the new width and height of the client area (in pixels) in the member variables m_cxClient and m_cyClient. These quantities are passed to fg_vbscale() in CMainFrame::OnPaint().

Windows generates a WM_DESTROY message after removing a window to signal a program exit. In an MFC program, the CMainFrame destructor serves as the WM_DESTROY handler. The destructor first closes the virtual buffer, releases its memory, and terminates virtual buffer processing:

if (m_hVB >= 0)
{
   fg_vbclose();
   fg_vbfree(m_hVB);
}
fg_vbfin();

It then calls the DeleteObject() member function to delete the logical palette created with fg_defpal(), and the Windows API function ReleaseDC() to release the device context created with GetDC():

if (m_hPal)
{
   DeleteObject(m_hPal);
   m_hPal = NULL;
}
if (m_hDC)
{
   ::ReleaseDC(m_hWnd, m_hDC);
   m_hDC = NULL;
}

<< Prev

Next >>

Contents
Fastgraph Home Page

 

copyright 2001 Ted Gruber Software, Inc.