【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_y

RECT l_rect
l_rect.left = 0
l_rect.top = 0
l_rect.right = 0
l_rect.bottom = 0

hmenu = getmenu(il_popmenu_window_hwnd)
hsubmenu = getsubmenu(hmenu, 0)

li_x = (xpos + parent.x) / 5
li_y = (ypos + parent.y) / 5

TrackPopupMenu(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_bitmapunderline

this.visible = false


ll_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.mfbz.cn/a/769430.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

流量控制组件选型之 Sentinel vs Hystrix

Sentinel: Sentinel 是阿里中间件团队研发的面向分布式服务架构的轻量级高可用流量控制组件,于2018年7月正式开源。Sentinel 主要以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度来帮助用户提升服务的稳定性。大家可能会问:Sen…

总线局域网及解决冲突的方案

上文内容:局域网 1.什么是总线局域网 总线网结构: 所有的结点通过专门的网卡附接到一条总线上; 所有结点的信息都发送到同一条总线上(冲突); 所有结点都从同一媒体上收取信息(广播&am…

视频汇聚/安防监控/GB28181国标EasyCVR视频综合管理平台出现串流的原因排查及解决

安防视频监控系统/视频汇聚EasyCVR视频综合管理平台,采用了开放式的网络结构,能在复杂的网络环境中(专网、局域网、广域网、VPN、公网等)将前端海量的设备进行统一集中接入与视频汇聚管理,视频汇聚EasyCVR平台支持设备…

Stable Diffusion web UI 插件

2024.7.3更新,持续更新中 如果需要在linux上自己安装sd,参考:stable diffusion linux安装 插件复制到 /stable-diffusion-webui/extensions 目录下,然后重新启动sd即可 一、插件安装方法 每种插件的安装方法可能略有不同&#xf…

Redis分布式锁的应用场景有哪些

⼀ 、应⽤场景 在多线程并发的场景下 ,Java Synchronized/Reentrantlock 锁能够实现同⼀个JVM进程内多线程 并发的安全性 ,但⽆法保证多个JVM进程实例构成的集群环境在多线程下的安全性。在⼀些业务场景 下需要引⼊分布式锁。 1、缓存击穿 当某个热点缓…

精确计算应用的冷启动耗时

在iOS项目中,冷启动时间是指从用户点击应用图标开始,到应用完全加载并呈现出第一个界面(可能需要网络请求必要的数据)所花费的时间。这里以 main 函数为界,分为两个时间段: 从用户点击应用图标 ~ invoke m…

深度学习简介-AI(三)

深度学习简介 深度学习简介深度学习例子深度学习训练优化1.随机初始化2.优化损失函数3.优化器选择4.选择/调整模型结构 深度学习常见概念隐含层/中间层随机初始化损失函数导数与梯度优化器Mini Batch/epoch 深度学习训练逻辑图 深度学习简介 深度学习例子 猜数字 A: 我现在心…

24年河南特岗教师招聘流程+报名流程

河南特岗教师报名流程如下 1.登录河南省特岗招聘网 登录河南省特岗招聘网注册账号和密码,账号可以是手机号或者身份证号,密码自己设置 2.注册登录账号 注册完账号重新登录账号,输入身份证号、手机号、密码、验证码 3.浏览考试须知 填写个人信…

Unity Shader技巧:实现带投影机效果,有效避免边缘拉伸问题

这个是原始的projector 投影组件,边缘会有拉伸 经过修改shader 后边缘就没有拉伸了 (实现代码在文章最后) 这个着色器通过检查每个像素的UV坐标是否在定义的边界内,来确定是否应用黑色边框。如果UV坐标处于边缘区域,那么像素颜色会被强制设为黑色,从而在投影图像周围形成一…

JWT入门

JWT与TOKEN JWT(JSON Web Token)是一种基于 JSON 格式的轻量级安全令牌,通常用于在网络应用间安全地传递信息。而“token”一词则是一个更广泛的术语,用来指代任何形式的令牌,用于在计算机系统中进行身份验证或授权。J…

云原生技术架构详解

云原生技术最全详解(图文全面总结) 容器技术 容器技术:是将应用程序、及其所有依赖项,打包到一个独立的、可移植的容器中。 如下图所示: 容器技术的实现,最典型的就是以Docker为代表的。 如下图所示: 主要解决: 1、…

【ROS中Cjson文件的作用】

在ROS (Robot Operating System) 中,.json 文件通常用于存储配置信息、数据序列化或者在某些情况下用于网络通信和数据交换。JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于…

UE4_材质_使用彩色半透明阴影

学习笔记,不喜勿喷!侵权立删,祝愿大美临沂生活越来越好! 本教程将介绍如何配置虚幻引擎来投射彩色半透明阴影。 此功能在许多应用中都很有用,常见例子就是透过彩色玻璃窗的彩色光。 一、半透明阴影颜色 阴影在穿过半…

【Python机器学习】模型评估与改进——带交叉验证的网格搜索

虽然将数据划分为训练集、验证集、测试集的方法是可行的,也相对常用,但这种方法对数据的划分相当敏感,为了得到对泛化性能的更好估计,我们可以使用交叉验证来评估每种参数组合的性能,而不是仅将数据单次划分为训练集与…

模拟退火算法2—优缺点

模拟退火算法优点 1、以一定的概率接受恶化解 模拟退火算法(SA)在搜索策略上与传统的随机搜索方法不同,它不仅引入了适当的随机因素,而且还引入了物理系统退火过程的自然机理。这种自然机理的引入使模拟退火算法在迭代过程中不仅接受使目标函数变“好”的试探点,而且还能以一…

Hadoop权威指南-读书笔记-02-关于MapReduce

Hadoop权威指南-读书笔记 记录一下读这本书的时候觉得有意思或者重要的点~ 还是老样子~挑重点记录哈😁有兴趣的小伙伴可以去看看原著😊 第二章 关于MapReduce MapReduce是一种可用于数据处理的编程模型。 MapReduce程序本质上是并行运行的&#xff0c…

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

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

网络安全--计算机网络安全概述

文章目录 网络信息系统安全的目标网络安全的分支举例P2DR模型信息安全模型访问控制的分类多级安全模型 网络信息系统安全的目标 保密性 保证用户信息的保密性,对于非公开的信息,用户无法访问并且无法进行非授权访问,举例子就是:防…

Andriod安装termux并换源

问题汇总 Error: The repository ‘https://mirrors.tuna.tsinghua.edu.cn/termux/termux-package-24 stable Release’ does not have a Release file. 更换源(这里使用的是清华大学源) 打开文件 nano $PREFIX/etc/apt/sources.list手动修改 deb htt…

Powershell 获取电脑保存的所有wifi密码

一. 知识点 netsh wlan show profiles 用于显示计算机上已保存的无线网络配置文件 Measure-Object 用于统计数量 [PSCustomObject]{ } 用于创建Powershell对象 [math]::Round 四舍五入 Write-Progress 显示进度条 二. 代码 只能获取中文Windows操作系统的wifi密码如果想获取…