void CGridButton::PreSubclassWindow()
{
// TODO: Add your specialized code here and/or call the base class
CButton::PreSubclassWindow();
}
void CGridButton::PreSubclassWindow()
{
ModifyStyle(NULL, BS_OWNERDRAW);
}
// Derived class is responsible for implementing all of these handlers
// for owner/self draw controls
void CButton::DrawItem(LPDRAWITEMSTRUCT)
{
ASSERT(FALSE);
}
#pragma once
class CUIElements
{
public:
CUIElements(void);
~CUIElements(void);
};
class CUIElements
{
private:
CUIElements() {};
CUIElements(const CUIElements&) {};
CUIElements& operator=(const CUIElements&) { return Instance(); };
~CUIElements() {};
CFont m_fntNumber;
public:
static CUIElements& Instance();
const CFont& GetNumberFont();
};
CUIElements& CUIElements::Instance()
{
//static means it is not to be destroyed once the function exits, to be shared across all instances of this class
static CUIElements inst;
return inst;
}
const CFont& CUIElements::GetNumberFont()
{
if(m_fntNumber.GetSafeHandle() == NULL)
{
//font not yet created - create it now
//Obtain a DC (Device Context) for the screen
HDC hDC = ::GetDC(NULL);
int iLogPixelsY = GetDeviceCaps(hDC, LOGPIXELSY);
::ReleaseDC(NULL, hDC);
LOGFONT logFont;
memset( &logFont, 0, sizeof(logFont));
//24 point bold, arial font
_tcscpy_s(logFont.lfFaceName, LF_FACESIZE, _T("Arial"));
logFont.lfHeight = -MulDiv(24, iLogPixelsY, 72);
logFont.lfWeight = FW_BOLD;
logFont.lfUnderline = false;
logFont.lfItalic = false;
m_fntNumber.CreateFontIndirect(&logFont);
}
//Safety - check it has been created
ASSERT(m_fntNumber.GetSafeHandle());
return m_fntNumber;
}
void CGridButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
ASSERT(lpDrawItemStruct->CtlType == ODT_BUTTON);
//Get an instance of the singleton - for the font
CUIElements& instUI = CUIElements::Instance();
//Get the button text - if any to display
CString szText;
if(GetValue() > 0)
szText.Format("%d", GetValue());
//Obtain an MFC device context - less typing for the next steps
CDC dc;
dc.Attach(lpDrawItemStruct->hDC);
//Perform a save of the state, we will be manipulating it, this allows one line of code to restore the state later
int iSaveDC = dc.SaveDC();
//Draw a simple rectangle, if button has the focus then draw another just inside the first
CRect rc(lpDrawItemStruct->rcItem);
if (lpDrawItemStruct->itemState & ODS_FOCUS)
{
dc.Rectangle(&rc);
rc.DeflateRect(1, 1);
dc.Rectangle(&rc);
}
else
dc.Rectangle(rc.left, rc.top, rc.right, rc.bottom);
//if there is a number to display then we display it
if(GetValue() > 0)
{
//Display a locked cell in a different colour
if(m_bLock)
{
rc.DeflateRect(1, 1);
dc.FillSolidRect(&rc, m_clrLockedCell);
}
dc.SelectObject(instUI.GetNumberFont());
// Draw the button text using the text color blue (or red - if invalid and grid is filled)
COLORREF clr = (m_bValid ? RGB(0,0,255) : RGB(255,0,0));
dc.SetTextColor(clr);
//If locked then we need to set the background colour - else it looks ghastly
if(m_bLock)
dc.SetBkColor(m_clrLockedCell);
dc.DrawText(szText, &rc, DT_SINGLELINE|DT_VCENTER|DT_CENTER);
}
else
{
//Draw hint
}
//restore the state of the dc to the original
dc.RestoreDC(iSaveDC);
//We don't require the dc any more, release it
dc.Detach();
}
private:
bool m_bValid;
static const COLORREF m_clrLockedCell;
public:
void SetValid(bool bFlag) { m_bValid = bFlag; };
#include "GridButton.h"
#include "UIElements.h"
const COLORREF CGridButton::m_clrLockedCell = RGB(192, 192, 192);
, m_bLock(false)
, m_bValid(true)
m_arWndButtons[row * 9 + col].SetLock();
m_arWndButtons[row * 9 + col].SetValid(true);
Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.
Comments (0)