Adding a clock to the status bar

Here is how to add the current time to your status bar...

Step 1:

Derive a CMyStatusBar class from CStatusBar as follows:
//MyStatusBar.h:
//==============
class CMyStatusBar : public CStatusBar {
     DECLARE_DYNCREATE(CMyStatusBar)
public:
     CMyStatusBar();
     ~CMyStatusBar();
private:
     CString m_strClockFormat;
public:
     void SetClockFormat(LPCTSTR strClockFormat);
     // Overrides
     // ClassWizard generated virtual function overrides
     //{{AFX_VIRTUAL(CMyStatusBar)
     //}}AFX_VIRTUAL
     // Generated message map functions
     //{{AFX_MSG(CMyStatusBar)
     afx_msg void OnDestroy();
     afx_msg void OnUpdateIndicatorTime(CCmdUI* pCmdUI);
     afx_msg int OnCreate( LPCREATESTRUCT lpCreateStruct );
     //}}AFX_MSG
     DECLARE_MESSAGE_MAP()
};


/////////////////////////////////////////////////////////////////
//MyStatusBar.cpp:
//==============
#include "stdafx.h"
#include "MyStatusBar.h"
#include "Resource.h"

#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif

IMPLEMENT_DYNCREATE(CMyStatusBar, CStatusBar)

BEGIN_MESSAGE_MAP(CMyStatusBar, CStatusBar)
ON_WM_CREATE()
ON_WM_DESTROY()
ON_UPDATE_COMMAND_UI(ID_INDICATOR_TIME, OnUpdateIndicatorTime)
END_MESSAGE_MAP()

CMyStatusBar::CMyStatusBar()
: CStatusBar()
, m_strClockFormat("%H:%M:%S")
{
}

CMyStatusBar::~CMyStatusBar() {
}

void CMyStatusBar::SetClockFormat(LPCTSTR strClockFormat) {
     m_strClockFormat = strClockFormat;
}

int CMyStatusBar::OnCreate(LPCREATESTRUCT lpCreateStruct) {
     // make sure time gets updated every second, even when idle
     CStatusBar::OnCreate(lpCreateStruct);
     SetTimer(ID_INDICATOR_TIME,1000,NULL);
     return 0;
}

void CMyStatusBar::OnUpdateIndicatorTime(CCmdUI* pCmdUI) {
     pCmdUI->Enable(true);
     pCmdUI->SetText(CTime::GetCurrentTime().Format(m_strClockFormat));
}

void CMyStatusBar::OnDestroy() {
     KillTimer(ID_INDICATOR_TIME);
     ProgressDestroy();
     CStatusBar::OnDestroy();
}

Step 2:

Create a new indicator pane by first adding a new menu called "ID_INDICATOR", add a single dropdown called "Indicator", add a single item to the menu called "Time" - This should create a menu item with id ID_INDICATOR_TIME. Give it a prompt string of, say, "HH:MM:SS" which reserves an approriate amount of space for the pane. NOTE: If you change time format by calling SetClockFormat you will need to ensure that your ID_INDICATOR_TIME pane is big enough.

Step 3:

Add a new indicator pane called ID_INDICATOR_TIME to your list of indicator in your mainframe eg. this is my indicator list...
static const UINT indicators[] = {
     ID_SEPARATOR,           // status line indicator
     ID_INDICATOR_CAPS,
     ID_INDICATOR_NUM,
     ID_INDICATOR_SCRL,
     ID_INDICATOR_TIME,  // <-- new indicator pane
};

Step 4:

Replace all existing uses of CStatusBar in your app with CMyStatusBar - in particular, the member variable in your mainframe m_wndStatusBar;



Comments

  • Time is not accurate

    Posted by Legacy on 08/10/2002 12:00am

    Originally posted by: Amir

    Has anyone noticed that the time is not very accurate. I use the SetTimer() method with a value of 1000 and the timer always runs faster than the actual time. Is there a more accurate way to keep time?

    -Amir

    Reply
  • SetTextAlign

    Posted by Legacy on 04/29/2002 12:00am

    Originally posted by: ray

    How could I apply SetTextAlign function in StatusBar ?
    

    Reply
  • Adding a clock to the status bar in A Dialog Box

    Posted by Legacy on 12/06/2001 12:00am

    Originally posted by: Dhayalan

    The Following part of the Code Wil be Used to Create a Status bar in Dialog box and Update the Panes of the Status Bar. Normally The Status bar will be attached to a CMainFrame object and we need to Send a ON_UPDATE_COMMAND_UI message to update the Controls.
    Since it is a DialogBased Appliation we don't have CMainFrame, we have to send the message direly to the Pane.

    This is a Simple Application with four pane with Date and Time.

    Step 0:
    --------
    Declare these Variables in the .h file
    CStatusBar m_StatBar;

    step1 :
    -------
    Add the Pane Indicators in the Resource file and add strings for the Coressponding Id's

    In MyDialog.cpp


    static UINT indicators[]={
    ID_INDICATOR_TESTING,
    ID_INDICATOR_TEST_PROG,
    ID_INDICATOR_DATE,
    ID_INDICATOR_TIME
    };

    Step2:
    -----
    Add these Message handler Manualy and By using Clwizard

    BEGIN_MESSAGE_MAP(CCheckDlg, CDialog)
    //{{AFX_MSG_MAP(CCheckTIDlg)
    ON_WM_TIMER()
    ON_WM_CREATE()
    //}}AFX_MSG_MAP
    ON_UPDATE_COMMAND_UIID_INDICATOR_TIME,OnUpdateTimer)
    END_MESSAGE_MAP()


    step3:
    ------
    Add this Code in to the Corrosponding Functions

    int CCheckDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
    if (CDialog::OnCreate(lpCreateStruct) == -1)
    return -1;

    CRect rect;
    this->GetWindowRect(&rect);
    rect.top = rect.bottom- 25;

    m_StatBar.GetStatusBarCtrl().Create(WS_CHILD | WS_BORDER | WS_VISIBLE|SBARS_SIZEGRIP|CCS_BOTTOM ,rect,this,
    IDC_MY_SATUSBAR);
    m_StatBar.SetIndicators(indicators,sizeof(indicators)/sizeof(UINT));

    m_StatBar.SetPaneInfo(0,ID_INDICATOR_TESTING,SBPS_NORMAL ,60);
    m_StatBar.SetPaneInfo(1,ID_INDICATOR_TEST_PROG,SBPS_NORMAL ,170);
    m_StatBar.SetPaneInfo(2,ID_INDICATOR_DATE,SBPS_NORMAL,50);
    m_StatBar.SetPaneInfo(3,ID_INDICATOR_TIME,SBPS_STRETCH,60);

    SetTimer(1,100,NULL);
    return 0;

    }

    void CCheckDlg::OnTimer(UINT nIDEvent)
    {

    har tmpbuf[50];
    _strdate(tmpbuf);
    m_StatBar.SetPaneText(2,tmpbuf,TRUE);

    CTime theTime=CTime::GetCurrentTime();
    CString szTime;
    szTime=theTime.Format(" %I:%M:%S");
    m_StatBar.SetPaneText(3,szTime,TRUE);
    CDialog::OnTimer(nIDEvent);
    }
    Reg,
    Dhayalan.V

    Reply
  • I use this code...(for MFC Dialogs !!)

    Posted by Legacy on 06/09/2001 12:00am

    Originally posted by: Sebastian

    ...your idea is not very successful!
    
    My Code uses the Class Item WM_TIMER added from the Class Assistent

    /// starts here ///
    void Arbeiten::OnTimer(UINT nIDEvent)
    {
    CString csUhr;
    switch ( nIDEvent )
    {
    case 0x3B0 :
    COleDateTime dZeit = COleDateTime::GetCurrentTime();

    csUhr.Format ("%02d.%02d.%02d", dZeit.GetHour(), dZeit.GetMinute(), dZeit.GetSecond() );
    GetDlgItem(IDC_uhr)->SetWindowText(csUhr);

    break;
    }
    CPropertyPage::OnTimer(nIDEvent);
    }
    /// My program uses CPropertyPage ;-P
    /// end

    Reply
  • Problems in NT

    Posted by Legacy on 02/03/2000 12:00am

    Originally posted by: Miguel Angel

    I have tried to use your code in Windows NT, but in the CMainFrame::OnCreate(), in the portion of code:
    if (!m_wndStatusBar.Create(this) ||
    !m_wndStatusBar.SetIndicators(indicators,
    sizeof(indicators)/sizeof(UINT)))
    {
    TRACE0("Failed to create status bar\n");
    return -1; // fail to create
    }

    The call to SetIndicators returns a 0. Any idea about the solution?
    I had no trouble in Windows 95/98.

    Best regards,
    Miguel Angel

    Reply
  • Dangerous situation

    Posted by Legacy on 03/04/1999 12:00am

    Originally posted by: Tom Bech

    1. By the way, this identical method are presented on MSDN KB Q99198. There are also method with global timer.
    2. When I implemented this method I have got serious problem: my time didn't work when I opened child window (time didn't appear). When I closed child window time appear.
    Reason: I like order, so I added ID_INDICATOR_TIME in string table just after ID_INDICATOR_REC and it has number up one to the previous.
    There was no warning from Visual Studio. But this number corresponds to
    ID_INDICATOR_KANA which has own implementation UI in CFrameWnd.
    My timer worked (when was no child window) because my implementation
    of time UI hides standard implementation of ID_INDICATOR_KANA
    (in class CMainFrame). But in class CChildFrame there was no my
    implementation and after opening child window my time works as
    ID_INDICATOR_KANA (by the way, what is it: 'kana'?!?).
    Solution: Set unique value for ID_INDICATOR_TIME.
    (and don't like order when you work with MFC)

    (sorry for my 'english')

    Reply
  • Ever-living timer

    Posted by Legacy on 02/12/1999 12:00am

    Originally posted by: Alex Rogovtsev

    One way to keep timer alive is to use an application-defined TimerProc callback function
    
    SetTimer(0x1000, 1000, TimerProc)
    instead of installing WM_TIMER message in application's message queue
    SetTimer(0x1000, 1000, NULL)

    So you should do only a few step to keep timer alive:
    (Let's do this for a simple SDI application)

    Step 1:
    Insert in your CMainFrame::OnCreate() function only one statement
    int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
    if (CFrameWnd::OnCreate(lpCreateStruct) == -1) return -1;
    if (!m_wndStatusBar.Create(this) ||
    !m_wndStatusBar.SetIndicators(indicators,
    sizeof(indicators)/sizeof(UINT)))
    return -1; // fail to create
    m_wndStatusBar.SetTimer(0x1000, 1000, TimerProc); //<-- new statement
    return 0;
    }

    Step 2:
    Add application defined function TimerProc() to your CMainFrame.cpp file
    void CALLBACK EXPORT TimerProc(HWND hWnd, UINT nMsg, UINT nIDEvent, DWORD dwTime)
    {
    CCmdUI cui;
    CMainFrame *pMainWnd = (CMainFrame *)AfxGetMainWnd(); //this is for SDI project
    cui.m_nID = ID_INDICATOR_TIME;
    cui.m_nIndex = pMainWnd->m_wndStatusBar.CommandToIndex(ID_INDICATOR_TIME);
    cui.m_pMenu = NULL;
    cui.m_pOther = &pMainWnd->m_wndStatusBar;
    pMainWnd->OnUpdateTime(&cui);
    }

    Step 3:
    Add ON_UPDATE_COMMAND message handler to CMainFrame message map
    BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
    ON_UPDATE_COMMAND_UI(ID_INDICATOR_TIME, OnUpdateTime)
    //{{AFX_MSG_MAP(CMainFrame)
    // NOTE - the ClassWizard will add and remove mapping macros here.
    // DO NOT EDIT what you see in these blocks of generated code !
    ON_WM_CREATE()
    //}}AFX_MSG_MAP
    END_MESSAGE_MAP()

    add OnUpdateTime() function to CMainFrame class

    void CMainFrame::OnUpdateTime(CCmdUI* pCmdUI)
    {
    // Get current date and format it
    CTime time = CTime::GetCurrentTime();
    CString strTime = time.Format(_T("%X"));
    m_wndStatusBar.SetPaneText(m_wndStatusBar.CommandToIndex(ID_INDICATOR_TIME),strTime);
    pCmdUI->Enable(TRUE);

    }

    Step 4:
    Add a new indicator pane called ID_INDICATOR_TIME to your list of indicator in your CMainFrame indicator list.

    static const UINT indicators[] = {
    ID_SEPARATOR, // status line indicator
    ID_INDICATOR_CAPS,
    ID_INDICATOR_NUM,
    ID_INDICATOR_SCRL,
    ID_INDICATOR_TIME, // <-- new indicator pane
    };
    Step 4:
    Add a new string with ID_INDICATOR_TIME to a string table and set its caption to "00:00:00"
    Step 5:
    Remove m_wndStatusBar from protected section in CMainFrame.h and add it to public section

    Remove afx_msg void OnUpdateTime(CCmdUI* pCmdUI) function from protected message map and add it to public section

    public:
    afx_msg void OnUpdateTime(CCmdUI* pCmdUI);
    // Generated message map functions
    protected:
    //{{AFX_MSG(CMainFrame)
    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    // NOTE - the ClassWizard will add and remove member functions here.
    // DO NOT EDIT what you see in these blocks of generated code!
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()

    That's all - your timer will live forever!

    This is a sample project that illustrate this method Timer.zip


    Reply
  • Timer is frozen.

    Posted by Legacy on 11/27/1998 12:00am

    Originally posted by: L. Chang

    Because WM_TIMER is a low-priority message, if the program is doing a
    
    time-consuming work and displays the progress at the same time, the
    timer on the status bar is frozen. Any method to keep the timer "alive"?

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • On-demand Event Event Date: September 10, 2014 Modern mobile applications connect systems-of-engagement (mobile apps) with systems-of-record (traditional IT) to deliver new and innovative business value. But the lifecycle for development of mobile apps is also new and different. Emerging trends in mobile development call for faster delivery of incremental features, coupled with feedback from the users of the app "in the wild." This loop of continuous delivery and continuous feedback is how the best mobile …

  • Java developers know that testing code changes can be a huge pain, and waiting for an application to redeploy after a code fix can take an eternity. Wouldn't it be great if you could see your code changes immediately, fine-tune, debug, explore and deploy code without waiting for ages? In this white paper, find out how that's possible with a Java plugin that drastically changes the way you develop, test and run Java applications. Discover the advantages of this plugin, and the changes you can expect to see …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds