I have built a simple Graphic Framework using Win32 API functions. The framework includes a common dialog which is all the parent class of all the drawing window. It has a OnPaintBackground and OnPaint method which can be overridden to draw custom things. Below is the detail code snippets.
The basic base class
BasicDialog.h:
#pragma once
#include <Windows.h>
#include <WinUser.h>
#include <map>
#include "resource.h"
class CBasicDialog
{
public:
CBasicDialog(HWND hParent, LPCTSTR lpTemplate = NULL);
virtual ~CBasicDialog(void);
static void Init(HINSTANCE instance);
static void Release();
static CBasicDialog* GetCurrentDialog();
void Show();
protected:
virtual LRESULT DialogProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam);
virtual void InitDialog();
virtual void OnResize();
virtual void OnPaintBackground(HDC dc);
virtual void OnPaint(HDC dc);
COLORREF m_cBackColor;
HWND m_hWnd;
RECT m_rClientRectangle;
private:
static LRESULT CALLBACK WinProc(HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam);
static const COLORREF WHITE_COLOR = RGB(255,255,255);
static std::map<HWND,CBasicDialog*> Dialogs;
static CBasicDialog* CurrentDialog;
static HINSTANCE HInstance;
};
BasicDialog.cpp:
#include "BasicDialog.h"
CBasicDialog::CBasicDialog(HWND hParent, LPCTSTR lpTemplate) : m_cBackColor(RGB(255, 0, 0))
{
if(HInstance)
{
if(lpTemplate == NULL)
lpTemplate = MAKEINTRESOURCE(IDD_DIALOG_BASIC);
m_hWnd = CreateDialog(HInstance,lpTemplate, hParent, (DLGPROC)WinProc);
if(GetWindowRect(m_hWnd, &m_rClientRectangle))
{
m_rClientRectangle.left = 0;
m_rClientRectangle.right = 0;
m_rClientRectangle.top = 0;
m_rClientRectangle.bottom = 0;
}
if(m_hWnd && NULL == CurrentDialog)
{
CurrentDialog = this;
Dialogs[m_hWnd] = this;
}
}
}
CBasicDialog::~CBasicDialog(void)
{
}
void CBasicDialog::Show()
{
ShowWindow(m_hWnd, SW_SHOW);
UpdateWindow(m_hWnd);
}
void CBasicDialog::InitDialog()
{
//Do something here to initialize the dialog
}
void CBasicDialog::OnResize()
{
//Do something here to adjust the layout.
}
LRESULT CBasicDialog::DialogProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
switch(uMsg)
{
case WM_INITDIALOG:
this->InitDialog();
break;;
case WM_SHOWWINDOW:
GetWindowRect(m_hWnd, &m_rClientRectangle);
break;
case WM_SIZE:
GetWindowRect(m_hWnd, &m_rClientRectangle);
this->OnResize();
break;
case WM_ERASEBKGND:
RedrawWindow(m_hWnd, NULL, NULL, RDW_INVALIDATE);
break;
case WM_MOVE:
GetWindowRect(m_hWnd, &m_rClientRectangle);
break;
case WM_PAINT:
if(m_hWnd)
{
PAINTSTRUCT ps;
HDC dc = BeginPaint(m_hWnd,&ps);
this->OnPaintBackground(dc);
this->OnPaint(dc);
EndPaint(m_hWnd,&ps);
}
break;
case WM_CLOSE:
if(m_hWnd)
{
CloseWindow(m_hWnd);
}
break;
default:
break;
}
return FALSE;
}
void CBasicDialog::OnPaintBackground(HDC dc)
{
//Draw custom background here
}
void CBasicDialog::OnPaint(HDC dc)
{
//Draw some custom graphics here
}
HINSTANCE CBasicDialog::HInstance = NULL;
CBasicDialog* CBasicDialog::CurrentDialog = NULL;
std::map<HWND,CBasicDialog*> CBasicDialog::Dialogs;
CBasicDialog* CBasicDialog::GetCurrentDialog()
{
return CurrentDialog;
}
LRESULT CALLBACK CBasicDialog::WinProc(HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
if(uMsg == WM_ACTIVATE && wParam == WA_ACTIVE)
CurrentDialog = Dialogs[hwnd];
if(CurrentDialog)
{
CurrentDialog->DialogProc(hwnd, uMsg, wParam, lParam);
}
return FALSE;
}
void CBasicDialog::Init(HINSTANCE instance)
{
HInstance = instance;
}
void CBasicDialog::Release()
{
}
A simple child class
MyDialog.h
#pragma once
#include "basicdialog.h"
class CMyDialog :
public CBasicDialog
{
public:
CMyDialog(HWND hParent, LPCTSTR lpTemplate = NULL);
virtual ~CMyDialog(void);
protected:
virtual void OnPaintBackground(HDC dc);
virtual void OnPaint(HDC dc);
};
MyDialog.cpp:
#include "MyDialog.h"
CMyDialog::CMyDialog(HWND hParent, LPCTSTR lpTemplate) : CBasicDialog(hParent,lpTemplate)
{
}
CMyDialog::~CMyDialog(void)
{
}
void CMyDialog::OnPaintBackground(HDC dc)
{
RECT r;
r.left = r.top = 0;
r.right = m_rClientRectangle.right - m_rClientRectangle.left;
r.bottom = m_rClientRectangle.bottom - m_rClientRectangle.top;
HBRUSH hBackBrush = CreateSolidBrush(m_cBackColor);
FillRect(dc, &r, hBackBrush);
DeleteObject(hBackBrush);
}
void CMyDialog::OnPaint(HDC dc)
{
//Do some custom painting here.
HPEN hPen, hPenOld;
HBRUSH hBrush, hBrushOld;
//Initial colors
BYTE bRed = 0;
BYTE bGreen = 0;
BYTE bBlue = 0;
//Pen color
COLORREF cPen = RGB(bRed, bGreen, bBlue);
//Set the brush color based on the pen color. It is purple partial to blue.
COLORREF cBrush = RGB(233,GetGValue(cPen), 255);
//Create the pen.
hPen = CreatePen(PS_SOLID, 10, cPen);
//Create the brush.
hBrush = CreateSolidBrush(cBrush);
//Select the pen and brush. Just like set the drawing arguments.
hPenOld = (HPEN)SelectObject(dc, hPen);
hBrushOld = (HBRUSH)SelectObject(dc, hBrush);
//Draw a triangle
MoveToEx(dc, 30, 10, NULL);
LineTo(dc, 10, 50);
LineTo(dc, 50, 50);
LineTo(dc, 30, 10);
//Use the old pen
SelectObject(dc,hPenOld);
//Draw and fill an ellipse
Ellipse(dc, 10, 60, 110, 160);
//Release the resources
DeleteObject(hPen);
SelectObject(dc, hBrushOld);
DeleteObject(hBrush);
}
Testing code and the main function
main.cpp:
#include "MyDialog.h"
BOOL InitApplication(HINSTANCE hInstance);
BOOL InitMainWindow(HINSTANCE hInstance, HWND* pWnd);
LRESULT CALLBACK MainWindowProc(HWND hwnd,
UINT uMsg,WPARAM wParam,LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
HWND mainWindow;
if(!InitApplication(hInstance))
return FALSE;
if(!InitMainWindow(hInstance, &mainWindow))
return FALSE;
ShowWindow(mainWindow,nCmdShow);
UpdateWindow(mainWindow);
CBasicDialog::Init(hInstance);
CMyDialog mainDialog(mainWindow);
mainDialog.Show();
MSG msg;
BOOL fGotMessage;
while((fGotMessage = GetMessage(&msg, NULL, 0, 0)) != 0 && fGotMessage != -1)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
CBasicDialog::Release();
return msg.wParam;
}
BOOL InitApplication(HINSTANCE hInstance)
{
WNDCLASSEX wcx;
wcx.cbSize = sizeof(wcx);
wcx.style = CS_HREDRAW | CS_VREDRAW;
wcx.lpfnWndProc = MainWindowProc;
wcx.cbClsExtra = 0;
wcx.cbWndExtra = 0;
wcx.hInstance = hInstance;
wcx.hIcon = LoadIcon(NULL,MAKEINTRESOURCE(IDI_ICON_MAIN_WINDOW));
wcx.hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_NODROP));
wcx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wcx.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);
wcx.lpszClassName = L"MainClass";
wcx.hIconSm = (HICON)LoadImage(hInstance,
MAKEINTRESOURCE(IDI_ICON_MAIN_WINDOW),
IMAGE_ICON,
GetSystemMetrics(SM_CXSMICON),
GetSystemMetrics(SM_CYSMICON),
LR_DEFAULTCOLOR);
return RegisterClassEx(&wcx);
}
BOOL InitMainWindow(HINSTANCE hInstance, HWND* pWnd)
{
HWND hwnd;
hwnd = CreateWindow(
TEXT("MainClass"),
TEXT("Main Window"),
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_POPUPWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
800,
600,
NULL,
LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MENU1)),
hInstance,
NULL);
*pWnd = hwnd;
if(!hwnd)
return FALSE;
return TRUE;
}
LRESULT CALLBACK MainWindowProc(HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
switch(uMsg)
{
case WM_CREATE:
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
break;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}