Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

The Port of MFC Updating Command UI Mechanism

0.00/5 (No votes)
14 Sep 2005 1  
A replacement for the CUpdateUI using event-driven architecture.

Motivation

WTL's CUpdateUI goes against the policy of ATL. BEGIN_MSG_MAP is a set of function calls, but WTL's BEGIN_UPDATE_UI_MAP is a set of data. It makes your program uncontrollable especially in the case of MDI applications. See the WTL sample, MDIDocVw. It is impossible to understand. Therefore, CUpdateUI should be replaced.

So, Ketchup.CmdUI provides a port of MFC Update Command UI mechanism, which is the only good thing MFC has left.

Requirements

Quick start

  1. Include the header:
    #include "ketchup/cmd_ui.hpp"
  2. Define CmdUI handlers:
    void OnUpdateViewStatusBar(ketchup::cmd_ui& ui)
    {
      ui.set_check(::IsWindowVisible(m_hWndStatusBar));
    }
  3. Add the handlers to message map:
    BEGIN_MSG_MAP(CMDIFrame)
      // ...
    
      KETCHUP_CMD_UI_HANDLER(ID_VIEW_STATUS_BAR, 
                               OnUpdateViewStatusBar)
    END_MSG_MAP()
  4. Add CmdUI generators:
    virtual BOOL OnIdle()
    {
      ketchup::update_toolbar_cmd_ui(m_hWnd, m_ToolBar);
      return FALSE;
    }
    BEGIN_MSG_MAP(CMDIFrame)
      // ...
    
      KETCHUP_UPDATE_MENU_CMD_UI()
    END_MSG_MAP()

Ketchup.CmdUI is an event-driven architecture. You can determine the state of UI using the code instead of data. To begin with, CUpdateUI is inconsistent with Win32.

Basic concepts

  • CmdUI

    A CmdUI is an object that is derived from ketchup::cmd_ui.

  • CmdUI generator

    A CmdUI generator is anything that generates a CmdUI and sends it to the window that handles it.

  • Dependent CmdUI

    A dependent CmdUI is any CmdUI that doesn't have the ID for itself. is_dependent represents the dependency.

ketchup::cmd_ui

This class is a port of MFC's CCmdUI:

struct cmd_ui
{
  UINT get_id() const;
  void set_handled(bool on);
  bool is_handled() const;

  virtual void enable(bool on);
  virtual void set_check(int state);
  virtual void set_radio(bool on);
  virtual void set_text(LPCTSTR pszText);
  virtual void set_default(bool on);
  virtual bool is_dependent();
};

The semantics of the members is the same as that of CCmdUI, but the default arguments are rejected.

Predefined CmdUI generators

KETCHUP_UPDATE_MENU_CMD_UI

This is an entry of BEGIN_MSG_MAP that makes a CmdUI from a menu item.

ketchup::update_toolbar_cmd_ui

This makes a CmdUI from a toolbar button item.

Nested pop-up menu

A CmdUI generated from a pop-up menu is a model of the dependent CmdUI. A pop-up menu cannot have an ID for itself, so it depends on the first menu item. See the MFC's document Nested Pop-up Menus. MFC's syntax is somewhat awkward. The ketchup::cmd_ui provides a member called is_dependent:

void OnUpdatePopupSubmenu(ketchup::cmd_ui& ui)
{
  if (ui.is_dependent())
    ui.enable(m_popup_enabled);
}

Note that all the top-level menu items like the File, Edit and etc. can be made dependent if you use the chevron menu of WTL::CCommandBarCtrl.

CmdUI chain

The KETCHUP_CHAIN_CLIENT_CMD_UI and KETCHUP_CHAIN_MDI_CHILD_CMD_UI are provided. The roles are the same as those of CHAIN_CLIENT_COMMANDS or CHAIN_MDI_CHILD_COMMANDS of WTL.

Automatic disabling

Each MDI child has a different set of commands. The MDI framework provides dynamic menus, but what would you do with the toolbar? What would you do if you want to share menus among the MDI children? So KETCHUP_ENABLE_CMD_UI_IF_HANDLED_BY_MDI_CHILD chains and disables CmdUI automatically:

typedef ketchup::idset<
  ID_BLACK, ID_RED, ID_GREEN, ID_BLUE, ID_WHITE,
  ID_CUSTOM, ID_SPEED_SLOW, ID_SPEED_FAST
> child_cmd_ids;

BEGIN_MSG_MAP(CMDIFrame)
  // ...

  KETCHUP_ENABLE_CMD_UI_IF_HANDLED_BY_MDI_CHILD(child_cmd_ids)
END_MSG_MAP()

MFC can disable CCmdUI in response to whether or not WM_COMMAND is handled, but WTL cannot. So Ketchup.CmdUI disables CmdUIs in response to whether or not CmdUI is handled, that is to say, whether an MDI child has KETCHUP_CMD_UI_HANDLER entry or not. Note that you should specify the target set of commands using ketchup::idset.

References

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