Background button flashing ...

I have created a class named CAlarmButton. This class permit to falsh
background when I call member function StartFlashing and stop it when
calling member function StopFlashing.
The StartFlashing function starts a timer which Invalidate the control.
The StopFlashing function stop the timer.

My problem is when I use more then one button and when I call StartFlashing
for each button, all button are not flashing in rhythm. I wan't that all button
flash in rhythm.

I have tried to start the timer when I construct the control, but the result
is the same !

How can I do this ?

You can find the code below.

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------

class CAlarmButton : public CButton
 {
  COLORREF  m_BackgroundColor1, m_BackgroundColor2, m_BackgroundColor, m_TextColor;
  BOOL      m_IsBackgroundFlashing;
  CBitmap  *m_pImage, *m_pMask;
  int       m_ImageW, m_ImageH;
  UINT      m_TextAlignment, m_ImageAlignment;
  BOOL      m_HoldState;
 
  // Construction
  public :
           CAlarmButton();

           void SetBackgroundColor(COLORREF BackgroundColor, BOOL First = TRUE);
           void SetTextColor(COLORREF TextColor);
           void StartFlashing(UINT Time = 1000);
           void StopFlashing();
           void SetBitmap(UINT ImageID, UINT MaskID = NULL);
           void SetTextAlignment(UINT Alignment = HCENTER | VCENTER);
           void SetImageAlignment(UINT Alignment = HCENTER | VCENTER);
           void HoldState(BOOL HoldState = FALSE);

  // Attributes
  public :

  // Operations
  public :
           BOOL ModifyStyle(DWORD dwRemove, DWORD dwAdd, UINT nFlags = 0);

  // Overrides
      // ClassWizard generated virtual function overrides
      //{{AFX_VIRTUAL(CAlarmButton)
      protected:
      virtual void PreSubclassWindow();
    virtual void DrawItem(LPDRAWITEMSTRUCT);
      //}}AFX_VIRTUAL

  // Implementation
  public :
           virtual ~CAlarmButton();

  // Generated message map functions
  protected :
      //{{AFX_MSG(CAlarmButton)
      afx_msg void OnTimer(UINT nIDEvent);
      afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
      afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
      //}}AFX_MSG

  DECLARE_MESSAGE_MAP()
 };

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------

CAlarmButton::CAlarmButton()
 {
  m_BackgroundColor  = m_BackgroundColor1 = RGB(198,198,198);
  m_BackgroundColor2 = RGB(255,0,0);
  m_TextColor        = RGB(0,0,0);

  m_IsBackgroundFlashing = FALSE;
  m_pImage               = NULL;
  m_pMask                = NULL;
  m_TextAlignment        = HCENTER | VCENTER;
  m_ImageAlignment       = HCENTER | VCENTER;
  m_HoldState            = FALSE;
 }

// --------------------------------------------------------------------------

CAlarmButton::~CAlarmButton()
 {
  if (m_pImage) delete m_pImage;
  if (m_pMask ) delete m_pMask;
 }

// --------------------------------------------------------------------------

void CAlarmButton::SetBackgroundColor(COLORREF BackgroundColor, BOOL First)
 {
  if (First) m_BackgroundColor1 = BackgroundColor;
  else m_BackgroundColor2 = BackgroundColor;
 }

// --------------------------------------------------------------------------

void CAlarmButton::StartFlashing(UINT Time)
 {
  SetTimer(TIMER_FLASHING, Time, NULL);
 }

// --------------------------------------------------------------------------

void CAlarmButton::StopFlashing()
 {
  KillTimer(TIMER_FLASHING);
  m_BackgroundColor = m_BackgroundColor1;
  Invalidate();
 }

// --------------------------------------------------------------------------

void CAlarmButton::SetBitmap(UINT ImageID, UINT MaskID)
 {
  if (m_pImage) delete m_pImage;
  if (m_pMask) delete m_pMask;

  m_pImage = m_pMask = NULL;

  if (ImageID)
   {
    m_pImage = new CBitmap;
    m_pImage->LoadBitmap(ImageID);

    BITMAP Bitmap;
    m_pImage->GetBitmap(&Bitmap);
    m_ImageW = Bitmap.bmWidth;
    m_ImageH = Bitmap.bmHeight;
   }
 
  if (MaskID)
   {
    m_pMask = new CBitmap;
    m_pMask->LoadBitmap(MaskID);
   }

  Invalidate();
 }

// --------------------------------------------------------------------------

void CAlarmButton::SetTextAlignment(UINT Alignment)
 {
  m_TextAlignment = Alignment;
  Invalidate();
 }

// --------------------------------------------------------------------------

void CAlarmButton::SetImageAlignment(UINT Alignment)
 {
  m_ImageAlignment = Alignment;
  Invalidate();
 }

// --------------------------------------------------------------------------

void CAlarmButton::HoldState(BOOL HoldState)
 {
  m_HoldState = HoldState;
 }

// --------------------------------------------------------------------------

BOOL CAlarmButton::ModifyStyle(DWORD dwRemove, DWORD dwAdd, UINT nFlags)
 {
  BOOL rcCode = CButton::ModifyStyle(dwRemove,dwAdd,nFlags);

  Invalidate();

  return rcCode;
 }

// --------------------------------------------------------------------------

BEGIN_MESSAGE_MAP(CAlarmButton, CButton)
      //{{AFX_MSG_MAP(CAlarmButton)
      ON_WM_TIMER()
      ON_WM_LBUTTONDOWN()
      ON_WM_LBUTTONUP()
      //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CAlarmButton message handlers

void CAlarmButton::OnTimer(UINT nIDEvent)
 {
  if (m_IsBackgroundFlashing)
   {
    m_IsBackgroundFlashing = FALSE;
    m_BackgroundColor = m_BackgroundColor2;
   }
  else {
        m_IsBackgroundFlashing = TRUE;
        m_BackgroundColor = m_BackgroundColor1;
       }

  Invalidate();
             
  CButton::OnTimer(nIDEvent);
 }

// --------------------------------------------------------------------------

void CAlarmButton::PreSubclassWindow()
 {
  CButton::PreSubclassWindow();
  ModifyStyle(0, BS_OWNERDRAW);
 }

// --------------------------------------------------------------------------

void CAlarmButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
 {
  ASSERT(lpDrawItemStruct != NULL);

  CDC   *pMemDC;
  int    Offset,
         X,
         Y;
  CDC   *pDC    = CDC::FromHandle(lpDrawItemStruct->hDC);
  CRect  Rect   = lpDrawItemStruct->rcItem;
  UINT   State  = lpDrawItemStruct->itemState;
  UINT   nStyle = GetStyle();

  pDC->SelectStockObject(NULL_BRUSH);
  pDC->FillSolidRect(Rect, m_BackgroundColor);

  // Draw the focus rectangle around the button
  if ((State & ODS_FOCUS))
   {
    CRect FocusRect(Rect.left + 4, Rect.top + 4, Rect.right - 4, Rect.bottom - 4);
    pDC->DrawFocusRect(FocusRect);
   }

  // Draw Bitmap if one
  if (m_pImage != NULL)
   {
    pMemDC = new CDC;
    pMemDC->CreateCompatibleDC(pDC);

    Offset = 0;
    if (State & ODS_SELECTED) Offset++;

    if ((m_ImageAlignment & HLEFT) == HLEFT) X = 4;
    else if ((m_ImageAlignment & HCENTER) == HCENTER) X = (Rect.Width()  - m_ImageW) / 2;
         else if ((m_ImageAlignment & HRIGHT) == HRIGHT) X = Rect.Width() - m_ImageW - 4;

    if ((m_ImageAlignment & VTOP) == VTOP) Y = 4;
    else if ((m_ImageAlignment & VCENTER) == VCENTER) Y = (Rect.Height() - m_ImageH) / 2;
         else if ((m_ImageAlignment & VBOTTOM) == VBOTTOM) Y = Rect.Height() - m_ImageH - 4;

    if (X < 0) X=0;
    if (Y < 0) Y=0;

    X += Offset;
    Y += Offset;

    if (m_pMask != NULL)
     {
      pMemDC->SelectObject(m_pMask);
      pDC->BitBlt(X,Y,m_ImageW,m_ImageH,pMemDC,0,0,SRCAND);
     }

    pMemDC->SelectObject(m_pImage);
    if (m_pMask != NULL) pDC->BitBlt(X,Y,m_ImageW,m_ImageH,pMemDC,0,0,SRCINVERT);
    else pDC->BitBlt(X,Y,m_ImageW,m_ImageH,pMemDC,0,0,SRCCOPY);

    delete pMemDC;
   }

  // Draw the raised/sunken edges of the button
  if (nStyle & BS_FLAT)
   {
    pDC->DrawEdge(Rect,EDGE_ETCHED, BF_RECT);
   }
  else {
        if ((State & ODS_SELECTED))
         {
          pDC->Draw3dRect(Rect,RGB(0,0,0),RGB(255,255,255));
         }
        else {
              pDC->Draw3dRect(Rect,RGB(255,255,255),RGB(0,0,0));
             }
       }

  // Draw the text if there is any
  CString strText;
  GetWindowText(strText);

  if (!strText.IsEmpty())
   {
    CSize  Extent = pDC->GetTextExtent(strText);
    CPoint Pt;
   
    if ((m_TextAlignment & HLEFT) == HLEFT) Pt.x = 4;
    else if ((m_TextAlignment & HCENTER) == HCENTER) Pt.x = (Rect.Width() - Extent.cx) / 2;
         else if ((m_TextAlignment & HRIGHT) == HRIGHT) Pt.x = Rect.Width() - Extent.cx - 4;

    if ((m_TextAlignment & VTOP) == VTOP) Pt.y = 4;
    else if ((m_TextAlignment & VCENTER) == VCENTER) Pt.y = (Rect.Height() - Extent.cy) / 2;
         else if ((m_TextAlignment & VBOTTOM) == VBOTTOM) Pt.y = Rect.Height() - Extent.cy - 4;

    if (State & ODS_SELECTED) Pt.Offset(1,1);

    pDC->SetBkMode(TRANSPARENT);
    pDC->SetTextColor(m_TextColor);

    if (State & ODS_DISABLED)
     pDC->DrawState(Pt, Extent, strText, DSS_DISABLED, TRUE, 0, (HBRUSH)NULL);
    else
     pDC->TextOut(Pt.x, Pt.y, strText);
   }
 }
mike_marquetAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

RONSLOWCommented:
Get the system time and calculate the time for the first interval to make it in sync with the system time (eg. flash every second).

So, when you turn the alarm on.  If the system time is 0.4s after the second, then set the inital timer for 0.6s.  When the timer goes off, change the color and repeat the process (work out the time required until the next whole second and set the timer again).



0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
System Programming

From novice to tech pro — start learning today.