Click here to Skip to main content
15,897,518 members
Articles / Desktop Programming / MFC

Wall Clock Control

Rate me:
Please Sign up or sign in to vote.
4.00/5 (14 votes)
12 Feb 20042 min read 99.7K   4.5K   43  
This article explains how to add a wall clock control to a dialog-based application.
// WallClockST.cpp : implementation file
//

#include "stdafx.h"
#include "AnalogClockDemo.h"
#include "WallClockST.h"
#include <afxwin.h>
#include <math.h>

#define SQUARESIZE			20
#define ID_TIMER_CLOCK		1

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// WallClockST

CWallClockST::CWallClockST()
{
	time = COleDateTime::GetCurrentTime ();
    m_nPrevSecond = time.GetSecond ();
    m_nPrevMinute = time.GetMinute ();
    m_nPrevHour = time.GetHour () % 12;
	sDate = time.Format("%d %b %Y");


    m_nSecond = time.GetSecond ();
    m_nMinute = time.GetMinute ();
    m_nHour = time.GetHour () % 12;

	m_nColor=RGB(0, 0, 0);
	m_dialClr = RGB(255,255,255);
	m_bkClr = RGB(81, 0, 0);
	m_tickClr = RGB(0, 0, 0);
	m_textClr = RGB(0, 0, 0);

	LoadColorSettings();
}

CWallClockST::~CWallClockST()
{
}


BEGIN_MESSAGE_MAP(CWallClockST, CStatic)
	//{{AFX_MSG_MAP(CWallClockST)
	ON_WM_TIMER()
	ON_WM_PAINT()
	ON_WM_CLOSE()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// WallClockST message handlers
BOOL bOnce = FALSE;
void CWallClockST::DrawClockFace (CDC* pDC)
{
	CRect rcDialog;
	GetClientRect(rcDialog);


	// This Creates area assigned to Dialog: This goes directly below the above in OnInitDialog
	if(m_rgn.m_hObject!=NULL)
		m_rgn.DeleteObject();

	m_rgn.CreateRoundRectRgn(0, 0, rcDialog.Width(), rcDialog.Height(),100,100);
	::SetWindowRgn(GetSafeHwnd(), (HRGN) m_rgn, TRUE);

	if(!bOnce)
		SetTimer(ID_TIMER_CLOCK,1000,NULL);
	
	static CPoint point[12] = {
        CPoint (   0,  450),    // 12 o'clock
        CPoint ( 225,  390),    //  1 o'clock
        CPoint ( 390,  225),    //  2 o'clock
        CPoint ( 450,    0),    //  3 o'clock
        CPoint ( 390, -225),    //  4 o'clock
        CPoint ( 225, -390),    //  5 o'clock
        CPoint (   0, -450),    //  6 o'clock
        CPoint (-225, -390),    //  7 o'clock
        CPoint (-390, -225),    //  8 o'clock
        CPoint (-450,    0),    //  9 o'clock
        CPoint (-390,  225),    // 10 o'clock
        CPoint (-225,  390),    // 11 o'clock
    };

    pDC->SelectStockObject (NULL_BRUSH);


	if(!bOnce)
	{
		CBrush mybrush(m_bkClr);
		pDC->SelectObject(&mybrush);
		pDC->RoundRect(-500,-500,500,500,100,100);
	}
	bOnce = TRUE;
	CBrush mybrush1(m_dialClr);
	pDC->SelectObject(&mybrush1);
	pDC->SetBkColor(m_dialClr);

	pDC->Ellipse(-450,-450,450,450);
	CString str="";
    CPen tickpen (PS_SOLID, 0, m_tickClr);
    CPen* pOldTickPen = pDC->SelectObject (&tickpen);
	for(int i=0;i<12;i++)
	{
		pDC->MoveTo(0,0);
		pDC->LineTo(point[i].x,point[i].y);
	}
	pDC->SelectObject(pOldTickPen);

    CPen pen (PS_SOLID, 0, m_dialClr);
    CPen* pOldPen = pDC->SelectObject (&pen);
	pDC->Ellipse(-400,-400,400,400);

	static CPoint point1[12] = {
        CPoint (   -25,  400),  // 12 o'clock
        CPoint ( 170,  340),    //  1 o'clock
        CPoint ( 290,  200),    //  2 o'clock
        CPoint ( 350,    28),    //  3 o'clock
        CPoint ( 300, -160),    //  4 o'clock
        CPoint ( 180, -270),    //  5 o'clock
        CPoint (  -10, -340),    //  6 o'clock
        CPoint (-180, -290),    //  7 o'clock
        CPoint (-320, -160),    //  8 o'clock
        CPoint (-380,    28),    //  9 o'clock
        CPoint (-340,  200),    // 10 o'clock
        CPoint (-200,  340),    // 11 o'clock
    };

	int val = 12;
	pDC->SetTextColor(m_textClr);
	for( i=0;i<12;i++)
	{
		str.Format("%d",val);

		val++;
		if(val>12)
			val=1;

		pDC->TextOut(point1[i].x,point1[i].y,str);
	}

	DrawDate(pDC,sDate,-200,-150,RGB(0,0,0));

}

void CWallClockST::DrawSecondHand (CDC* pDC, int nLength, int nScale, int nDegrees, COLORREF clrColor)
{
	CPoint point[2];
    double nRadians = (double) nDegrees * 0.017453292;

    point[0].x = (int) (nLength * sin (nRadians));
    point[0].y = (int) (nLength * cos (nRadians));

    point[1].x = -point[0].x / nScale;
    point[1].y = -point[0].y / nScale;

    CPen pen (PS_SOLID, 0, clrColor);
    CPen* pOldPen = pDC->SelectObject (&pen);

    pDC->MoveTo (point[0]);
    pDC->LineTo (point[1]);

    pDC->SelectObject (pOldPen);
}

void CWallClockST::DrawHand (CDC* pDC, int nLength, int nScale, int nDegrees, COLORREF clrColor)
{
	
	CPoint point[4];
    double nRadians = (double) nDegrees * 0.017453292;

    point[0].x = (int) (nLength * sin (nRadians));
    point[0].y = (int) (nLength * cos (nRadians));

    point[2].x = -point[0].x / nScale;
    point[2].y = -point[0].y / nScale;

    point[1].x = -point[2].y;
    point[1].y = point[2].x;

    point[3].x = -point[1].x;
    point[3].y = -point[1].y;

    CPen pen (PS_SOLID, 0, clrColor);
    CPen* pOldPen = pDC->SelectObject (&pen);

    pDC->MoveTo (point[0]);
    pDC->LineTo (point[1]);
    pDC->LineTo (point[2]);
    pDC->LineTo (point[3]);
    pDC->LineTo (point[0]);

	CRgn myrgn;
	myrgn.CreatePolygonRgn(point,4,ALTERNATE);
	CBrush mybrush(m_nColor);

	pDC->FillRgn(&myrgn,&mybrush);

    pDC->SelectObject (pOldPen);
}

void CWallClockST::OnPaint() 
{
	CRect rect;
    GetClientRect (&rect);

    CPaintDC dc (this);
    dc.SetMapMode (MM_ISOTROPIC);
    dc.SetWindowExt (1000, 1000);
    dc.SetViewportExt (rect.Width (), -rect.Height ());
    dc.SetViewportOrg (rect.Width () / 2, rect.Height () / 2);

    DrawClockFace (&dc);
    DrawHand (&dc, 275, 8, (m_nPrevHour * 30) +
        (m_nPrevMinute / 2), m_nColor);
    DrawHand (&dc, 400, 16, m_nPrevMinute * 6, m_nColor);
    DrawSecondHand (&dc, 400, 8, m_nPrevSecond * 6, m_nColor);
	bOnce = FALSE;
}

void CWallClockST::OnTimer(UINT nIDEvent) 
{
	time = COleDateTime::GetCurrentTime();

    int nSecond = time.GetSecond ();
    int nMinute = time.GetMinute ();
    int nHour = time.GetHour () % 12;

	sDate = time.Format("%d %b %Y");


    if ((nSecond == m_nPrevSecond) &&
        (nMinute == m_nPrevMinute) &&
        (nHour == m_nPrevHour))
        return;

    //
    // Center the origin and switch to the MM_ISOTROPIC mapping mode.
    //
    CRect rect;
    GetClientRect (&rect);

    CClientDC dc (this);
    dc.SetMapMode (MM_ISOTROPIC);
    dc.SetWindowExt (1000, 1000);
    dc.SetViewportExt (rect.Width (), -rect.Height ());
    dc.SetViewportOrg (rect.Width () / 2, rect.Height () / 2);
    //
    // If minutes have changed, erase the hour and minute hands.
    //
    COLORREF clrColor = ::GetSysColor (COLOR_3DFACE);

	clrColor = m_dialClr;

    if (nHour != m_nPrevHour)
	{
	    DrawHand (&dc, 275, 8, (m_nPrevHour * 30) + (m_nPrevMinute / 2), clrColor);
		m_nPrevHour=nHour;
	}
	
	if (nMinute != m_nPrevMinute) 
	{
        DrawHand (&dc, 275, 8, (m_nPrevHour * 30) + (m_nPrevMinute / 2),
            clrColor);
        DrawHand (&dc, 400, 16, m_nPrevMinute * 6, clrColor);
        m_nPrevMinute = nMinute;
        m_nPrevHour = nHour;
    }

    //
    // If seconds have changed, erase the second hand and redraw all hands.
    //
    if (nSecond != m_nPrevSecond) 
	{
        DrawSecondHand (&dc, 400, 8, m_nPrevSecond * 6, clrColor);
        DrawSecondHand (&dc, 400, 8, nSecond * 6, m_nColor);
        DrawHand (&dc, 200, 8, (nHour * 30) + (nMinute / 2),
            m_nColor);
        DrawHand (&dc, 400, 16, nMinute * 6, m_nColor);
        m_nPrevSecond = nSecond;
    }

	Invalidate();

	CStatic::OnTimer(nIDEvent);
}

void CWallClockST::OnClose() 
{
	KillTimer (ID_TIMER_CLOCK);
	CStatic::OnClose();
}

//Function to set hand color of the clock
void CWallClockST::SetHandColor(COLORREF color)
{
	m_nColor=color;
	SaveColorSettings();
	Invalidate();
}

//Function to retrieve hand color of the clock
COLORREF CWallClockST::GetHandColor()
{
	return m_nColor;
}

//Function to retrieve dial color of the clock
COLORREF CWallClockST::GetDialColor()
{
	return m_dialClr;
}

//Function to set dial color of the clock
void CWallClockST::SetDialColor(COLORREF color)
{
	m_dialClr=color;
	SaveColorSettings();
	Invalidate();
}

//Function to set tick color of the clock
void CWallClockST::SetTickColor(COLORREF color)
{
	m_tickClr=color;
	SaveColorSettings();
	Invalidate();
}

//Function to retrieve tick color of the clock
COLORREF CWallClockST::GetTickColor()
{
	return m_tickClr;
}

//Function to retrieve text color of the clock
COLORREF CWallClockST::GetTextColor()
{
	return m_textClr;
}

//Function to set text color of the clock
void CWallClockST::SetTextColor(COLORREF color)
{
	m_textClr=color;
	SaveColorSettings();
	Invalidate();
}

//Function to show date color of the clock
void CWallClockST::DrawDate(CDC *pDC, CString str, int x, int y, COLORREF color)
{
	pDC->SetBkColor(color);
	pDC->SetTextColor(RGB(255,255,255));

	pDC->TextOut(x,y,str);

}

//Function to set date/time of the clock
void CWallClockST::SetDateTime(COleDateTime dt)
{
	m_PrevDate = COleDateTime::GetCurrentTime();
	SYSTEMTIME st;
	dt.GetAsSystemTime(st);
	SetLocalTime(&st);

	Invalidate();
}

//Function to retrieve default date/time settings of the clock
void CWallClockST::ResetDate()
{
	SYSTEMTIME st;
	m_PrevDate.GetAsSystemTime(st);
	SetLocalTime(&st);
	Invalidate();
}

// Restarts the clock.
void CWallClockST::StartClock()
{
	SetTimer(ID_TIMER_CLOCK,1000,NULL);
}

//Stops the clock
void CWallClockST::StopClock()
{
	KillTimer(ID_TIMER_CLOCK);
}

// Function to save clock settings to the PC.
// The clock settings will be saved as a .sys file
// in the user's system directory.
void CWallClockST::SaveColorSettings()
{
	FILE *fp;
	char sPath[512];

	GetSystemDirectory(sPath,512);

	sprintf(sPath,"%s\\clkstng.sys",sPath);
	fp = fopen(sPath,"w");
	char encstr[512] = "";
	char temp[512] = "";

	char str[512];
	sprintf(str,"!%ld|%ld|%ld|%ld|%d@",m_bkClr,m_dialClr,m_nColor,m_tickClr,m_textClr);
	int i,j;

	for(i=0,j=strlen(str)-1;j>=0;i++,j--)
	{
		encstr[i] = str[j];
	}
	encstr[i] = '\0';

	for(i=0;i<(int)strlen(encstr);i++)
	{
		sprintf(temp,"%s%d#!@",temp,encstr[i]+2);
	}

	sprintf(encstr,"%s",temp);

	fprintf(fp,"%s",encstr);
	fclose(fp);
	
}

// Function to load clock settings to the PC.
void CWallClockST::LoadColorSettings()
{
	char str[512];
	char sPath[512];
	FILE *fp;

	GetSystemDirectory(sPath,512);

	sprintf(sPath,"%s\\clkstng.sys",sPath);
	fp = fopen(sPath,"r");

	if(fp==NULL)
	{
		SaveColorSettings();
		return;
	}

	fscanf(fp,"%s",str);

	fclose(fp);

	char decstr[255] = "";
	char temp[255] = "";
	char *res;
	int pos=0,len;
	int i,j;

	len = strlen(str);
	while(strcmp(str,"")!=0)
	{
		res = strstr(str,"#!@");
		pos = res - str + 1;
		strncpy(temp,str,pos-1);
		temp[pos-1]='\0';
		sprintf(decstr,"%s%c",decstr,atoi(temp)-2);
		sprintf(str,"");
		sprintf(temp,"");
		sprintf(str,"%s",res+3);
	}

	for(i=0,j=strlen(decstr)-1;j>=0;i++,j--)
	{
		temp[i] = decstr[j];
	}

	CString sData = temp;

	/* Background Color */
	pos = sData.Find("|",0);
	CString sTemp = sData.Mid(1,pos-1);
	m_bkClr = atol(sTemp.GetBuffer(sTemp.GetLength()));

	sData = sData.Right(sData.GetLength()-pos-1);

	/* Dial Color */
	pos = sData.Find("|",0);
	sTemp = sData.Mid(0,pos);
	m_dialClr = atol(sTemp.GetBuffer(sTemp.GetLength()));

	sData = sData.Right(sData.GetLength()-pos-1);

	/* Hand Color */
	pos = sData.Find("|",0);
	sTemp = sData.Mid(0,pos);
	m_nColor = atol(sTemp.GetBuffer(sTemp.GetLength()));

	sData = sData.Right(sData.GetLength()-pos-1);

	/* Tick Color */
	pos = sData.Find("|",0);
	sTemp = sData.Mid(0,pos);
	m_tickClr = atol(sTemp.GetBuffer(sTemp.GetLength()));

	sData = sData.Right(sData.GetLength()-pos-1);

	/* Text Color */
	pos = sData.Find("|",0);
	sTemp = sData.Mid(0,pos);
	m_textClr = atol(sTemp.GetBuffer(sTemp.GetLength()));
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
India India
I am currently working as Senior Software Engineer in a U.S.based Multi National Company. I have worked on projects related to various fields including Process Control, Security Solutions usng Biometrics, Artificial Intelligence etc.

I have developed many programs related to security solutions and embedded systems.

Comments and Discussions