【PB案例学习笔记】-28制作一个右键菜单

写在前面

这是PB案例学习笔记系列文章的第28篇,该系列文章适合具有一定PB基础的读者。

通过一个个由浅入深的编程实战案例学习,提高编程技巧,以保证小伙伴们能应付公司的各种开发需求。

文章中设计到的源码,小凡都上传到了gitee代码仓库https://gitee.com/xiezhr/pb-project-example.git

gitee代码仓库

需要源代码的小伙伴们可以自行下载查看,后续文章涉及到的案例代码也都会提交到这个仓库【pb-project-example

如果对小伙伴有所帮助,希望能给一个小星星⭐支持一下小凡。

一、小目标

基本上所有的应用程序在点击鼠标右键之后都会弹出一个菜单,本案例我们将使用PB实现这个功能。通过鼠标右键,弹出一个命令菜单,

菜单上包含“剪切”、“复制”、“粘贴”、“加粗”等操作标识。这在日常开发中是一个非常常见的功能,一定要学会哈。

最终效果如下所示

右键菜单

二、实现思路

我们将通过引用user32.dll中的GetMenuGetSubMenuTrackPopupMenuGetSystemMetrics等窗体操作函数和LoadImageA

SetMenuItemBitmaps等图形显示函数来实现相关功能。具体函数功能如下

GetMenu函数

用于获取与特定窗口关联的菜单句柄

函数原型:

HMENU GetMenu(HWND hWnd);

参数说明:

hWnd: 一个窗口句柄,指定了要查询其菜单的窗口。

返回值:

成功时,返回窗口的菜单句柄(HMENU)。如果没有菜单关联到该窗口,则返回NULL。

GetSubMenu函数

用于从主菜单中获取指定位置的子菜单

函数原型:

HMENU GetSubMenu(HMENU hMenu, int nPos);

参数说明:

  • hMenu: 主菜单的句柄,即之前通过GetMenu或其他方式获得的菜单句柄。
  • nPos: 一个整数,表示要获取的子菜单在其父菜单中的位置索引,其中0通常是第一个子菜单(顶级菜单项)。

返回值

成功时,返回指定位置的子菜单句柄(HMENU)。如果索引无效或没有子菜单,则返回NULL。

TrackPopupMenu函数

用于在一个指定的位置显示一个弹出式菜单,并跟踪用户的选择。

函数原型:

BOOL TrackPopupMenu(HMENU hMenu,UINT uFlags,int x,int y,int nReserved,HWND hWnd,CONST RECT* prcRect
);

参数说明:

  • hMenu: 要显示的弹出菜单的句柄。
  • uFlags: 控制菜单显示方式的标志,如TPM_LEFTALIGNTPM_RIGHTBUTTON等。
  • x, y: 菜单左上角的屏幕坐标,相对于屏幕原点或指定窗口客户区。
  • nReserved: 在旧版本中保留,应设为0。
  • hWnd: 与菜单显示相关的窗口句柄,用于消息处理。
  • prcRect(旧版)/lptpm(新版,包含x, y, flags, rect等更详细信息的结构体): 用于指定额外的显示参数或限制区域。

返回值:

如果用户选择了菜单项并成功处理,返回非零值;否则,返回0。通常需要检查GetLastError来确定失败原因。

GetSystemMetrics函数

用于获取有关当前系统的各种度量信息和配置设置。这些信息涵盖了显示器分辨率、颜色深度、鼠标和键盘状态、操作系统版本特性等多个方面。

函数原型:

int GetSystemMetrics(int nIndex);

参数说明:

nIndex: 一个整型参数,作为索引值,指定了想要获取的系统度量信息类型。不同的索引值对应不同的系统配置或状态信息。

返回值:

函数根据nIndex所指定的索引值,返回相应的系统度量信息值。返回值类型通常是整数。

LoadImageA函数

用于加载光标、图标、位图或图元文件资源。

函数原型:

HANDLE LoadImageA(HINSTANCE hinst,LPCSTR lpszName,UINT uType,int cxDesired,int cyDesired,UINT fuLoad
);

参数说明:

  • hinst: 一个模块实例句柄,通常为NULL以加载系统资源,或指定的DLL句柄来加载该DLL中的资源。
  • lpszName: 指向资源名称(文件名或资源ID,如图标ID)的指针,可以是字符串或整数资源ID(需要转换为LPCTSTR)。
  • uType: 指定要加载的图像类型,可以是IMAGE_BITMAP, IMAGE_ICON, IMAGE_CURSOR, 或 IMAGE_ENHMETAFILE
  • cxDesired, cyDesired: 指定希望加载图像的宽度和高度(以像素为单位)。如果为0,则使用图像的实际大小。
  • fuLoad: 加载标志,如LR_CREATEDIBSECTION, LR_LOADFROMFILE, LR_DEFAULTSIZE等,用于控制加载行为。

返回值:

成功时返回图像句柄(HBITMAP, HCURSOR, HICON, 或 HENHMETAFILE),失败则返回NULL。

SetMenuItemBitmaps函数

用于设置菜单项的位图图像的API,可以为菜单项的正常状态和选中(或按下)状态指定不同的位图

函数原型:

BOOL SetMenuItemBitmaps(HMENU hMenu,UINT uPosition,UINT uFlags,HBITMAP hBitmapUnchecked,HBITMAP hBitmapChecked
);

参数说明:

  • hMenu: 要修改的菜单的句柄。
  • uPosition: 要设置位图的菜单项的位置索引,从0开始计数。
  • uFlags: 指定要设置哪一组位图的标志,可以是MF_BYCOMMAND(基于菜单项的ID查找)或MF_BYPOSITION(直接使用位置索引)。
  • hBitmapUnchecked: 未选中状态下菜单项的位图句柄。
  • hBitmapChecked: 选中或按下状态下菜单项的位图句柄。

返回值:

函数执行成功返回非零值,失败返回0。可以通过GetLastError获取详细的错误信息

三、创建程序基本框架

① 新建examplework工作区

② 新建exampleapp应用

③ 新建w_main窗口,将其Title设置为"右键菜单"

由于文章篇幅原因,以上步骤不再赘述,如果忘记了的小伙伴可以翻一翻该系列第一篇文章复习一下

④ 新建w_popmenu窗口

⑤ 在w_mian窗口中布局控件

新建一个MultiLineEdit控件和一个CommandButton控件,名称分别为mle_1cb_1,调整控件布局,

并将cb_1Text设置为"关闭"

控件布局

⑥ 设置w_popmenu窗口属性

w_popmenu窗口缩小成一个小方块,并在MenuName属性栏中添加菜单m_popmenu

⑦ 保存w_popmenu窗口

w_popmenu窗口

⑧ 新建m_popmenu菜单如下图所示

新建菜单

四、编写代码

① 在w_main窗口中定义实例变量,代码如下

ulong il_popmenu_window_hwnd

② 在w_main窗口中定义外部函数

FUNCTION ulong GetMenu(ulong hwnd) LIBRARY "user32.dll"FUNCTION ulong GetSubMenu(ulong hMenu,ulong nPos) LIBRARY "user32.dll"FUNCTION ulong TrackPopupMenu(ulong hMenu,ulong wFlags,ulong x,ulong y,ulong nReserved,ulong hwnd,ref Rect lprc) LIBRARY "user32.dll"

③ 在w_main窗口的Open中添加如下代码

open(w_popmenu)il_popmenu_window_hwnd = handle(w_popmenu)

④ 在w_main窗口的close事件中添加如下代码

close(w_popmenu)

⑤ 在mle_1控件的rbuttondown事件中输入如下代码

ulong hmenu,hsubmenu,hwnd
integer li_x,li_yRECT l_rect
l_rect.left = 0
l_rect.top = 0
l_rect.right = 0
l_rect.bottom = 0hmenu = getmenu(il_popmenu_window_hwnd)
hsubmenu = getsubmenu(hmenu, 0)li_x = (xpos + parent.x) / 5
li_y = (ypos + parent.y) / 5TrackPopupMenu(hsubMenu, 2, li_x, li_y, 0, il_popmenu_window_hwnd, l_rect)

⑥ 在cb_1按钮的clicked中添加如下代码

close(parent)return 0

⑦ 在w_popmenu窗口中定义实例变量

//Win32
CONSTANT Integer IMAGE_BITMAP	   = 0
CONSTANT Integer LR_LOADFROMFILE = 16
CONSTANT Integer SM_CXMENUCHECK  = 71
CONSTANT Integer SM_CYMENUCHECK	= 72
CONSTANT Integer MF_BITMAP			= 4
CONSTANT Integer MF_BYPOSITION	= 1024

⑧ 在w_popmenu窗口中定义外部函数

FUNCTION ulong LoadImageA(ulong hintance, string filename,uint utype,int x,int y,uint fload)  LIBRARY "USER32.DLL"FUNCTION boolean SetMenuItemBitmaps(ulong hmenu,uint upos,uint flags,ulong handle_bm1,ulong handle_bm2)  LIBRARY "USER32.DLL"FUNCTION int GetSystemMetrics(  int nIndex ) LIBRARY "USER32.DLL"FUNCTION int GetSubMenu(ulong hMenu,int pos) LIBRARY "USER32.DLL"FUNCTION ulong GetMenu(ulong hWindow) LIBRARY "USER32.DLL"

⑨ 在w_popmenu窗口的open事件中添加如下代码并准备图片

准备图片

**注:**图片资源会一起推送到gitee仓库,需要图片资源的小伙伴克隆仓库即可获取

long		ll_MainHandle
long		ll_SubMenuHandle
long		ll_X
long		ll_Y
long		ll_Bitmapcut
long		ll_Bitmapcopy
long		ll_Bitmappaste
long		ll_Bitmapitl
long 		ll_bitmapcnt
long		ll_bitmapunderlinethis.visible = falsell_MainHandle = GetMenu(Handle(this))ll_SubMenuHandle = GetSubMenu(ll_MainHandle,0)ll_x = GetSystemMetrics(SM_CXMENUCHECK) 
ll_y = GetSystemMetrics(SM_CYMENUCHECK) ll_Bitmapcut = LoadImageA(0,'cut.bmp',  IMAGE_BITMAP ,ll_x,ll_y,LR_LOADFROMFILE)
ll_Bitmapcopy = LoadImageA(0,'copy.bmp',  IMAGE_BITMAP ,ll_x,ll_y,LR_LOADFROMFILE)
ll_Bitmappaste = LoadImageA(0,'paste.bmp',  IMAGE_BITMAP ,ll_x,ll_y,LR_LOADFROMFILE)
ll_Bitmapitl = LoadImageA(0,'itl.bmp',  IMAGE_BITMAP ,ll_x,ll_y,LR_LOADFROMFILE)
ll_Bitmapcnt = LoadImageA(0,'big.bmp',  IMAGE_BITMAP ,ll_x,ll_y,LR_LOADFROMFILE)
ll_bitmapunderline = LoadImageA(0,'ul.bmp',  IMAGE_BITMAP ,ll_x,ll_y,LR_LOADFROMFILE)SetMenuItemBitmaps(ll_SubMenuHandle,0,MF_BYPOSITION,ll_Bitmapcut,ll_Bitmapcut)
SetMenuItemBitmaps(ll_SubMenuHandle,1,MF_BYPOSITION,ll_Bitmapcopy,ll_Bitmapcopy)
SetMenuItemBitmaps(ll_SubMenuHandle,2,MF_BYPOSITION,ll_Bitmappaste,ll_Bitmappaste)
SetMenuItemBitmaps(ll_SubMenuHandle,4,MF_BYPOSITION,ll_Bitmapitl,ll_Bitmapitl)
SetMenuItemBitmaps(ll_SubMenuHandle,5,MF_BYPOSITION,ll_Bitmapcnt,ll_Bitmapcnt)
SetMenuItemBitmaps(ll_SubMenuHandle,6,MF_BYPOSITION,ll_Bitmapunderline,ll_Bitmapunderline)

⑩ 在开发界面左边的SystemTree窗口中双击exampleapp应用对象,并在其open事件中添加如下代码

open(w_main)

五、运行程序

经过一波代码编写之后,我们来验证下结果

右键菜单

本期内容到这儿就结束了★,°:.☆( ̄▽ ̄)/$:.°★ 。 希望对您有所帮助

我们下期再见 ヾ(•ω•`)o (●’◡’●)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/39177.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

任天堂称未来第一方游戏不会使用生成式AI

虽然EA、育碧、暴雪、Embracer等西方游戏厂商都大力支持生成式AI技术,但日本老牌游戏公司任天堂并不会追随这一步伐。任天堂已经确认该公司未来的第一方游戏不会使用生成式AI技术。 在公司最近的投资人问答会上,任天堂描绘了公司未来游戏愿景。在谈到AI技…

LeetCode——第 404 场周赛

周赛 三角形的最大高度 给你两个整数 red 和 blue,分别表示红色球和蓝色球的数量。你需要使用这些球来组成一个三角形,满足第 1 行有 1 个球,第 2 行有 2 个球,第 3 行有 3 个球,依此类推。 每一行的球必须是 相同 …

Go语言--自定义函数

定义格式 函数构成代码执行的逻辑结构。在 Go语言中,兩数的基本组成为:关键字 func、函数名、参数列表、返回值、所数体和返回语句。 函数定义说明: func:函数由关键字func开始声明FuncName:函数名称,根据约定,数名首字母小写即为private…

浅谈 Linux 中的 core dump 分析方法

文章目录 一、什么是 core dump二、发生 core dump 的原因1. 空指针或非法指针引起 core dump2. 数组越界或指针越界引起的 core dump3. 数据竞争导致 core dump4. 代码不规范 三、core dump 分析方法1. 启用 core dump2. 触发 core dump2-1. 因空指针解引用而崩溃2-2. 通过 SI…

图形编辑器基于Paper.js教程06:鼠标画圆与椭圆

绘制椭圆与圆形:利用Paper.js进行交互式图形设计 在Web应用中实现交互式图形绘制功能,对于提高用户体验至关重要,尤其是在设计和艺术相关的应用中。Paper.js是一款强大的JavaScript库,专门用于处理矢量图形,它提供了一…

智能语音门锁:置入NV170D语音芯片ic 打造便捷生活新体验

一、智能门锁语音芯片开发背景 随着科技的飞速发展,传统门锁的局限性日益凸显,无法满足现代人对高效、安全生活的需求。在这样的时代背景下,智能门锁应运而生,它不仅继承了传统门锁的基本功能,更通过融入先进的科技元素…

商标的近似分辩,商标起名称时注意!

曾有过网友发来商标名称,普推知商标老杨说有近似,然后网友起过新名称还是存有近似,或者加字,后面加的通用词,与先有商标名称也是近似。 “良信健康”这个名称健康是行业通用词,加成健康后变成四个字&#x…

HTTP协议深入

1.了解web和网络基础 有客户端和服务端双方参与交互 客户端发送请求:request 服务端根据请求给出响应:response 请求通过URL来指定要获取都得资源 响应内容可以是HTML网页,或者用json表示的数据或者其他二进制文件内容 Web使用一种名为HTTP的协议作为规范&…

AI与大模型工程师证书研修班报名啦!

人工智能大模型是指拥有超大规模参数(通常在十亿个以上)、超强计算资源的机器学习模型,能够处理海量数据,完成各种复杂任务,如自然语言处理、图像识别等。计算机硬件性能不断提升,深度学习算法快速优化&…

ESP32CAM物联网教学03

ESP32CAM物联网教学03 物联网小车 小智突发奇想:要是我在点灯物联APP中多增加几个按钮,控制小车的行驶方向,不就可以做成遥控小车了吗? 点灯物联控制小车的行驶方向 我们可以重新编辑点灯物联APP中的设备控件界面,如…

开关电源中强制连续FCCM模式与轻载高效PSM,PFM模式优缺点对比笔记

文章目录 前言一、连续FCCM模式优点:缺点: 二,轻载高效PSM,PFM优点:缺点: 总结 前言 今天我们来学习下开关电源中,强制连续FCCM模式与轻载高效PSM,PFM模式优缺点对比 一、连续FCCM模式 优点: …

mac中如何恢复因为破解脚本导致的IDEA无法启动的问题

问题 为了在mac中安装免费的2024版idea,导致下载了一个脚本,使用这个脚本后,但是发现idea还没有破解,相反导致idea无法启动,每次点击,都会弹出“cannot start IDE…” 问题排查 在访达中点击mac的应用程…

docker -run hello-world超时

主要原因就是尝试拉取库的时候没有从阿里云镜像里拉&#xff0c;所以设置一下就好了 这里使用的是ubuntu系统&#xff08;命令行下逐行敲就行了&#xff09; sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-EOF {"registry-mirrors": [&quo…

Adobe Acrobat添加时间戳服务器

文章目录 前言一、Adobe Acrobat添加时间戳服务器1.打开Adobe Acrobat软件2.点击【菜单】→ 【首选项】3.点击【安全性】→【更多】4.点击【新建】5.输入【名称】→【服务器URL】 前言 一、Adobe Acrobat添加时间戳服务器 1.打开Adobe Acrobat软件 2.点击【菜单】→ 【首选项…

模拟退火算法1——简介

模拟退火算法来源于固体退火原理&#xff0c;将固体加温至充分高&#xff0c;再让其徐徐冷却&#xff0c;加温时&#xff0c;固体内部粒子随温升变为无序状&#xff0c;内能增大&#xff0c;而徐徐冷却时粒子渐趋有序&#xff0c;在每个温度都达到平衡态&#xff0c;最后在常温…

[C++][设计模式][访问器]详细讲解

目录 1.动机2.模式定义3.要点总结4.代码感受1.代码一2.代码二 1.动机 在软件构件过程中&#xff0c;由于需求的变化&#xff0c;某些类层次结构中常常需要增加新的行为(方法)&#xff0c;如果直接在基类中做这样的更改&#xff0c; 将会给子类带来很繁重的变更负担&#xff0c…

数据恢复篇:5 款最佳 Mac 数据恢复软件

说到保护我们的数字生活&#xff0c;数据恢复软件的重要性怎么强调都不为过。无论您是意外删除了假期照片的普通用户&#xff0c;还是面临硬盘损坏的专业人士&#xff0c;随之而来的恐慌都是普遍存在的。幸运的是&#xff0c;数据恢复工具可以缓解这些压力。在Mac用户可用的众多…

zabbix小白入门:从SNMP配置到图形展示——以IBM服务器为例

作者 乐维社区&#xff08;forum.lwops.cn&#xff09;许远 在运维实践中&#xff0c;Zabbix作为一款强大的开源监控工具&#xff0c;被广泛应用于服务器、网络设备和应用程序的监控&#xff0c;成为保障业务连续性和高效运行的关键。然而&#xff0c;对于Zabbix的初学者来说&a…

人工智能--循环神经网络

个人主页&#xff1a;欢迎来到 Papicatch的博客 课设专栏 &#xff1a;学生成绩管理系统 专业知识专栏&#xff1a; 专业知识 文章目录 &#x1f349;引言 &#x1f349;概述 &#x1f348;基本概念 &#x1f34d;定义 &#x1f34d;结构 &#x1f34c;输入层 &#…

行业模板|DataEase旅游行业大屏模板推荐

DataEase开源数据可视化分析工具于2022年6月发布模板市场&#xff08;https://templates-de.fit2cloud.com&#xff09;&#xff0c;并于2024年1月新增适用于DataEase v2版本的模板分类。模板市场旨在为DataEase用户提供专业、美观、拿来即用的大屏模板&#xff0c;方便用户根据…