Click here to Skip to main content
15,867,453 members
Articles / Desktop Programming / WTL
Article

A generalized CUpdateUI based on a policy design

Rate me:
Please Sign up or sign in to vote.
4.27/5 (5 votes)
21 Jan 20024 min read 73.4K   447   19   9
A policy based implementation of UI updating that accumulates and executes UI changes.

Introduction

Type list is one of more amazing things ever made in C++, weird thing! That's why I prefer C++ to any. Are you familiar with type lists? If not then you have to click here [1] and read. Andrei will explain you better and you'll never regret of it. I've overhauled the previous edition using the type list and was excited of how it made easy a lot of things.

There is the CUpdateUI class template in WTL that manages UI elements updating, and I like that. In most of cases it's what we need. The thing that made me thinking of another implementation is the way the CUIUpdate may be extended to have more functionality. You would have one option in deriving from CUpdateUI or CUpdateUIBase. Seems that would be mess and awkward. I thought it would be nice to have a CUpdateUI generalization based on a policy design. The benefits of such a model are:

  • it's extendable; to add new feature, we never should rewrite it wholly; 
  • it's adjustable; having put another policy in set of policies, we get more functionality; 
  • it has high performance. 

I attempted to do so.

Implementation

I thought it looks as that:

class CMainFrame :
    public CFrameWindowImpl<CMainFrame>,
    public CUIStates<StatePolicy1, StatePolicy2, ...>,
    public CUIUpdate<CMainFrame, UIPolicy1, UIPolicy2, ...>
{
    ...
};

The CUIStates is a class template that accumulate changes of UI which the CUIUpdate has to apply. Each StatePolicyNs supports a specific kind of change. The CUIUpdate shows changes that have been made in the CUIStates. It has a set of UIPolicyNs; each of them supports specific kind of user interface. Both the CUIStates and the CUIUpdate can have an arbitrary set of policies. You may specify up to 32 policies. If you took a look at the definition of the CUIStates you would see something like that:

struct nil {}

template
<
	typename S01 = nil, typename S02 = nil, typename S03 = nil,
	typename S04 = nil, typename S05 = nil, 
	...
	typename S31 = nil, typename S32 = nil
> 
class CUIStates : 
	...

What is last ellipsis (...)? It's a stuff that derives CUIStates from parameters SXX which are not nil. That's where the type list works and it's a kind of magic. It could be a subject for another article. Well, a compiler has lots of work to exclude from run-time an unused code. The CUIUpdate has been done in the same manner.

Here is the WTL wizard equal code that updates "Toolbar" and "Status Bar" menu's items:

class CMainFrame : 
    public CUIStates<CStyle>,
    public CUIUpdate<CMainFrame, CUICommand<CMainFrame> >,
    ...
{
    ...
    virtual BOOL OnIdle()     {
        UIUpdate();    // CUIUpdate method
        return FALSE;
    }

    BEGIN_MSG_MAP(CMainFrame)
        MESSAGE_HANDLER(WM_CREATE, OnCreate)

        // Does the same as CHAIN_MSG_MAP(CUpdateUI<CMainFrame>)
        // Updates popup menus and checks accelerators 
        CHAIN_MSG_MAP(CUICommand<CMainFrame>)

        COMMAND_ID_HANDLER(ID_VIEW_TOOLBAR, OnViewToolBar)
        COMMAND_ID_HANDLER(ID_VIEW_STATUS_BAR, OnViewStatusBar)
        ... 
    END_MSG_MAP()

    LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, 
                     BOOL& /*bHandled*/) {
        ...

        // CStyle methods
        UIAddStyle(ID_VIEW_TOOLBAR, CStyle::Enable|CStyle::Visible|CStyle::Checked);
        UIAddStyle(ID_VIEW_STATUS_BAR, CStyle::Enable|CStyle::Visible|CStyle::Checked);

        ...
        return 0;
    }
    LRESULT OnViewToolBar(WORD /*wNotifyCode*/, WORD /*wID*/, 
                          HWND /*hWndCtl*/, BOOL& /*bHandled*/) {
        bool bVisible = !::IsWindowVisible(m_hWndToolBar);
        ::ShowWindow(m_hWndToolBar, bVisible ? SW_SHOWNOACTIVATE : SW_HIDE);
        UISetCheck(ID_VIEW_TOOLBAR, bVisible);    // CStyle method
        UpdateLayout();
        return 0;
    }
    LRESULT OnViewStatusBar(WORD /*wNotifyCode*/, WORD /*wID*/, 
                            HWND /*hWndCtl*/, BOOL& /*bHandled*/) {
        bool bVisible = !::IsWindowVisible(m_hWndStatusBar);
        ::ShowWindow(m_hWndStatusBar, bVisible ? SW_SHOWNOACTIVATE : SW_HIDE);
        UISetCheck(ID_VIEW_STATUS_BAR, bVisible);    // CStyle method
        UpdateLayout();
        return 0;
    }
    ...
};

The CStyle policy supports flags of command IDs such as enable/disable, visible/hidden, checked/unchecked. The CUICommand supports updates of popup menus and handles accelerator keys. Thus, the CUICommand requires that the CUIState has the CStyle; but what would be if it had not? Nothing, the CUICommand just does nothing and I ensure you that the CUICommand doesn't have such an ugly code as:

if(Does_CUIState_Have_CStyle()) {
	// translates accelerators
}
else {
	// does nothing
}

All of job done by a compiler at compile-time, there's no such "if". Do you think it's not right? Then you are in bad place, please, close your browser.

If we wanted to manage text labels of items we should add a CText state policy and use its methods to be in control of UI changes:

class CMainFrame :
public CUIStates<CStyle, CText>,
public CUIUpdate<CMainFrame, CUICommand<CMainFrame> >,
...

To manage toolbar's buttons just rewrite:

class CMainFrame :
public CUIStates<CStyle, CText>,
public CUIUpdate<CMainFrame, CUICommand<CMainFrame>, CUIToolBar<CMainFrame> >,
...

To manage a status bar: CUIStatusBar, a rebar: CUIReBar.

If you had your own control you might implement CUIUpdate policy and thus add the control to that model. Moreover we may specify our own state policy and enlarge functionality of existing CUIToolBar, CUIStatusBar.

How to add new state and UI policies

The sample project shows how to implement state policy called CParts that manages number and widths of status bar parts and how to make CUIStatusBar extended to change the status bar according to changes in CParts.

State policy is supposed to have three function:

bool dirty(ui_type id) const
void clean(ui_type id)
void set_default_value()

dirty and clean support dirty flags; the same as in WTL's CUpdateUI. set_default_value changes values of state to default ones if state has them; it's made for easy MDI interface support. That's enough to compile it with CUIStates. The others methods are at discretion, they are going to be used at changes applying code of UI elements.

The requirement for UI policy is that it should have a following templated function:

template<class State>
void update_state(HWND hwnd, const State& state) {}

Thus, if an UI policy doesn't support specified kind of a state policy then it does nothing; if we wanted it to support, say, CText then it should have function as following:

void update_state(HWND hwnd, CText& state) {
...
}

For details, you should see a source code.

A couple of words about efficiency. Both the CUIStates and the CUIUpdate made by aggressively using of generic programming techniques; they have no virtual function. So performance is very high. For comparison, release size of binary generated by WTL wizard is the same. There're two implementations, specifying #include <map> before #include <wtlx/ui_update.hpp> we switch to STL library from CSimpleMaps and CStrings.

I think using such techniques will make a future of C++ libraries. What is WTL going to be? Will see, I just hope that isn't a MFC2. What is the reason of some things as CString? To make MFC programmers feel themselves comfortable? Well, well, well...

Acknowledgements

[1] Andrei Alexandrescu. Generic<Programming>: Typelists and Applications

[2] Andrei Alexandrescu. Generic<Programming>: Mappings between Types and Values.

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
Web Developer
Russian Federation Russian Federation
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralAcknoledgement links are broken. Pin
Nathan Holt23-Jan-05 10:25
Nathan Holt23-Jan-05 10:25 
GeneralNot exist atlres.h file Pin
vision14-Jan-02 15:26
vision14-Jan-02 15:26 
GeneralRe: Not exist atlres.h file Pin
Voinkov14-Jan-02 21:26
Voinkov14-Jan-02 21:26 
Generalany idea on how to handle update UI in case of dialog apps. Pin
Hawkeye8-Jan-02 15:48
Hawkeye8-Jan-02 15:48 
GeneralRe: any idea on how to handle update UI in case of dialog apps. Pin
Voinkov8-Jan-02 22:27
Voinkov8-Jan-02 22:27 
GeneralSuggestion Pin
Yury Sulsky6-Jan-02 9:43
Yury Sulsky6-Jan-02 9:43 
GeneralRe: Suggestion Pin
Voinkov8-Jan-02 1:58
Voinkov8-Jan-02 1:58 
Thank you, Yury for good point.
Nested policies allow to eliminate that restriction on CUIStates. What about CUIUpdate, seems it could be done in same manner, but it would be more complicated. The thing is that the type of dirty flags depends on the maximum number of policies.
I'll think.

Vladimir
GeneralRe: Suggestion Pin
Yury Sulsky10-Jan-02 10:58
Yury Sulsky10-Jan-02 10:58 
GeneralRe: Suggestion Pin
Voinkov11-Jan-02 4:45
Voinkov11-Jan-02 4:45 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.