首页 > 编程知识 正文

鼠标右键弹出的菜单如何更改,右键菜单 快捷键

时间:2023-05-03 16:14:33 阅读:210653 作者:4834

写MFC,少不了用到菜单和快捷键,此处我用到了右键菜单。我的项目是一个播放器的实现,那么在屏幕中央右键点击,应该会弹出右键菜单,比如播放,暂停等,如我这样:

对应的每一个菜单应该还有相应的快捷键。那么具体如何设置呢?此处我省略在资源中添加菜单的步骤了,我的菜单ID为IDR_MENU1。想要实现右键点击播放器区域弹出菜单,需要响应右键按下的消息WM_RBUTTONDOWN,添加事件处理函数如下:

void CMyDlg::OnRButtonDown(UINT nFlags, CPoint point){ // TODO: 在此添加消息处理程序代码和/或调用默认值 mypic_video.EnableWindow(FALSE); CMenu menu; menu.LoadMenuA(IDR_MENU1); CMenu *pPopup=menu.GetSubMenu(0); ClientToScreen(&point);//将客户区坐标转换为屏幕坐标 //显示右键菜单,由视类窗口拥有。 pPopup->TrackPopupMenu(nFlags,point.x,point.y,this); //TrackPopupMenu的最后一个参数,可以为GetParent让父窗口既框架窗口拥有右键菜单,这样 //框架类窗口获得了对右键菜单中菜单项的命令响应, CDialogEx::OnRButtonDown(nFlags, point);}

其中值得一说的函数是TrackPopupMenu函数,简单的讲就是它决定了弹出菜单的位置。那么具体的讲呢,此处我引用互动百科上面的解释如下:TrackPopupMenu - 函数功能
该函数在指定位置显示快捷菜单,并跟踪菜单项的选择。快捷菜单可出现在屏幕上的任何位置。

TrackPopupMenu - 函数原型
BOOL TrackPopupMenu(HMENU hMenu,UINT uFlags,int x,int y,int nReserved,HWND hWnd,CONST RECT”prcRect);

TrackPopupMenu - 主要参数

hMenu:被显示的快捷菜单的句柄。此句柄可为调用CreatePopupMenu创建的新快捷菜单的句柄,也可以为调用GetSubMenu取得的与一个已存在菜单项相联系的子菜单的句柄。uFlags:一种指定功能选项的位标志。用下列标志位之一来确定函数如何水平放置快捷菜单:TPM_CENTERALLGN:若设置此标志,函数将按参数x指定的坐标水平居中放置快捷菜单。TPM_LEFTALLGN:若设置此标志,函数使快捷菜单的左边界与由参数X指定的坐标对齐。TPM_RIGHTALLGN:若设置此标志,函数使快捷菜单的右边界与由参数X指定的坐标对齐。用下列标志位之一来确定函数如何垂直放置快捷菜单:TPM_BOTTOMALLGN:若设置此标志,函数使快捷菜单的下边界与由参数y指定的坐标对齐。TPM_TOPALLGN:若设置此标志,函数使快捷菜单的上边界与由参数y指定的坐标对齐。TPM_VCENTERALLGN;若设置此标志,函数将按参数y指定的坐标垂直居中放置快捷菜单用下列标志位之一来确定在菜单没有父窗口的情况下用户的选择:TPM_NONOTIFY:若设置此标志,当用户单击菜单项时函数不发送通知消息。TPM_RETURNCMD;若设置此标志;函数将用户所选菜单项的标识符返回到返回值里。用下列标志位之一来确定在快捷菜单跟踪哪一个鼠标键:TPM_LEFTBUTTON:若设置此标志,用户只能用鼠标左键选择菜单项。TPM_RIGHTBUTTON:若设置此标志,用户能用鼠标左、右键选择菜单项。X:在屏幕坐标下,快捷菜单的水平位置。Y:在屏幕坐标下,快捷菜单的垂直位置。NReserved:保留值,必须为零。HWnd:拥有快捷菜单的窗口的句柄。此窗口接收来自菜单的所有消息。函数返回前,此窗口不接受来自菜单的WM_COMMAND消息。如果在参数uFlags里指定了TPM_NONOTIFY值,此函数不向hWnd标识的窗口发消息。 但必须给hWnd里传一个窗口句柄,可以是应用程序里的任一个窗口句柄。PrcRect:未用。返回值:如果在参数uFlags里指定了TPM_RETURNCMD值,则返回值是用户选择的菜单项的标识符。如果用户未作选择就取消了菜单或发生了错误,则退回值是零。如果没在参数uFlags里指定TPM_RETURNCMD值,若函数调用成功,返回非零值,若函数调用失败,返回零。若想获得更多的错误信息,清调用GetLastError。

至此,运行发现确实能右键弹出菜单。但是我此时又想念起了我的女神,是她陪我度过了最近这段很充实很发愁的时光,于是打开“中国好声音刘明湘.mp4”,顿时播放器里边传来那温柔的声音,没办法,写软件少不了测试,每次都是呆萌的未来来帮我测试。但此时我发现,右键点击,没有任何反应,怎么点都没有反应,我马上点击停止按钮,再右键播放区域,弹出了菜单。这就怪了,为什么播放的时候和不播放的时候是不同的反应呢?分析后只有一种可能,那就是播放的时候,右键的Rbuttondown消息被屏蔽了,或者说父窗口没有接收到Rbuttondown消息。后来在网上终于找到了一个方法,一句代码解决,就是mypic_video.EnableWindow(FALSE);先禁用picture控件,不让它拦截右键down消息。果然在此运行播放呆萌的未来的时候,右键点击,能弹出菜单了!哈哈!

那么播放器中,总是有很多快捷键的设置,比如Space按钮就是播放/暂停,<-和->就是后退和快进,等等。那么我接下来就是设置右键菜单的快捷键。此处我就写详细一点吧,毕竟当时我也是磕磕碰碰了很久。
首先选择资源视图,点击Accelerator,应该是有一个默认的项吧,不记得了,名字可定不是图中的名字,这里要注意,一定要将这个ID改为你准备设置快捷键的总菜单的ID,注意注意!

然后双击进入,为菜单里的每一项添加快捷键,如下所示:
这个是我自己的设置啦,对应上边讲到的右键菜单。
接下来还要添加代码。在对话框类里面添加成员变量HACCEL hAccel; 然后在OnInitDialog函数中添加
hAccel=::LoadAccelerators(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDR_MENU1));,此时最重要的一步来了。需要重写PreTranslateMessage函数,具体方法如下:
在类视图中找到对话框类,然后右键属性,找到重写按钮,往下面找到PreTranslateMessage函数,点击添加。


在该函数里边添加代码:

if (WM_KEYFIRST<=pMsg->message&&pMsg->message<= WM_KEYLAST) { HACCEL ihAccel=hAccel; if (ihAccel && ::TranslateAccelerator(GetSafeHwnd(), ihAccel, pMsg)) return TRUE; }

至此,完成。运行后快捷键果然成功了。当然前提是,之前需对菜单里的每一个菜单项添加事件响应函数。

那么为什么要这么做呢?PreTranslateMessage函数又是干嘛的?
引用百度百科:类: CWinThread
头文件:
afxwin.h
功能:
若要在消息被分配到Windows函数::TranslateMessage和DispatchMessage之前
过滤Windows消息,应重载这个函数。
语法:
virtual Bool PreTranslateMessage(MSG * pMsg);[1]
参数:
pMsg 指向包含要处理的消息的MSG结构
返回值:
若消息在PreTranslateMessage已经完全处理,不需要作进一步处理,返回非零值。
若消息需要进一步处理,则返回零。
说明:
仅在用户界面线程中使用。

简单的理解就是这个函数具有较高的优先级,它能首先截获一些按键消息之类的,所以在截获后便可以调用自己的函数进行消息响应。

至此,右键菜单的设置和快捷键的设置就完了,当然我的项目中用到的还有其他的快捷键设置,还需要调试。加油!

——————————————————————————————————————————(以下为二次修改内容)

后来,发现好像还有另外一种很方便的方法,即在该菜单或者按钮的caption属性中,添加
&G就可以实现Alt+G键的快捷键,当然可以把G键换成其他的字母键。

除了快捷键,我也听说过热键,那么什么是热键呢?其实好像就是一样的意思,我到现在还没有明白。先不管了,我的重点不是说这个,我的重点是上面的快捷键设置方法只是local的,即当应用程序失去焦点后或者没有被激活前,快捷键是不起作用的。那么与此相对应的就是global的,即任何时候(不管程序有没有获得焦点,或是有没有被激活)都可以响应快捷键。
那么如何设置全局的快捷键?
首先,利用类向导添加消息WM _HOTKEY的响应函数,会在类中自动生成成员函数

afx_msg void OnHotKey(UINT nHotKeyId, UINT nKey1, UINT nKey2);

,同时在BEGIN_MESSAGE_MAP(CMyPlayerDlg, CDialogEx)里也生成衣蛾消息宏映射

ON_WM_HOTKEY()

上面两步不用我们自己操作,类向导已经帮我们做好了,接下来我们可以开始真正的编写设置。
在OnInitDialog中添加注册热键的代码:

//注册热键 int nRet = RegisterHotKey(GetSafeHwnd(),ID_hotkeyftp,MOD_ALT|MOD_CONTROL,'Y'); //热键 ctrl+alt+Y if(!nRet) AfxMessageBox("RegisterHotKey 0 false"); nRet = RegisterHotKey(GetSafeHwnd(),ID_hotkeytty,MOD_ALT|MOD_CONTROL,'T'); //热键 ctrl +alt + t if(!nRet) AfxMessageBox("RegisterHotKey 1 false");

其中ID_hotkeyftp和ID_hotkeytty是我自己定义的两个宏。可以在头文件中定义:

#define ID_hotkeyftp 1001#define ID_hotkeytty 1002

关于热键的具体风格可以是如下的组合:(利用’|’进行组合)

然后在生成的void CMyPlayerDlg::OnHotKey(UINT nHotKeyId, UINT nKey1, UINT nKey2)函数中编写代码:

void CMyPlayerDlg::OnHotKey(UINT nHotKeyId, UINT nKey1, UINT nKey2){ // TODO: 在此添加消息处理程序代码和/或调用默认值 if (nHotKeyId==ID_hotkeyftp) { //快捷键对应的动作响应函数 OnBnClickedButtonftp(); } else if (nHotKeyId==ID_hotkeytty) { 快捷键对应的动作响应函数 OnBnClickedButtty(); } else { NULL; } CDialogEx::OnHotKey(nHotKeyId, nKey1, nKey2);}

还没有完,还需要在类的析构函数中书写如下代码:

UnregisterHotKey(m_hWnd,ID_hotkeyftp); UnregisterHotKey(m_hWnd,ID_hotkeytty);

到此设置完毕,运行之后就可以看到效果了,不管有没有获得焦点,按下组合键,都能响应相应的动作。也就是全局的热键。

关于热键和快捷键,或许可以从字面理解,因为热键可以设置成全局的,所以应该是哪些经常用到的操作,所以称之为“热”嘛。哈哈!

拙见,小记!

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。