Topic : Menus
Author : Unknown
Page : << Previous 2  Next >>
Go to page :


on to add more features to the mainframe menu. Class CCmdUI has another useful member function CCmdUI::SetText(...), which allows us to change the text of a menu item dynamically. By using this function, we can change the text of Edit | Paste menu item so that it can convey more information to the user. For example, we could set text to "Do not paste" when data is not available, and to "Please paste" when data is available. To add this feature, all we need is to call CCmdUI::SetText(...) in the above message handler as follows:

void CMenuDoc::OnUpdateEditPaste(CCmdUI* pCmdUI)

{

pCmdUI->Enable(m_bPasteAvailable);

pCmdUI->SetText(m_bPasteAvailable ? "Please &paste":"Do not &paste");

}


Checking a Menu Item

Let's further add some more interesting features to the menu commands. With the current implementation we do not know if the data has been "Pasted" after it is "cut" or "copied" to the "clipboard". We can indicate the data status by putting a check mark on the menu item so the user knows if the current "data" in the "clipboard" has been pasted (after the user executes View | Paste command). This check will be removed when either "cut" or "copy" command is executed.

Similar to tool bar, we can call function CCmdUI::SetCheck(...) to set check for a menu item. The difference between the results of this function is the changing on the interface: while setting check for a button will make it recess, setting check for a menu item will put a check mark at the left side of the menu item.

We need a new Boolean type variable to indicate the status of "data". In the sample application, this variable is CMenuDoc::m_bDataPasted, which is initialized to FALSE in the constructor. The following functions show how its value is changed under different situations:

void CMenuDoc::OnEditCopy()
{

m_bPasteAvailable=TRUE;

m_bDataPasted=FALSE;

}

void CMenuDoc::OnEditCut()

{

m_bPasteAvailable=TRUE;

m_bDataPasted=FALSE;

}

void CMenuDoc::OnEditPaste()

{

m_bDataPasted=TRUE;

}


In function OnUpdateEditPaste(...), the menu item is checked only when flag CMenuDoc:: m_bDataPasted is TRUE:

void CMenuDoc::OnUpdateEditPaste(CCmdUI* pCmdUI)

{

pCmdUI->Enable(m_bPasteAvailable);

pCmdUI->SetCheck(m_bDataPasted);

pCmdUI->SetText

(

m_bPasteAvailable ?

(

m_bDataPasted ? "Data &pasted":"Please &paste"):

"Do not &paste"

);

}


The text of the menu item is also change to "Data pasted" when the menu item is checked.

The last thing need to be mentioned here is another member function of class CCmdUI: CCmdUI:: SetRadio(...). Like CCmdUI::SetCheck(...), this function will put a check mark on a menu item. The difference between two functions is that CCmdUI::SetRadio(...) makes menu items behave like radio buttons: when this function is called to check one item, all other items in the same group will be unchecked automatically. Calling function CCmdUI::SetCheck(...) does not affect other menu items.

2 Right Click Pop Up Menu

In Windows 95, right-click menu becomes a standard user interface. We can right click on the desktop, task bar, or other types of windows to bring up a menu that contains the most commonly used commands. In this section, we will discuss how to add right-click menu to our application.

Adding Menu Resource

Sample 2\Menu demonstrates right-click menu implementation. It is a standard SDI application generated by Application Wizard with all the default settings. This is the same with the previous sample. We can also start from sample 1\Menu and add the new features that will be discussed below.

Like tool bar and dialog bar, a menu can be implemented starting from building menu resource. To add a menu resource, We can execute Insert | Resource command in Developer Studio, select "menu" resource type from the popped up dialog box, and click button "New". Now a new menu resource with a default ID will be added to the application. In the sample, this default ID is changed to IDR_MENU_POPUP, and a sub-menu with four menu items is created. The newly created menu items are "Pop Up Item 1", "Pop Up Item 2", "Pop Up Item 3" and "Pop Up Item 4", whose command IDs are ID__POPUPITEM1, ID__POPUPITEM2, ID__POPUPITEM3 and ID__POPUPITEM4 respectively (Figure 2-1).

Trapping Right Button Clicking Event

The first step to implement a right-click menu is to detect mouse's right clicking event, which is a standard Windows( event, and its corresponding message is WM_RBUTTONDOWN. To trap this message, we need to implement message handler.

When we click mouse's right button on a window, message WM_RBUTTONDOWN will be sent to that window. This window could be any type: mainframe window, client window, dialog box, or even button.

We need to handle this message in the class that implements the window. For example, if we want to handle right click in a dialog box, we need to add the message handler in a CDialog derived class, if we want to handle it in the client window of an SDI application, we need to add the message handler in CView derived class.

In our sample, right-clicking menu is implemented in the client window. So we need to trap message WM_RBUTTONDOWN in class CMenuView.

Adding message handler for message WM_RBUTTONDOWN is similar to that of WM_COMMAND: first we need to declare an afx_msg type member function OnRButtonDown(...), then use ON_RBUTTONDOWN macro to map the message to this function. Finally, we need to implement the message handler. Please note that OnRButtonDow(...) is the standard function name that will be automatically associated with message WM_RBUTTONDOWN. When using ON_RBUTTONDOWN macro, we do not need to specify function name.

The above-mentioned procedure can be implemented through using Class Wizard as follows: after invoking the Class Wizard, select class CMenuView, which is the class used to implement the client window. There are a lot of virtual functions and messages listed in the "Messages" window. By scrolling the vertical scroll bar, it is easy to find message WM_RBUTTONDOWN. Now highligh this message and click "Add function" button. This will cause a new member function OnRButtonDown to be added to class CMenuView, and message mapping macros to be added to the implementation file (See Figure 2-2).

In the sample, the newly added function is CMenuView::OnRButtonDown(...), which needs to be modified to implement right-click menu. By default, this function does nothing but calling the message handler implemented by the base class:

void CMenuView::OnRButtonDown(UINT nFlags, CPoint point)
{

CView::OnRButtonDown(nFlags, point);

}


Using Class CMenu

We need to modify the above function in order to implement right-click pop up menu. In MFC, there is a class designed for menu implementation: CMenu, which contains some member functions that allow us to create menu dynamically, track and update menu items, and destroy the menu.

The first function we will use is CMenu::LoadMenu(...), it allows us to load a menu resource and use it later. This function has two different versions, one allows us to load a menu resource with a numerical ID, and the other allows us to load a resource with a string ID:

BOOL LoadMenu(LPCTSTR lpszResourceName);

BOOL LoadMenu(UINT nIDResource);


In the sample application, the menu resource is stored by a numerical ID (IDR_MENU_POPUP). We can also assign a string ID to it by inputting a quoted text in the edit box labeled with "ID".

We need to use CMenu to declare a variable that will be used to load the menu resource. Normally the right-click menu will be initiated after right-clicking event has been detected. Then the mouse's activities will be tracked by the menu until the user executes one of the menu commands or dismisses the menu. Because all these things can be handled within the message handler, the variable used to implement menu can be declared as a local variable. In the sample, the menu resource is loaded as follows:

void CMenuView::OnRButtonDown(UINT nFlags, CPoint point)
{

CMenu menu;

menu.LoadMenu(IDR_MENU_POPUP);

CView::OnRButtonDown(nFlags, point);

}


Generally, one menu contains several sub-menus, and each sub-menu contains several menu items. For right click menu, only one sub-menu (instead of whole menu) will be implemented each time the user clicks mouse's right button. Because of this, in the sample application, menu IDR_MENU_POPUP contains only one sub-menu. To obtain a pointer to the sub-menu, we can call function CMenu::GetSubMenu(...), which has the following format:

CMenu *Cmenu::GetSubMenu(int nPos) const;

Parameter nPos indicates which sub-menu we are trying to obtain. In a menu resource, the left-most sub-menu is indexed 0, next sub-menu indexed 1, and so on. In the sample application, sub-menu that contains items "Pop Up Item 1"... is located at position 0.

This function returns a CMenu type pointer that could be used to further access each item contained in the sub-menu. Before the menu is displayed, we may want to set the state of each menu item: we can enable, disable, set check or change text for a menu item. Please note that for a right-click menu, we do not need to handle message UPDATE_COMMAND_UI in order to set the states of menu items. Instead, there exist two member functions that can be used:

UINT CMenu::EnableMenuItem(UINT nIDEnableItem, UINT nEnable);

UINT CMenu::CheckMenuItem(UINT nIDCheckItem, UINT nCheck);


The above two functions can be used to enable/disable, set/remove check for a menu item. When calling the two functions, we can reference a menu item by using either its command ID or its position. Normally we can pass a command ID to nIDEnableItem or nIDCheckItem parameter. If we want to reference an item by its position (0 based, for example, in the sample application, ID__POPUPITEM1's position is 0, and ID__POPUPITEM2's position is 1...), we need to set MF_BYPOSITION bit of nEnable or nCheck parameter.

The menu

Page : << Previous 2  Next >>