DirectUI界面编程(六)实现右键弹出菜单

向右看齐 2022-08-03 05:14 411阅读 0赞

本节向大家介绍一下右键弹出菜单是如何实现的。效果如下,在窗口中点击鼠标右键弹出菜单,点击菜单项能够响应菜单点击事件。
这里写图片描述
使用Duilib库实现的弹出菜单,实际上也是一个Windows窗口,因此我们需要创建两个窗口(主窗口和菜单窗口),然后响应主窗口的鼠标右键点击事件,在主窗口右键点击事件的响应函数中获取鼠标位置,將菜单窗口的位置调整为当前鼠标位置,同时把窗口设置为显示即可。

菜单窗口的xml布局文件内容如下:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <Window bktrans="true" size="120,102">
  3. <Font name="宋体" size="13" bold="false"/>
  4. <Font name="宋体" size="12"/>
  5. <VerticalLayout bkimage="file='menu_bk.png' corner='40,8,8,8'" hole="false">
  6. <List header="hidden" inset="8,8,8,8" itemhotimage="file='menu_hot_bk.png' corner='2,2,2,2'" itemdisabledbkcolor="#20000000">
  7. <ListContainerElement name="menu_Open" height="22" inset="40,0,0,0">
  8. <Label text="打开" mouse="false"/>
  9. </ListContainerElement>
  10. <ListContainerElement name="menu_Mark" height="22" inset="40,0,0,0">
  11. <Label text="标注" mouse="false"/>
  12. </ListContainerElement>
  13. <ListContainerElement name="menu_Delete" height="22" inset="40,0,0,0">
  14. <Label text="删除" mouse="false"/>
  15. </ListContainerElement>
  16. <ListContainerElement name="menu_Test" height="22" inset="40,0,0,0">
  17. <Label text="测试" mouse="false"/>
  18. </ListContainerElement>
  19. </List>
  20. </VerticalLayout>
  21. </Window>

我们需要编写一个菜单窗口类继承WindowImplBase来加载xml界面。和上节不同的是我们把这个类的声明和成员函数的定义放在一个单独的头文件中,这样代码容易维护一些。新建头文件MenuWnd.h:

  1. #ifndef _MENUWND_H__
  2. #define _MENUWND_H__
  3. #include "win_impl_base.hpp"
  4. #include <Windows.h>
  5. class MenuWnd : public WindowImplBase {
  6. LPCTSTR GetWindowClassName() const
  7. {
  8. return L"MenuWnd";
  9. }
  10. UINT GetClassStyle() const{
  11. return UI_CLASSSTYLE_FRAME|CS_DBLCLKS;
  12. }
  13. tString GetSkinFile(){
  14. return L"tutorial6_menu.xml";
  15. }
  16. void Notify(TNotifyUI& msg)
  17. {
  18. if(msg.sType == L"itemclick")
  19. {
  20. //响应菜单事件
  21. ::MessageBox(NULL,L"hello",L"hello",MB_OK);
  22. this->ShowWindow(false);
  23. }
  24. }
  25. };
  26. #endif

接下来是主窗口,主窗口的xml界面布局文件内容和上节相同,仅仅是主窗口类的定义有些变化,我们同样把主窗口类的声明和定义放在一个单独的头文件MyWnd.h中:

  1. #ifndef _MYWND_H__
  2. #define _MYWND_H__
  3. #include "win_impl_base.hpp"
  4. #include "MenuWnd.h"
  5. #include <Windows.h>
  6. class MyWnd : public WindowImplBase
  7. {
  8. public:
  9. MyWnd()
  10. {
  11. pMenu = new MenuWnd();
  12. pMenu->Create(m_hWnd,L"Menu",WS_POPUP,WS_EX_TOOLWINDOW);
  13. pMenu->ShowWindow(false);
  14. }
  15. LPCTSTR GetWindowClassName() const
  16. {
  17. return L"MyWnd";
  18. }
  19. UINT GetClassStyle() const{
  20. return UI_CLASSSTYLE_FRAME|CS_DBLCLKS;
  21. }
  22. tString GetSkinFile(){
  23. return L"tutorial6.xml";
  24. }
  25. void Notify(TNotifyUI& msg)
  26. {
  27. if(msg.sType == L"click")
  28. {
  29. if(msg.pSender->GetName() == L"CloseBtn")
  30. {
  31. ::PostQuitMessage(0);
  32. }else if(msg.pSender->GetName() == L"MinBtn")
  33. {
  34. ::SendMessage(m_hWnd,WM_SYSCOMMAND, SC_MINIMIZE, 0);
  35. }
  36. }
  37. }
  38. LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
  39. {
  40. switch(uMsg)
  41. {
  42. case WM_RBUTTONDOWN:
  43. OnRButtonDown(wParam,lParam);
  44. return 0;
  45. default:
  46. return WindowImplBase::HandleMessage(uMsg,wParam,lParam);
  47. }
  48. }
  49. void OnRButtonDown(WPARAM wParam, LPARAM lParam)
  50. {
  51. int xPos = LOWORD(lParam);
  52. int yPos = HIWORD(lParam);
  53. POINT pt = {xPos,yPos};
  54. ClientToScreen(m_hWnd,&pt);
  55. pMenu->ShowWindow(true);
  56. ::SetWindowPos(pMenu->GetHWND(), NULL, pt.x, pt.y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
  57. }
  58. LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  59. {
  60. //获取鼠标点击位置
  61. int xPos = LOWORD(lParam);
  62. int yPos = HIWORD(lParam);
  63. //將位置转换为屏幕坐标
  64. POINT pt = {xPos,yPos};
  65. ClientToScreen(m_hWnd,&pt);
  66. RECT menuWndRect = {
  67. 0};
  68. ::GetWindowRect(pMenu->GetHWND(),&menuWndRect);
  69. if(pt.x <= menuWndRect.left || pt.x >= menuWndRect.right
  70. || pt.y <= menuWndRect.top || pt.y >= menuWndRect.bottom)
  71. {
  72. pMenu->ShowWindow(false);
  73. }
  74. bHandled = FALSE;
  75. return 0;
  76. }
  77. private:
  78. MenuWnd* pMenu;
  79. };
  80. #endif

在主窗口类中定义一个MenuWnd指针类型的成员变量,在构造函数中创建菜单窗口设置显示风格为隐藏,重写父类的HandleMessage函数,响应主窗口鼠标右键点击事件,在右键点击事件的响应函数中重新设置菜单位置,并把窗口显示风格设置为显示。

最后在WinMain函数中创建并显示主窗口:

  1. //tutorial6.cpp
  2. #include <Windows.h>
  3. #include "MyWnd.h"
  4. INT WinMain(HINSTANCE hInst,HINSTANCE hPreInst,LPSTR lpCmdLine,INT Show)
  5. {
  6. CPaintManagerUI::SetInstance(hInst);
  7. CPaintManagerUI::SetResourcePath(CPaintManagerUI::GetResourcePath());
  8. //创建主窗口
  9. MyWnd* pFrame = new MyWnd();
  10. pFrame->Create(NULL,L"Tutorial6",UI_WNDSTYLE_FRAME,WS_EX_WINDOWEDGE);
  11. pFrame->CenterWindow();
  12. pFrame->ShowWindow(true);
  13. CPaintManagerUI::MessageLoop();
  14. return 0;
  15. }

博文源码:https://github.com/rongbo-j/duilib-tutorial
(参考tutorial6工程)

发表评论

表情:
评论列表 (有 0 条评论,411人围观)

还没有评论,来说两句吧...

相关阅读

    相关 基于Java的菜单源码

    摘要:本文详细介绍了一种基于Java的右键出菜单的设计实现,并提供了带有附录源码示例。通过使用Java的图形用户界面(GUI)组件和事件处理功能,实现了一个具有右键弹出菜单的应

    相关 QT鼠标菜单

    在用QT编程时,有时候要实现鼠标右键弹出菜单的功能.下面代码演示鼠标右键弹出菜单. 1.新建一个QT工程,点击MainWindow.ui,鼠标右键Go to slot....