不用位圖文件的電子鐘錶
實現步驟:
1 把CGCColorStatic.h/cpp和GCClock.h/cpp加入到工程中
2 在StaticDigitalClock2Dlg.h中添加
#include "GCClock.h"
3 添加如圖所示的控件,併爲第一個單選按鈕IDC_RADIO_12HOURS添加一個變量
int m_iFormat;
4 在StaticDigitalClock2Dlg.h中添加
private:
CGCClock m_Clock;
CGCClock m_StyleExampleA;
CGCClock m_StyleExampleB;
CGCClock m_StyleExampleC;
CGCClock m_StyleExampleD;
5 在構造函數中加入
m_iFormat = 0;
在DoDataExchange(CDataExchange* pDX)的
//{{AFX_DATA_MAP(CStaticDigitalClock2Dlg)上面增加:
DDX_Control(pDX, IDC_STATIC_CLOCK, m_Clock);
DDX_Control(pDX, IDC_STATIC_STYLE_EXA, m_StyleExampleA);
DDX_Control(pDX, IDC_STATIC_STYLE_EXB, m_StyleExampleB);
DDX_Control(pDX, IDC_STATIC_STYLE_EXC, m_StyleExampleC);
DDX_Control(pDX, IDC_STATIC_STYLE_EXD, m_StyleExampleD);
6 在OnInitDialog()中加入:
// TODO: Add extra initialization here
m_StyleExampleA.SetOn(TRUE);
m_StyleExampleA.SetTextOffColor(RGB(0,180,255));
m_StyleExampleA.SetBackgroundOffColor(RGB(0,0,0));
m_StyleExampleA.SetBold();
m_StyleExampleA.SetSunken();
m_StyleExampleA.SetPointFont(12,"Comic Sans MS");
m_StyleExampleA.Start();
m_StyleExampleB.SetOn(FALSE);
m_StyleExampleB.SetTextOffColor(RGB(255,255,255));
m_StyleExampleB.SetPointFont(11,"Times New Roman");
// m_StyleExampleB.SetBold();
m_StyleExampleB.SetColorFrame(TRUE,2,RGB(190,0,0));
m_StyleExampleB.Start();
m_StyleExampleC.SetOn(FALSE);
m_StyleExampleC.SetTextOffColor(RGB(0,0,255));
m_StyleExampleC.SetBackgroundOffColor(RGB(0,0,0));
m_StyleExampleC.SetBold();
m_StyleExampleC.SetSunken();
m_StyleExampleC.SetPointFont(12,"幼圓");
m_StyleExampleC.Start();
m_StyleExampleD.SetOn(FALSE);
m_StyleExampleD.SetTextOffColor(RGB(0,255,0));
m_StyleExampleD.SetBackgroundOffColor(RGB(0,0,0));
m_StyleExampleD.SetBold();
m_StyleExampleD.SetSunken();
m_StyleExampleD.SetPointFont(12,"楷體GB2312");
m_StyleExampleD.Start();
m_Clock.SetOn(FALSE);
m_Clock.SetTextOffColor(RGB(0,180,255));
m_Clock.SetBackgroundOffColor(RGB(0,0,50));
m_Clock.SetBold();
m_Clock.SetPointFont(9,"Arial");
m_Clock.SetModalFrame();
m_Clock.Start();
7 寫單選按鈕響應函數
void CStaticDigitalClock2Dlg::OnRadio12hours()
...{
m_Clock.Format();
}
void CStaticDigitalClock2Dlg::OnRadio24hours()
...{
m_Clock.Format(TRUE);
}
8 附相關代碼:
CGCClock::CGCClock() : CGCColorStatic()
...{
m_b24hr = FALSE;
m_uiHour = 0;
m_uiMinutes = 0;
m_bAlarmSet = FALSE;
m_bAlarmRunning = FALSE;
m_bAlarmActivated = FALSE;
}
CGCClock::~CGCClock()
...{
}
BEGIN_MESSAGE_MAP(CGCClock, CGCColorStatic)
ON_WM_TIMER()
END_MESSAGE_MAP()
void CGCClock::OnTimer(UINT nIDEvent)
...{
// The CGCClock class is derived from the CGCColorStatic class.
// Since the CGCColorStatic class provides the capability to flash the background
// or text using timer events, we must distinguish between CGCColorStatic timer events
// and the CGCClock's clock update timer event. Verify that the current timer
// event is the CGCClock class' update event. If it isn't route it on to the
// parent class' OnTimer() event handler because that may be one of the
// CGCColorStatic class' flashing timer events.
if (nIDEvent != CLOCK_UPDATE_TIMER_ID) CGCColorStatic::OnTimer(nIDEvent);
// If we are here then the current timer event is the clock's update event.
// Get the current time.
GetLocalTime(&m_CurrentDateTime);
// Format it for display.
FormatTime();
// Display the time.
SetWindowText(m_FormattedTime);
// If it is time for the alarm, initiate flashing of the background
// by calling the inherited FlashBackground() method.
if ( (!m_bAlarmRunning) && m_bAlarmSet && m_bAlarmActivated &&
( (m_CurrentDateTime.wHour >= m_uiHour)
&&
(m_CurrentDateTime.wMinute >= m_uiMinutes)
)
)
...{
FlashBackground(TRUE,FALSE,1);
m_bAlarmRunning = TRUE;
// Here is where you would add sound for the alarm.
}
}
void CGCClock::FormatTime()
...{
if (m_b24hr)
m_FormattedTime.Format("%02d:%02d:%02d",
m_CurrentDateTime.wHour,
m_CurrentDateTime.wMinute,
m_CurrentDateTime.wSecond);
else
...{
if (m_CurrentDateTime.wHour > 12)
...{
UINT th;
th = m_CurrentDateTime.wHour - 12;
m_FormattedTime.Format("%2d:%02d:%02d p.m.",
th,
m_CurrentDateTime.wMinute,
m_CurrentDateTime.wSecond);
}
else
m_FormattedTime.Format("%d:%02d:%02d p.m.",
m_CurrentDateTime.wHour,
m_CurrentDateTime.wMinute,
m_CurrentDateTime.wSecond);
}
}
BOOL CGCClock::Start()
...{
GetLocalTime(&m_CurrentDateTime);
FormatTime();
SetWindowText(m_FormattedTime);
UINT id = this->SetTimer(CLOCK_UPDATE_TIMER_ID,1000,NULL);
if (id == 0) return FALSE;
return TRUE;
}
void CGCClock::Format(const BOOL bTwentyFourHour)
...{
m_b24hr = bTwentyFourHour;
FormatTime();
SetWindowText(m_FormattedTime);
}
void CGCClock::GetAlarmTime(UINT &Hour, UINT &Minutes, BOOL& Active) const
...{
Hour = m_uiHour;
Minutes = m_uiMinutes;
Active = m_bAlarmRunning;
}
BOOL CGCClock::SetAlarm(const UINT Hour, const UINT Minutes)
...{
if ( Hour <= 0 ) return FALSE;
m_bAlarmSet = TRUE;
if (m_bAlarmRunning)
...{
// Since we are setting a new alarm time, kill the current alarm
// if it is active (going off).
FlashBackground(FALSE,FALSE);
m_bAlarmRunning = FALSE;
}
m_uiHour = Hour;
m_uiMinutes = Minutes;
return TRUE;
}
BOOL CGCClock::ActivateAlarm(const BOOL bOn)
...{
BOOL prev = m_bAlarmActivated;
m_bAlarmActivated = bOn;
return prev;
}
CGCColorStatic::CGCColorStatic(const BOOL bOn)
...{
m_bBackgroundOn = bOn; // Set initial bacground state.
m_bTextOn = bOn; // Set initial text state.
m_bColorFrameFlag = FALSE; // Is a color frame displayed?
m_ColorFrameWidth = 2; // At what width is the color frame to be displayed, if displayed?
// Initialize default on/off color variables.
m_CurrentBackgroundOnColor = DEFAULT_BACKGROUND_ON_COLOR;
m_CurrentBackgroundOffColor = DEFAULT_BACKGROUND_OFF_COLOR;
m_CurrentTextOnColor = DEFAULT_TEXT_ON_COLOR;
m_CurrentTextOffColor = DEFAULT_TEXT_OFF_COLOR;
m_ColorFrameColor = DEFAULT_BACKGROUND_OFF_COLOR;
// Create default background ON brush.
m_brOnBrush.CreateSolidBrush(m_CurrentBackgroundOnColor);
// Create default background OFF brush.
m_brOffBrush.CreateSolidBrush(m_CurrentBackgroundOffColor);
// m_brOffBrush.CreateSolidBrush(GetSysColor(COLOR_3DFACE));
m_FlashTypeFlag = NONE; // Default to not flashing.
m_bTimerFlag = FALSE; // Indicates if a flashing Timer exists or not.
m_uiTimerID = 0;
m_bHatchMode = FALSE; // Is the background in hatch pattern mode?
m_iHatchType = -1; // Initialize hatch pattern.
// Initialize variables used for Asymmetrical Background Flashing
m_fOnDuration = 0.0;
m_fOffDuration = 0.0;
// Initialize variables used for Pulsed Background Flashing
m_pulseDuration = 0.0;
m_pulseRep = 0;
m_pulseOnDuration = 0.0;
m_pulseCounter = 0;
}
CGCColorStatic::~CGCColorStatic()
...{
m_brOnBrush.DeleteObject();
m_brOffBrush.DeleteObject();
}
BEGIN_MESSAGE_MAP(CGCColorStatic, CStatic)
ON_MESSAGE( WM_GECCOLORSTATIC_DRAWFRAME, OnDrawFrame )
//{{AFX_MSG_MAP(CGCColorStatic)
ON_WM_CTLCOLOR_REFLECT()
ON_WM_TIMER()
ON_WM_NCPAINT()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/**//////////////////////////////////////////////////////////////////////////////
// CGCColorStatic message handlers
// ****************************************************************************
// ****************************************************************************
// CGCColorStatic::CtlColor()
// Handles the appropriate colors when the control is repainted on screen
//
// REMEMBER
//
// If you handle WM_CTLCOLOR messages in your parent window (the window that
// contains this control) you must be sure to call the parent window's base
// class OnCtlColor() handler if the parent's OnCtlColor() handler is being
// called for this control. Otherwise, the OnCtlColor() handler in the
// parent window will OVERRIDE the OnCtlColor() handler for this control.
//
// Windows is designed that way to give the parent a shot at handling the
// message before reflecting it back to this control.
// ****************************************************************************
HBRUSH CGCColorStatic::CtlColor(CDC* pDC, UINT nCtlColor)
...{
#ifdef _DEBUG
CtlColorCount += 1;
_CrtDbgReport(_CRT_WARN,"GCColorStatic.cpp",__LINE__,"Demo"," %s %d ",">>>>>>>>> CtlColor() called.",CtlColorCount);
#endif
// Set the Text Color according to the control's state.
// It is not necessary to utilize the nCtlColor parameter in this implementation.
if (m_bTextOn)
pDC->SetTextColor(m_CurrentTextOnColor); // Set text to its ON color.
else
pDC->SetTextColor(m_CurrentTextOffColor); // Set text to its OFF color.
// Set the fill color according to the background state.
if (m_bBackgroundOn)
pDC->SetBkColor(m_CurrentBackgroundOnColor);
else
pDC->SetBkColor(m_CurrentBackgroundOffColor);
// If the control is in Hatch Mode, the control will display the
// hatch in the background's ON color and the background behind the
// hatch pattern in the background's OFF color by calling the SetBkColor() method
// of the CDC class above.
// The SetHatch() method changes the ON brush to a hatch brush.
// We return the hatch brush when in Hatch Mode.
if (m_bHatchMode)
...{
// I do not set the background mode of the device context to transparent
// when in Hatch Mode because having the lines passing through underneath
// the text usually makes the text difficult to read when the control is in
// its "off" state. Therefore I keep the background mode to OPAQUE (default)
// to use the background off color as a block on which the text is drawn.
// This makes it much easier to read.
//
PostMessage(WM_GECCOLORSTATIC_DRAWFRAME);
return static_cast(m_brOnBrush.GetSafeHandle());
}
// At this point, we must not be in Hatch Mode.
// Set background mode of the DC to TRANSPARENT so that if a bitmap pattern
// is being used for the background, it will show beneath the text.
//
pDC->SetBkMode(TRANSPARENT);
if (!m_bBackgroundOn)
...{
PostMessage(WM_GECCOLORSTATIC_DRAWFRAME);
return static_cast(m_brOffBrush.GetSafeHandle()); // Return background's OFF color.
}
else
...{
PostMessage(WM_GECCOLORSTATIC_DRAWFRAME);
return static_cast(m_brOnBrush.GetSafeHandle()); // Return background's ON color.
}
}
// ****************************************************************************
// ****************************************************************************
COLORREF CGCColorStatic::SetBackgroundOnColor(const COLORREF backColor)
...{
// Prepare to return previous background ON color.
COLORREF prevColor = m_CurrentBackgroundOnColor;
// Store new background ON color.
m_CurrentBackgroundOnColor = backColor;
// Calling SetBackgroundOnColor() does not change whether or not
// a hatch pattern is displayed. It changes the ON color of the
// background. If the control is in Hatch Mode, the hatch pattern
// will be updated with the new ON color. If the control is NOT in
// Hatch Mode, then the solid ON color will be updated.
if (!m_bHatchMode)
...{
#ifdef _DEBUG
_CrtDbgReport(_CRT_WARN,"GCColorStatic.cpp",__LINE__,"Demo"," %s ",">> SetBackgroundOnColor() - creating background On solid brush.");
#endif
// We are not in Hatch Mode. Delete the old brush and create a new
// SOLID brush with the new "on" color.
m_brOnBrush.DeleteObject();
m_brOnBrush.CreateSolidBrush(m_CurrentBackgroundOnColor);
}
else
...{
#ifdef _DEBUG
_CrtDbgReport(_CRT_WARN,"GCColorStatic.cpp",__LINE__,"Demo"," %s ",">> SetBackgroundOnColor() - creating background On hatch brush.");
#endif
// We ARE in Hatch Mode. Delete the old hatch brush and create a new
// HATCH brush with the new "on" color.
m_brOnBrush.DeleteObject();
m_brOnBrush.CreateHatchBrush(m_iHatchType,m_CurrentBackgroundOnColor);
}
Invalidate(TRUE); // Force to redraw.
PostMessage(WM_GECCOLORSTATIC_DRAWFRAME);
return prevColor; // Return previous background ON color.
}
COLORREF CGCColorStatic::SetTextOnColor(const COLORREF textColor)
...{
#ifdef _DEBUG
_CrtDbgReport(_CRT_WARN,"GCColorStatic.cpp",__LINE__,"Demo"," %s ",">> SetTextOnColor() - Setting text On color.");
#endif
COLORREF prevColor = m_CurrentTextOnColor; // Prepare to return text's previous ON color.
m_CurrentTextOnColor = textColor; // Store text's new ON color.
Invalidate(TRUE); // Force edit window to repaint.
PostMessage(WM_GECCOLORSTATIC_DRAWFRAME);
return prevColor;
}
COLORREF CGCColorStatic::SetTextOffColor(const COLORREF offColor)
...{
#ifdef _DEBUG
_CrtDbgReport(_CRT_WARN,"GCColorStatic.cpp",__LINE__,"Demo"," %s ",">> SetTextOffColor() - Setting text Off color.");
#endif
COLORREF prevColor = m_CurrentTextOffColor; // Prepare to return text's previous OFF color.
m_CurrentTextOffColor = offColor; // Store text's new OFF color.
Invalidate(TRUE); // Force edit window to repaint.
PostMessage(WM_GECCOLORSTATIC_DRAWFRAME);
return prevColor; // Return text's previous OFF color.
}
COLORREF CGCColorStatic::GetTextOffColor() const
...{
return m_CurrentTextOffColor;
}
void CGCColorStatic::GetTextOffColor(BYTE &Red, BYTE &Green, BYTE &Blue) const
...{
Red = GetRValue(m_CurrentTextOffColor);
Green = GetGValue(m_CurrentTextOffColor);
Blue = GetBValue(m_CurrentTextOffColor);
}
COLORREF CGCColorStatic::GetBackgroundOnColor() const
...{
return m_CurrentBackgroundOnColor;
}
COLORREF CGCColorStatic::GetTextOnColor() const
...{
return m_CurrentTextOnColor;
}
void CGCColorStatic::GetBackgroundOnColor(BYTE & Red, BYTE & Green, BYTE & Blue) const
...{
Red = GetRValue(m_CurrentBackgroundOnColor);
Green = GetGValue(m_CurrentBackgroundOnColor);
Blue = GetBValue(m_CurrentBackgroundOnColor);
}
void CGCColorStatic::GetTextOnColor(BYTE & Red, BYTE & Green, BYTE & Blue) const
...{
Red = GetRValue(m_CurrentTextOnColor);
Green = GetGValue(m_CurrentTextOnColor);
Blue = GetBValue(m_CurrentTextOnColor);
}
BOOL CGCColorStatic::SetPointFont(const int PointSize, const LPCTSTR fontname)
...{
BOOL bResult = FALSE;
// Get device context for this edit box.
CDC* pDC = this->GetDC();
// Delete previous CGdiObject and free its memory.
m_Font.DeleteObject();
// Create a new Font object.
bResult = m_Font.CreatePointFont((PointSize*10),fontname,pDC);
if (! bResult) return bResult;
// Set the new font for this edit box.
CStatic::SetFont(&m_Font,TRUE);
// Release the device context.
ReleaseDC(pDC);
return bResult;
}
BOOL CGCColorStatic::SetFontIndirect(const LOGFONT * lpLogFont)
...{
BOOL bResult;
// Delete previous CGdiObject and free its memory.
m_Font.DeleteObject();
// Create a new Font object.
bResult = m_Font.CreateFontIndirect(lpLogFont);
if (! bResult) return bResult;
// Set the new font for this edit box.
CStatic::SetFont(&m_Font,TRUE);
return bResult;
}
BOOL CGCColorStatic::SetPointFontIndirect(const LOGFONT * lpLogFont)
...{
BOOL bResult;
// Delete previous CGdiObject and free its memory.
m_Font.DeleteObject();
// Get device context for this edit box.
CDC* pDC = this->GetDC();
// Create a new Font object.
bResult = m_Font.CreatePointFontIndirect(lpLogFont, pDC);
if (! bResult)
...{
// Release the device context.
ReleaseDC(pDC);
return bResult;
}
// Set the new font for this edit box.
CStatic::SetFont(&m_Font,TRUE);
// Release the device context.
ReleaseDC(pDC);
return bResult;
}
LOGFONT CGCColorStatic::GetLogFont() const
...{
LOGFONT fontstruct;
CFont* pFont = NULL;
pFont = this->GetFont();
pFont->GetLogFont(&fontstruct);
return fontstruct;
}
void CGCColorStatic::SetUnderline(const BOOL On)
...{
LOGFONT fontstruct;
fontstruct = this->GetLogFont();
fontstruct.lfUnderline = (BYTE) On;
SetFontIndirect(&fontstruct);
}
void CGCColorStatic::SetItalic(const BOOL On)
...{
LOGFONT fontstruct;
fontstruct = this->GetLogFont();
fontstruct.lfItalic = (BYTE) On;
SetFontIndirect(&fontstruct);
}
void CGCColorStatic::SetBold(const BOOL On)
...{
LOGFONT fontstruct;
fontstruct = this->GetLogFont();
switch (On)
...{
case TRUE:
fontstruct.lfWeight = 700;
break;
case FALSE:
fontstruct.lfWeight = 400;
}
SetFontIndirect(&fontstruct);
}
BOOL CGCColorStatic::SetFontWeight(const int Weight)
...{
if ( (Weight < 1) || (Weight > 1000) ) return FALSE;
LOGFONT fontstruct;
fontstruct = this->GetLogFont();
fontstruct.lfWeight = Weight;
return SetFontIndirect(&fontstruct);
}
BOOL CGCColorStatic::FlashBackground(const BOOL bFlash,
const BOOL bFinalState,
const float duration)
...{
if (m_bTimerFlag) KillTimer(m_uiTimerID); // If a timer is active, kill it.
if (bFlash)
...{
// We are turning on flashing of the background.
m_bTextOn = m_bBackgroundOn; // Resync on/off states.
Invalidate(TRUE); // Force to redraw.
PostMessage(WM_GECCOLORSTATIC_DRAWFRAME);
m_FlashTypeFlag = BACKGROUND; // Set flash type to BACKGROUND.
m_bTimerFlag = TRUE; // Yes, a timer process exists.
m_uiTimerID = SetTimer(FLASH_TIMER_ID,int(duration * 1000),NULL); // Create the timer.
if (!m_uiTimerID) return FALSE;
}
else
...{
// If we are turning off the flashing, make sure the background is left
// in the state specified by bFinalState.
m_bBackgroundOn = bFinalState; // Set final state of background.
m_bTextOn = bFinalState; // Resync text state with background state.
m_FlashTypeFlag = NONE; // No flash state exists.
Invalidate(TRUE); // Force to redraw.
PostMessage(WM_GECCOLORSTATIC_DRAWFRAME);
}
return TRUE;
}
BOOL CGCColorStatic::FlashBackgroundAsym(const BOOL bFlash,
const BOOL bFinalState,
const float OnDuration,
const float OffDuration)
...{
if (m_bTimerFlag) KillTimer(m_uiTimerID); // If a timer is active, kill it.
if (bFlash)
...{
m_fOnDuration = OnDuration * 1000;
m_fOffDuration = OffDuration * 1000;
// We are turning on flashing of the background.
SetOn(TRUE); // Resync text with background and
// set to on state. Start asymmetrical
// flashing out in ON state.
m_FlashTypeFlag = ASYM_BACKGROUND; // Set flash type to ASYM_BACKGROUND.
// This is the Asymmetrical Flash mode.
m_bTimerFlag = TRUE; // Yes, a timer process exists.
m_uiTimerID = SetTimer(FLASH_TIMER_ID,int(m_fOnDuration),NULL); // Create the timer.
if (!m_uiTimerID) return FALSE;
}
else
...{
// If we are turning off the flashing, make sure the background is left
// in the state specified by bFinalState.
m_bBackgroundOn = bFinalState; // Set final state of background.
m_bTextOn = bFinalState; // Resync text state with background state.
m_FlashTypeFlag = NONE; // No flash state exists.
Invalidate(TRUE); // Force repaint.
PostMessage(WM_GECCOLORSTATIC_DRAWFRAME);
}
return TRUE;
}
BOOL CGCColorStatic::FlashBackgroundPulsed(const BOOL bFlash,
const BOOL bFinalState,
const float pulseDuration,
const int pulseRep,
const float onDuration)
...{
if (m_bTimerFlag) KillTimer(m_uiTimerID); // If a timer is active, kill it.
if (bFlash)
...{
m_pulseDuration = pulseDuration * 1000;
m_pulseOnDuration = onDuration * 1000;
m_pulseRep = pulseRep * 2 + 1;
// We are turning on flashing of the background.
SetOn(TRUE); // Resync text with background and
// set to on state. Start pulsed
// flashing out in ON state.
m_FlashTypeFlag = PULSED_BACKGROUND; // Set flash type to PULSED_BACKGROUND.
// This is the Pulsed Flash mode.
m_bTimerFlag = TRUE; // Yes, a timer process exists.
m_pulseCounter += 1;
m_uiTimerID = SetTimer(FLASH_TIMER_ID,int(m_pulseDuration),NULL); // Create the timer.
if (!m_uiTimerID) return FALSE;
}
else
...{
// If we are turning off the flashing, make sure the background is left
// in the state specified by bFinalState.
m_bBackgroundOn = bFinalState; // Set final state of background.
m_bTextOn = bFinalState; // Resync text state with background state.
m_FlashTypeFlag = NONE; // No flash state exists.
Invalidate(TRUE); // Force repaint.
PostMessage(WM_GECCOLORSTATIC_DRAWFRAME);
}
return TRUE;
}
BOOL CGCColorStatic::FlashText(const BOOL bFlash, const float duration, const BOOL bFinalState)
...{
if (m_bTimerFlag) KillTimer(m_uiTimerID); // If a timer is active, kill it.
if (bFlash)
...{
// We are turning on flashing of the text.
m_bTextOn = m_bBackgroundOn; // Resync on/off states.
Invalidate(TRUE);
PostMessage(WM_GECCOLORSTATIC_DRAWFRAME);
m_FlashTypeFlag = TEXT; // Set flash type to TEXT.
m_bTimerFlag = TRUE; // Yes, a timer process exists.
m_uiTimerID = SetTimer(FLASH_TIMER_ID,int(duration * 1000),NULL); // Spawn timer.
if (!m_uiTimerID) return FALSE;
}
else
...{
m_FlashTypeFlag = NONE; // No flash state exists.
m_bTextOn = bFinalState; // Resync text with background final state.
Invalidate(TRUE); // Force redraw.
PostMessage(WM_GECCOLORSTATIC_DRAWFRAME);
}
return TRUE;
}
void CGCColorStatic::OnTimer(UINT nIDEvent)
...{
// Toggle the state of the appropriate item.
switch (m_FlashTypeFlag)
...{
case TEXT:
// If the flash type is TEXT...
m_bTextOn = !m_bTextOn; // Invert state.
Invalidate(TRUE); // Force to redraw.
PostMessage(WM_GECCOLORSTATIC_DRAWFRAME);
break;
case BACKGROUND:
// If the flash type is BACKGROUND...
m_bBackgroundOn = !m_bBackgroundOn; // Invert state.
m_bTextOn = !m_bTextOn; // Invert state. Yes, I do this here
// but not for TEXT above.
Invalidate(TRUE); // Force to redraw.
PostMessage(WM_GECCOLORSTATIC_DRAWFRAME);
break;
case ASYM_BACKGROUND:
// If the flash type is Asymmetrical Background...
KillTimer(m_uiTimerID); // Kill previous timer.
// When FlashBackgroundAsym() is called, the control is immediately updated
// to the "ON" state by that method. So, we want to start out with
// setting the timer for the OnDuration as specified by m_fOnDuration
// member variable.
m_bBackgroundOn = !m_bBackgroundOn; // Invert state.
m_bTextOn = !m_bTextOn; // Invert state. Yes, I do this here
Invalidate(TRUE);
PostMessage(WM_GECCOLORSTATIC_DRAWFRAME);
switch (m_bBackgroundOn)
...{
case TRUE:
m_uiTimerID = SetTimer(FLASH_TIMER_ID,int(m_fOnDuration),NULL); // Create the "ON" timer.
break;
case FALSE:
m_uiTimerID = SetTimer(FLASH_TIMER_ID,int(m_fOffDuration),NULL); // Create the "OFF" timer.
}
break;
case PULSED_BACKGROUND:
// If the flash type is Pulsed Background...
// When FlashBackgroundPulsed() is called, the control is immediately updated
// to the "ON" state by that method. So, we want to start out with
// setting the timer for the pulse's on duration as specified by m_pulseDuration
// member variable.
m_bBackgroundOn = !m_bBackgroundOn; // Invert state.
m_bTextOn = !m_bTextOn; // Invert state. Yes, I do this here
Invalidate(TRUE);
PostMessage(WM_GECCOLORSTATIC_DRAWFRAME);
m_pulseCounter += 1;
if (m_pulseCounter <= m_pulseRep)
...{
m_uiTimerID = SetTimer(FLASH_TIMER_ID,int(m_pulseDuration),NULL); // Create a pulse timer.
}
else
...{
m_pulseCounter = 0;
SetOn();
m_uiTimerID = SetTimer(FLASH_TIMER_ID,int(m_pulseOnDuration),NULL); // Create the "ON" timer.
}
}
CStatic::OnTimer(nIDEvent);
}
COLORREF CGCColorStatic::SetBackgroundOffColor(const COLORREF offColor)
...{
#ifdef _DEBUG
_CrtDbgReport(_CRT_WARN,"GCColorStatic.cpp",__LINE__,"Demo"," %s ",">> SetBackgroundOffColor() - Creating background Off brush.");
#endif
COLORREF prevColor = m_CurrentBackgroundOffColor; // Prepare to return background's previous OFF color.
m_CurrentBackgroundOffColor = offColor; // Store background's new OFF color.
m_brOffBrush.DeleteObject(); // Delete background's old OFF brush.
m_brOffBrush.CreateSolidBrush(m_CurrentBackgroundOffColor); // Create background's new OFF brush.
if (!m_bBackgroundOn)
...{
Invalidate(TRUE); // Force to redraw.
PostMessage(WM_GECCOLORSTATIC_DRAWFRAME);
}
return prevColor; // Return background's previous OFF color.
}
COLORREF CGCColorStatic::GetBackgroundOffColor() const
...{
return m_CurrentBackgroundOffColor;
}
void CGCColorStatic::GetBackgroundOffColor(BYTE &Red, BYTE &Green, BYTE &Blue) const
...{
Red = GetRValue(m_CurrentBackgroundOffColor);
Green = GetGValue(m_CurrentBackgroundOffColor);
Blue = GetBValue(m_CurrentBackgroundOffColor);
}
BOOL CGCColorStatic::SetOn(const BOOL bOn)
...{
#ifdef _DEBUG
if (bOn)
_CrtDbgReport(_CRT_WARN,"GCColorStatic.cpp",__LINE__,"Demo"," %s ",">> SetOn() - Setting state to ON");
else
_CrtDbgReport(_CRT_WARN,"GCColorStatic.cpp",__LINE__,"Demo"," %s ",">> SetOn() - Setting state to OFF");
#endif _DEBUG
BOOL prevState = m_bBackgroundOn; // Key off background for overall state of control.
m_bBackgroundOn = bOn; // Set background to specified on/off state.
m_bTextOn = m_bBackgroundOn; // Sync text state to background state.
Invalidate();
PostMessage(WM_GECCOLORSTATIC_DRAWFRAME);
return prevState; // Return previous state.
}
BOOL CGCColorStatic::SetSunken(const BOOL bSunken)
...{
BOOL Result = FALSE;
if (bSunken)
...{
if (m_bColorFrameFlag) SetColorFrame(FALSE); // Color frame and sunken frame mutually exclusive.
Result = ModifyStyleEx(0,WS_EX_STATICEDGE,SWP_DRAWFRAME);
}
else
Result = ModifyStyleEx(WS_EX_STATICEDGE,0,SWP_DRAWFRAME);
return Result;
}
BOOL CGCColorStatic::SetBorder(const BOOL bBorder)
...{
BOOL Result = FALSE;
if (bBorder)
Result = ModifyStyle(0,WS_BORDER,SWP_DRAWFRAME);
else
Result = ModifyStyle(WS_BORDER,0,SWP_DRAWFRAME);
return Result;
}
BOOL CGCColorStatic::SetModalFrame(const BOOL bModal)
...{
BOOL Result = FALSE;
if (bModal)
...{
if (m_bColorFrameFlag) SetColorFrame(FALSE); // Color frame and modal frame mutually exclusive.
Result = ModifyStyleEx(0,WS_EX_DLGMODALFRAME,SWP_DRAWFRAME);
}
else
Result = ModifyStyleEx(WS_EX_DLGMODALFRAME,0,SWP_DRAWFRAME);
return Result;
}
BOOL CGCColorStatic::TextOn(const BOOL bOn)
...{
BOOL prevState = m_bTextOn;
if (m_bTextOn == bOn) return m_bTextOn;
m_bTextOn = bOn;
Invalidate(TRUE);
PostMessage(WM_GECCOLORSTATIC_DRAWFRAME);
return prevState;
}
void CGCColorStatic::GetStates(BOOL &bBackgroundState, BOOL &bTextState) const
...{
bBackgroundState = m_bBackgroundOn;
bTextState = m_bTextOn;
}
COLORREF CGCColorStatic::SetBackgroundOnPattern(CBitmap * pattern)
...{
#ifdef _DEBUG
_CrtDbgReport(_CRT_WARN,"GCColorStatic.cpp",__LINE__,"Demo"," %s ",">>SetBackgroundOnPattern() - Creating background on pattern brush");
#endif
m_bHatchMode = FALSE;
COLORREF prev = m_CurrentBackgroundOnColor;
// Since the bitmap to be used to create the pattern brush may
// not be a single color, just set the background "on" color to
// the default background ON color.
m_CurrentBackgroundOnColor = DEFAULT_BACKGROUND_ON_COLOR;
m_brOnBrush.DeleteObject(); // Delete the old background "on" brush.
m_brOnBrush.CreatePatternBrush(pattern); // Create the new "on" pattern brush.
Invalidate(); // Repaint the control.
PostMessage(WM_GECCOLORSTATIC_DRAWFRAME);
return prev; // Return previous background ON color.
}
COLORREF CGCColorStatic::SetBackgroundOffPattern(CBitmap * pattern)
...{
#ifdef _DEBUG
_CrtDbgReport(_CRT_WARN,"GCColorStatic.cpp",__LINE__,"Demo"," %s ",">>SetBackgroundOffPattern() - Creating background off pattern brush");
#endif
m_bHatchMode = FALSE;
COLORREF prev = m_CurrentBackgroundOffColor;
// Since the bitmap to be used to create the pattern brush may
// not be a single color, just set the background "off" color to
// the default background OFF color.
m_CurrentBackgroundOffColor = DEFAULT_BACKGROUND_OFF_COLOR;
m_brOffBrush.DeleteObject(); // Delete the old background "on" brush.
m_brOffBrush.CreatePatternBrush(pattern); // Create the new "on" pattern brush.
Invalidate(); // Repaint the control.
PostMessage(WM_GECCOLORSTATIC_DRAWFRAME);
return prev; // Return previous background OFF color.
}
BOOL CGCColorStatic::SetHatch(const BOOL bOn,
const UINT HatchType)
...{
if (m_bHatchMode == bOn) return (m_bHatchMode == bOn);
m_bHatchMode = bOn;
if (m_bHatchMode)
...{
#ifdef _DEBUG
_CrtDbgReport(_CRT_WARN,"GCColorStatic.cpp",__LINE__,"Demo"," %s ",">>SetHatch() - Creating hatch brush");
#endif
// If the control is being set to Hatch Mode, delete the old brush
// used for the background's ON state and create a hatch brush
// using the same color.
m_brOnBrush.DeleteObject();
m_brOnBrush.CreateHatchBrush(HatchType,m_CurrentBackgroundOnColor);
// If the previous background OFF brush was a bitmap pattern,
// we want to delete it and set the background OFF color to the default
// off color. It is expected that the client will set a color for the
// background off color as well as for the background on color that will
// be used for the hatch pattern.
LOGBRUSH logicalBrush;
m_brOffBrush.GetLogBrush(&logicalBrush);
if (
(logicalBrush.lbStyle == BS_PATTERN)
||
(logicalBrush.lbStyle == BS_PATTERN8X8)
)
...{
m_CurrentBackgroundOffColor = DEFAULT_BACKGROUND_OFF_COLOR;
m_brOffBrush.DeleteObject();
m_brOffBrush.CreateSolidBrush(DEFAULT_BACKGROUND_OFF_COLOR);
}
m_iHatchType = HatchType;
}
else
...{
#ifdef _DEBUG
_CrtDbgReport(_CRT_WARN,"GCColorStatic.cpp",__LINE__,"Demo"," %s ",">>SetHatch() - Creating solid brush");
#endif
// if Hatch Mode is being turned off, then delete the hatch brush
// and re-create the solid brush for the background's ON state.
m_brOnBrush.DeleteObject();
m_brOnBrush.CreateSolidBrush(m_CurrentBackgroundOnColor);
}
Invalidate(); // Force the control to redraw.
PostMessage(WM_GECCOLORSTATIC_DRAWFRAME);
return FALSE;
}
void CGCColorStatic::SetColorFrame(const BOOL bOn, const int Width, const COLORREF FrameColor)
...{
m_bColorFrameFlag = bOn;
if (!bOn)
...{
#ifdef _DEBUG
_CrtDbgReport(_CRT_WARN,"GCColorStatic.cpp",__LINE__,"Demo"," %s ",">>SetColorFrame() - Color Frame turned on");
#endif
if (m_bBackgroundOn)
m_ColorFrameColor = m_CurrentBackgroundOnColor;
else
m_ColorFrameColor = m_CurrentBackgroundOffColor;
}
else
...{
// I made the color frame mutually exclusive of the modal and sunken frames. They just
// do not look nice together.
// When using the modal or sunken frames, the client area that is actually visible
// is decreased in size. If you were to add the color frame with the modal or sunken
// frames, and draw the color frame so that it did not overlay the modal or sunken frame,
// the usable area would be even smaller. Therefore, as a design decision,
// I made the color frame border type mutually exclusive with the modal and sunken types.
// Overlaying the color frame on the modal or sunken frame looks bad.
BOOL Result = ModifyStyleEx(WS_EX_DLGMODALFRAME | WS_EX_STATICEDGE,0,SWP_DRAWFRAME);
m_ColorFrameWidth = Width;
#ifdef _DEBUG
_CrtDbgReport(_CRT_WARN,"GCColorStatic.cpp",__LINE__,"Demo"," %s ",">>SetColorFrame() - Color Frame turned off");
#endif
m_ColorFrameColor = FrameColor;
}
Invalidate(TRUE); // Force to redraw.
PostMessage(WM_GECCOLORSTATIC_DRAWFRAME);
}
/**//*
void CGCColorStatic::OnNcPaint()
{
if (m_bColorFrameFlag)
{
// Note: I do not inflate the rectangle at which the color frame is drawn because
// this would make the control take up more area on the screen. If there are multiple
// indicators next to each other, you would have the color frame of one
// control being drawn on top of the adjoinging control. Therefore, I paint the
// frame inside the edges of the control. Remember this when selecting fonts because
// the color frame makes the area availble for displaying text a little smaller.
_CrtDbgReport(_CRT_WARN,"GCColorStatic.cpp",__LINE__,"Demo"," %s ",">>OnNcPaint() - Painting frame");
CRect rect;
this->GetWindowRect(&rect);
CPen pen(PS_INSIDEFRAME , m_ColorFrameWidth,m_ColorFrameColor);
ScreenToClient(&rect);
CDC* pDDC = this->GetDC();
pDDC->SelectObject(pen);
pDDC->SelectObject(GetStockObject(NULL_BRUSH));
pDDC->Rectangle(rect);
ReleaseDC(pDDC);
}
else
{
_CrtDbgReport(_CRT_WARN,"GCColorStatic.cpp",__LINE__,"Demo"," %s ",">>OnNcPaint() - Calling base class OnNcPaint()");
CStatic::OnNcPaint();
}
CStatic::OnNcPaint();
}
*/
void CGCColorStatic::OnDrawFrame(WPARAM wp, LPARAM lp)
...{
if (m_bColorFrameFlag)
...{
// Note: I do not inflate the rectangle at which the color frame is drawn because
// this would make the control take up more area on the screen. If there are multiple
// indicators next to each other, you would have the color frame of one
// control being drawn on top of the adjoinging control. Therefore, I paint the
// frame inside the edges of the control. Remember this when selecting fonts because
// the color frame makes the area availble for displaying text a little smaller.
#ifdef _DEBUG
_CrtDbgReport(_CRT_WARN,"GCColorStatic.cpp",__LINE__,"Demo"," %s ",">>OnDrawFrame() - Painting frame");
#endif
CRect rect;
this->GetWindowRect(&rect);
// Do not allow an exception constructing the pen or from creating
// the device context to kill the client.
try
...{
CPen pen(PS_INSIDEFRAME , m_ColorFrameWidth,m_ColorFrameColor);
ScreenToClient(&rect);
CClientDC dc(this);
dc.SelectObject(pen);
dc.SelectObject(GetStockObject(NULL_BRUSH));
dc.Rectangle(rect);
}
catch (CResourceException)
...{
}
}
}
void CGCColorStatic::SetWindowText(LPCTSTR lpszString)
...{
// Had to override this method. Calling the
// inherited SetWindowText() resulted in a message being generated causing the
// background to be repainted. Since my color frame is drawn inside the edge of the
// control, over the client area, this would erase the colored border when a colored
// border was being used. Therefore, I had to override this method and force
// the redraw of the frame so that it would stay visible.
//
//
CStatic::SetWindowText(lpszString);
PostMessage(WM_GECCOLORSTATIC_DRAWFRAME);
}