New MenuDemo-use Duilib to simulate Windows native menu, menudemoduilib

Source: Internet
Author: User

New MenuDemo-use Duilib to simulate Windows native menu, menudemoduilib

I believe that Duilib's friends have been looking forward to this article for a long time, because I mentioned the application of the non-focus window in the menu in my article "Implementation of the non-focus window" published a week ago, I promise you to write a Demo about Menu implementation and share it with you. First, take a look at the effect.


How about Skilla? This work can make you feel at ease. Yes, the menu above is not in cool dog, but in Duilib, which we are familiar.

When talking about menus, we all think of the original MenuDemo. Anyone who has read the original MenuDemo should be aware of its principles. It uses focus to control how menus are destroyed. The focus intervention adds a lot of difficulty to the maintenance of cascading menus, and unnecessary focus switching is also a waste. It is also a very tricky issue to add Keyboard Events. This time, the MenuDemo provided by Skilla has no focus, making it more natural and original. For DirectUI menus, we focus on "simulation". In menu implementation, we should not only simulate the appearance, but also simulate the essence. When we use a window to simulate a menu, we must first touch the internal principle of the Windows native menu implementation, otherwise it will take a lot of detours. Next we will first introduce the mechanism of Windows native menu, first with the previous code.


Int CDuiMenu: RunMenu () {int nRet (-1); BOOL bMenuDestroyed (FALSE); BOOL bMsgQuit (FALSE); while (TRUE) {if (m_menuRet.bExit) {nRet = 0; break;} if (GetForegroundWindow ()! = M_hWndOwner) {break;} BOOL bInterceptOther (FALSE); MSG msg = {0}; if (PeekMessage (& msg, NULL, 0, 0, PM_REMOVE )) {if (msg. message = WM_KEYDOWN | msg. message = WM_SYSKEYDOWN | msg. message = WM_KEYUP | msg. message = WM_SYSKEYUP | msg. message = WM_CHAR | msg. message = WM_IME_CHAR) {// transfer the message to menu Using WIF (m_menus-> IsKeyEvent () {SKILL_ASSERT (m_pKeyEvent-> GetMenuWnd ()-> GetHWND (); msg. hwn D = m_pKeyEvent-> GetMenuWnd ()-> GetHWND () ;}} else if (msg. message = WM_LBUTTONDOWN | msg. message = WM_RBUTTONDOWN | msg. message = WM_NCLBUTTONDOWN | msg. message = WM_NCRBUTTONDOWN | msg. message = WM_LBUTTONDBLCLK) {// click on other javaswif (! IsMenuWnd (msg. hwnd) {DestroyMenu (); // to synchronize with the pop-up message of the menu again: PostMessage (msg. hwnd, msg. message, msg. wParam, msg. lParam); bInterceptOther = true; bMenuDestroyed = TRUE ;}} else if (msg. message = WM_LBUTTONUP | msg. message = WM_RBUTTONUP | msg. message = WM_NCLBUTTONUP | msg. message = WM_NCRBUTTONUP | msg. message = WM_CONTEXTMENU) {if (! IsMenuWnd (msg. hwnd) {// prevent multiple pop-up menus at the same time: PostMessage (msg. hwnd, msg. message, msg. wParam, msg. lParam); break;} else if (msg. message = WM_QUIT) {bMsgQuit = TRUE;} // intercept the MouseMove message in the non-menu window if (msg. message = WM_MOUSEMOVE) {if (! IsMenuWnd (msg. hwnd) {bInterceptOther = TRUE ;}} if (! BInterceptOther) {TranslateMessage (& msg); DispatchMessage (& msg) ;}} else {MsgWaitForMultipleObjects (0, 0, 0, 10, QS_ALLINPUT);} if (bMenuDestroyed) break; if (bMsgQuit) {PostQuitMessage (msg. wParam); break ;}} if (! BMenuDestroyed) {DestroyMenu ();} return nRet ;}

We all know that there is no focus in the menu when there is a "stage" of the keyboard message in the focus, so why does the menu respond when we press VK_UP, VK_DOWN, VK_LEFT, VK_RIGHT, and VK_RETURN on the keyboard? Maybe you still don't believe it. When a menu is popped up, it is blocked internally. It will enable a while loop in it like a DoModel, so that we can control the message direction as we like. When the menu pops up, the message is cyclically created. As long as it is the message of this process, no matter which window it is, it will be here. When receiving a keyboard message, no matter which window, all are allocated to the menu window. When you press the mouse key, you can determine whether the menu window exists. If not, the menu will be destroyed, and the messages retrieved from the message queue will be thrown to the message queue again and will exit cyclically; when the mouse key is popped up, as long as it is not in the menu window, retrieve the message and throw it back to the Message Queue (just like a bottle, catch it and find it does not need to be thrown back again, in fact, the purpose of this operation is to make a transition between the destruction of the menu and the next pop-up. Otherwise, if the previous menu has not been destroyed, this pop-up will be messy ); when there is a MouseMove message, you can block it as long as it is not a menu window, because the MouseMove events in other windows will be blocked when the menu pops up, check whether the native menu of Windows has this effect. When the Owner window switches from the foreground to the background, the menu also needs to be destroyed and exits cyclically. When MenuItem receives a click event, obtain the menu command Id and notify the end of the message loop of the menu. Return the menu command Id and send it to Owne. The r window WM_COMMAD message.

How is the implementation of menus suddenly become open-minded? When implementing cascading menus, you no longer need to consider the focus issue, and the addition of Keyboard Events becomes easier. Menu effects are important, but more importantly, they must be easy to use. If the package is easy to use, it seems that Duilib is not powerful. The Skilla test Duilib is still very powerful. Haha, just kidding. The CContainerUI in Duilib is a control container. For display purposes, we use CContainerUI as our menu container, but it is not directly displayed. We use it as a normal array, why? Of course, it is easy to parse. Because of the need for cascading, menus are naturally not one, so we use CContainerUI as our container to parse them using CDialogBuilder, which is naturally a menu array. This is the outermost tag for menu parsing xml. To add two attributes to it, we inherit CContainerUI, re-create a MenuContainer, override SetAttribute, and add two attributes, one is interval (the interval between two levels of menus. If you don't understand it, try modifying it yourself), and the other is keyevent, which is a bool attribute (whether to enable the keyboard or not ).

MenuContainer contains one menu. For convenience of drawing, we use CListUI as the menu UI and use CListUI as the base class to derive CMenuUI, we can also rewrite SetAttribute to add the required attributes to it. Here I still add two attributes to it, one major (bool type, whether it is the main menu) and one bktrans (bool type, whether to enable transparency). Other attributes follow the CListUI attributes.

CMenuUI contains one menu item. To meet various requirements, Skilla designs two menu items, called MenuItem ), the other is StaticMenuItem. As the name suggests, MenuItem is the real menu item. If you move your mouse over it, there will be a floating event. Press the keyboard to move it up or down to select a menu item; staticMenuItem is the control that has nothing to do with the menu, such as the menu separator, the play button and slide bar on the menu bar of the cool dog. Unbiased, Skilla also gives MenuItem two attributes, one comand (string, return value when the menu message is cyclically exited, which is the basis for the menu command response), and the other extendmenu (string, sub-menu name, which is the key to the cascading of various menus ).

To use this MenuUI, you only need to introduce two files, one MenuUI. h and one MenuUI. cpp. You also need to modify the source code. follow skilla's previous article to modify the CPaintManagerUI so that it supports non-focus windows. modify the AttachDialog, because the CPaintManagerUI will analyze the number of controls bound to the above during the analysis, because all Menu controls are created by calling CDialogBuilder, naturally, we need to destroy it on our own, so in order not to interfere with the CPaintManagerUI, we add a bool m_bAutoDeleteControls attribute and initialize it to false. Add a bool parameter to AttachDialog. The default value is true. m_bAutoDeleteControls is assigned to the function body. Finally, add an if (m_bAutoDeleteControls) judgment to delete m_pRoot In the destructor of CPaintManagerUI. After modification, you can use the MenuUI. h and MenuUI. cpp files.

Finally, let's talk about Skilla's views on Windows interface programming. Although there are many open-source interface libraries, you can come up with one to make a very dazzling interface. However, we cannot be overly infatuated with any interface library. Since you are playing Windows, you cannot forget the book. If you are using Duilib or SOUI, You need to carefully explore the Windows API, because any of our controls are being simulated. In other words, there is no interface library that fully meets all requirements. to be perfect, you have to do it yourself.


Download the source code and Demo. (If any suggestions or bugs are found, leave a message or contact QQ: 848861075 (Skilla). Thank you !)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.