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

news2024/12/25 12:44:01

写在前面

这是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.coloradmin.cn/o/1892681.html

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

相关文章

多态相关知识2

多态相关知识2 抽象基类和纯虚函数纯虚函数和多继承虚析构函数虚析构函数作用纯虚析构函数 重写 重载 重定义 抽象基类和纯虚函数 在设计时,常常希望基类仅仅作为其派生类的一个接口。这就是说,仅想对基类进行向上类型转换,使用它的接口&…

Wing FTP Server

文章目录 1.Wing FTP Server简介1.1主要特点1.2使用教程 2.高级用法2.1Lua脚本,案例1 1.Wing FTP Server简介 Wing FTP Server,是一个专业的跨平台FTP服务器端,它拥有不错的速度、可靠性和一个友好的配置界面。它除了能提供FTP的基本服务功能以外&#…

据阿谱尔APO Research统计,2023年全球皮肤科药物市场价值为 751.7 亿美元

据阿谱尔 (APO Research)统计,2023 年全球皮肤科药物市场价值估计为 751.7 亿美元,预计到 2030 年将达到 1622.1 亿美元,预测期内(2024-2030 年)的复合年增长率为 11.44%。 全球最大的单一类别皮肤科药物是…

TheBrain 14:AI增强的视觉知识管理工具

TheBrain是一款与众不同的思维导图软件,其所有信息通过一个又一个的节点进行联系,最终形成一个杂而不乱的网状结构。与传统的树形思维导图相较而言,TheBrain更有助于整合零散的资源,激发创意和锻炼思维。此次thebrain13带来了很多…

基因组学系列3:基因分型Phasing与单倍型参考序列HRC

1. 基因分型Phasing概念 基因分型,也称为基因定相、单倍体分型、单倍体构建等,即将一个二倍体(或多倍体)基因组上的等位基因(或杂合位点)正确定位到父亲或母亲的染色体上,最终使得来自同一亲本…

HMI 的 UI 风格成就经典

HMI 的 UI 风格成就经典

【自动驾驶仿真在做什么——初学者总结(陆续补充)】

文章目录 基础概念自动驾驶级别再稍提一下ODD是什么? 自动驾驶仿真分类软件在环仿真硬件仿真 仿真究竟难在哪?一些名词解释 最近也是学习自动驾驶仿真相关知识,习惯去总结一下,方便自己回顾和总结,主要包括了自动驾驶框…

登 Cell 子刊!清华大学张强锋课题组开发 SPACE 算法,组织模块发现能力领先同类工具

多细胞生物中的细胞尽管共享相同的基因组,但因其内部基因调控网络的差异以及与周围微环境中相邻细胞的外部信号交流,使得它们在形态、基因表达和功能上展现出显著的多样性。为了将细胞类型信息与其在组织内的空间位置相关联,空间转录组学 (Sp…

OpenLCA、GREET、R语言的生命周期评价方法、模型构建

原文链接:OpenLCA、GREET、R语言的生命周期评价方法、模型构建教程https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247608240&idx6&sn1b5758206d500399fe7cc69e800f61fe&chksmfa826657cdf5ef413d31557941a1c5db5cc84bba8d0f408c469e05a4118c…

软考的报名详细流程

2024年软考的考试时间已经公布,分别为5月25日至28日和11月9日至12日。准备参加2024年软考的朋友们,一定要提前关注官方发布的考试安排。 本文将详细介绍软考报考的整个流程。准备报考的朋友们,阅读本文就足够啦!软考的报考流程大致…

Vant Design - VUE 时间区间限制

效果图&#xff0c;限制7天 实现代码 <a-range-picker v-model"dateTime" style"width: 100%" :disabled-date"disabledDate" format"YYYY-MM-DD HH:mm:ss" :showTime"true" :placeholder"[开始时间, 结束时间]&quo…

Vue 解决报错 VM6290:1 Uncaught SyntaxError: Unexpected identifier ‘Promise‘

Vue 报错 VM6290:1 Uncaught SyntaxError: Unexpected identifier ‘Promise’ 排查 控制台报了一个错误 , Uncaught SyntaxError: Unexpected identifier ‘Promise’&#xff0c;网上查到的方法是 缺少符号&#xff0c;语法写法错误&#xff0c;但这些都没有解决我的问题&am…

Simulink 模型生成 C 代码(三):将模型参数配置为全局变量以在运行时调整

默认情况下&#xff0c;代码生成优化可避免存储不参与入口函数接口的模型参数和大多数信号。要使参数可调和相关信号可访问&#xff0c;请通过显式配置方式来标识它们。 在模型 RollAxisAutopilot 的 BasicRollMode 子系统中&#xff0c;将 PID 控制参数配置为在代码中显示为可…

VMware Workstation桥接模式无法上网

问题背景 我之前创建过一个虚拟机&#xff0c;当时虚拟机的网络模式使用的是桥接模式&#xff0c;配置好了固定ip地址&#xff0c;是可以正常上网的&#xff0c;中间没有做任何网络上面的配置。但是今天再打开这台虚拟机时&#xff0c;发现竟然不能上网了。 物理主机的ip信息配…

构造函数深入理解

目录 构造函数构造函数体赋值初始化列表初始化列表格式初始化列表的意义以及注意点const修饰的成员变量初始化对象成员具体初始化的地方缺省值存在的意义例子1例子2 初始化与赋值引用成员变量的初始化注意点1注意点2我的疑惑 自定义类型成员初始化例子1例子2例子3例子4 初始化列…

JAVA小知识31:多线程篇2

一、等待唤醒机制 生产者和消费者&#xff0c;也叫等待唤醒机制。他是一个十分经典的多线程协作的模式。我们来讲一个小故事&#xff1a; 在一个繁忙的工厂里&#xff0c;有一个生产线&#xff0c;我们称之为“共享资源”。这个生产线一次只能生产一个产品&#xff0c;而且需要…

Stable Diffusion【基础篇】:降噪强度(denoising strength)

提到降噪强度&#xff08;denoising strength&#xff09;&#xff0c;大家一定不会陌生&#xff0c;这个参数是图生图中最关键的参数之一。今天在Stable Diffusion Art网站看到一篇介绍降噪强度&#xff08;denoising strength&#xff09;的文章&#xff08;地址&#xff1a;…

HMI 的 UI 风格创新无限

HMI 的 UI 风格创新无限

「实战应用」如何用图表控件LightningChart JS创建SQL仪表板应用(三)

LightningChart JS是Web上性能特高的图表库&#xff0c;具有出色的执行性能 - 使用高数据速率同时监控数十个数据源。 GPU加速和WebGL渲染确保您的设备的图形处理器得到有效利用&#xff0c;从而实现高刷新率和流畅的动画&#xff0c;常用于贸易&#xff0c;工程&#xff0c;航…

从零开始:AI产品经理的入门路线图

引言&#xff1a; 想象这样一个场景&#xff1a;早晨的阳光穿透窗帘&#xff0c;投射在新一代智能机器人上&#xff0c;它正静静等待着你的第一个命令开始全新的一天。这样的场景听起来像是科幻小说里的情节&#xff0c;但实际上&#xff0c;这正是AI产品经理们工作的成果。如…