<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                快捷菜單,說得容易理解一點,就是右鍵菜單,當我們在某個區域內單擊鼠標右鍵,會彈出一些菜單項。這種類型的菜單,是隨處可見的,我們在桌面上右擊一下,也會彈出一個菜單。 右鍵菜單的好處就是方便,它經常和我們正在操作的某個UI元素聯系起來,比如我們正在使用文本框輸入文本,我們在文本框中右擊,就會看到可能有【復制】【清空】【全選】之類的選項,所以,右鍵菜單也稱為“上下文菜單(Context Menu)”。 一般來說,創建并使用快捷菜單,可以按照以下步驟進行: 1、用資源編輯器創建菜單。 2、當我們在窗口上按下鼠標右鍵,當系統處理WM_RBUTTONUP時會向我們的應用程序發送一條WM_CONTEXTMENU消息,我們通過響應這條消息來決定是否彈出菜單。 3、計算菜單彈出的位置,一般在我們鼠標指針的右下方,該坐標是基于屏幕的,不是窗口的。 4、調用TrackPopupMenu函數顯示快捷菜單。 5、因為這種菜單是不屬于某個窗口的,它的內存資源不會在窗口銷毀時被回收,因此,在TrackPopupMenu返回后要調用DestroyMenu來銷毀菜單的資源,釋放內存。 好的,基本思路有了,我們就按照這個思路來試一試,看能不能實現一個右鍵菜單。 首先,用資源編輯器建立一個菜單,因為我們的彈出菜單一般只顯示一系列菜項,是沒有菜單的頭部,不像菜單欄。因此,我們把菜單做成這樣: ![](https://box.kancloud.cn/2016-06-14_575fd2cfb0648.PNG) 快捷菜單只會顯示我用畫筆圈起來的那部分,而上面的【abc】是不顯示的,所以你可以讓它空著,也可以隨便輸入一些內容。 然后為每個菜單項設置ID就行了,資源編輯器有時候會產生一堆沒有被使用的ID宏,這些我們可以手動刪除,當然也可以不管它,反正不影響程序的編譯,因為頭文件是不參與編譯的。我們編譯的時候只是編譯.cpp文件。 接下來就是捕捉WM_CONTEXTMENU消息。顯示菜單。 ~~~ case WM_CONTEXTMENU: { //加載菜單資源 HMENU hroot = LoadMenu((HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), MAKEINTRESOURCE(IDR_CONTEXT)); if(hroot) { // 獲取第一個彈出菜單 HMENU hpop = GetSubMenu(hroot,0); // 獲取鼠標右擊是的坐標 int px = GET_X_LPARAM(lParam); int py = GET_Y_LPARAM(lParam); //顯示快捷菜單 TrackPopupMenu(hpop, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RIGHTBUTTON, px, py, 0, (HWND)wParam, NULL); // 用完后要銷毀菜單資源 DestroyMenu(hroot); } } break; ~~~ 首先用LoadMenu來加載資源文件中的菜單,注意,它加載的是整個菜單欄,而我們要的是圖中標注的子項。 ![](https://box.kancloud.cn/2016-06-14_575fd2cfc39f9.PNG) 我們這里只有一個子彈出項,所以,GetSubMenu函數獲取子項時,索引應為0。 根據MSDN文檔的說明,WM_CONTEXTMENU消息的wParam參數指的是彈出菜單的窗口的句柄,lParam參數的低字位是鼠標指針的水平坐標,高字位指的是垂直坐標。 但我們不用自己去轉換,我們通過GET_X_LPARAM和GET_Y_LPARAM兩個宏可以把lParam中的值轉為坐標值,類型為int,要使用這兩個宏,需要包含WindowsX.h頭文件。接著調用TrackPopupMenu來顯示菜單,最后銷毀菜單。 函數的具體參數我不想抄MSDN了,大家可以上MSDN查查。如果你覺得英文文檔看得不舒服,你不妨使一下技巧,你可以在百度百科上搜,有中文說明,還有一些VB 6 的網站也有API的中文說明,你可以參考一下。 為了使菜單點擊后程序能做出反應,我們還要捕捉WM_COMMAND消息。 ~~~ case WM_COMMAND: { switch(LOWORD(wParam)) { case IDM_WANG: MessageBox(hwnd,L"你選擇了王維。",L"提示",MB_OK); break; case IDM_MENG: MessageBox(hwnd,L"你選擇了孟浩然。",L"提示",MB_OK); break; case IDM_LI: MessageBox(hwnd,L"你選擇了李白。",L"提示",MB_OK); break; } } return 0; ~~~ 我們來運行一下,看看能不能起作用。 ![](https://box.kancloud.cn/2016-06-14_575fd2cfd58e9.PNG) ![](https://box.kancloud.cn/2016-06-14_575fd2cfe8bd8.PNG) 我們感覺到,程序好像是成功了,目的也似乎達到了,但是,如果你細心研究一下,你會發現一個問題,通常我們窗口的快捷菜單都是在窗口的客戶區域右擊才出現,即除了標題欄和邊框,但我們這個程序,你試試,在標題欄上右擊,也會出現快捷菜單,而且把系統菜單也覆蓋掉了。 ![](https://box.kancloud.cn/2016-06-14_575fd2d00c4fd.PNG) 很顯然,我們是不能這樣做的,很不道德,很不忠不孝不仁不義。所以,我們還要考慮一下,用戶鼠標右擊的位置是否在我們的客戶區域范圍內。要判斷某個點是否在一個矩形范圍內,我們可以用PtInRect函數。 于是,把上面的代碼改成這樣: ~~~ case WM_CONTEXTMENU: { RECT rect; POINT pt; // 獲取鼠標右擊是的坐標 pt.x = GET_X_LPARAM(lParam); pt.y = GET_Y_LPARAM(lParam); //獲取客戶區域大小 GetClientRect((HWND)wParam, &rect); //判斷點是否位于客戶區域內 if(PtInRect(&rect, pt)) { //加載菜單資源 HMENU hroot = LoadMenu((HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), MAKEINTRESOURCE(IDR_CONTEXT)); if(hroot) { // 獲取第一個彈出菜單 HMENU hpop = GetSubMenu(hroot,0); //顯示快捷菜單 TrackPopupMenu(hpop, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, 0, (HWND)wParam, NULL); // 用完后要銷毀菜單資源 DestroyMenu(hroot); } } } break; ~~~ 然后再次運行,可是你會發現,靠,問題更嚴重了,無論我在窗口的哪個地方右擊,菜單都不出來了。 代碼中是用GetClientRect函數來獲取窗口客戶區域的矩形位置的,我們明明是在窗口中的可視區域右擊了,但為什么會沒有看到菜單出來呢?我們在調用PtInRect的地方下一個斷點,然后調試運行,我們來比較一下,到底鼠標右擊的坐標在不在客戶區域的矩形內。 ![](https://box.kancloud.cn/2016-06-14_575fd2d0200f8.PNG) ![](https://box.kancloud.cn/2016-06-14_575fd2d0321a0.png) 有一點我們要注意的,GetClientRect它計算的標準是相對于窗口的,而WM_CONTEXTMENU取出的坐標是基于屏幕的,兩個參照點不同,所以在PtInRect中無法正確地比較。所以,我們需要調用ScreenToClient函數把屏幕坐標轉為客戶區域坐標。但是在彈出菜單的時候,因為我們要傳入基于屏幕的坐標,所以,在顯示菜單前要用ClientToScreen來還原坐標為相對于屏幕的點。 即: ScreenToClient.... ??? ..........if? PtInRect ????????? ...........ClientToScreen ???????? ............TrackPopupMenu ~~~ case WM_CONTEXTMENU: { RECT rect; POINT pt; // 獲取鼠標右擊是的坐標 pt.x = GET_X_LPARAM(lParam); pt.y = GET_Y_LPARAM(lParam); //獲取客戶區域大小 GetClientRect((HWND)wParam, &rect); //把屏幕坐標轉為客戶區坐標 ScreenToClient((HWND)wParam, &pt); //判斷點是否位于客戶區域內 if(PtInRect(&rect, pt)) { //加載菜單資源 HMENU hroot = LoadMenu((HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), MAKEINTRESOURCE(IDR_CONTEXT)); if(hroot) { // 獲取第一個彈出菜單 HMENU hpop = GetSubMenu(hroot,0); // 把客戶區坐標還原為屏幕坐標 ClientToScreen((HWND)wParam, &pt); //顯示快捷菜單 TrackPopupMenu(hpop, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, 0, (HWND)wParam, NULL); // 用完后要銷毀菜單資源 DestroyMenu(hroot); } } } ~~~ 這樣一來,就把坐標問題解決了,現在可以彈出菜單了。但還有一個問題沒有解決,你會發現,現在在窗口的標題欄上右擊,快捷菜單不會再出現了,但是,同時,系統菜單也沒有出現。因為系統菜單是由系統來處理的,所以,解決這問題很簡單,只要我們把WM_CONTEXT消息發回給系統來處理就行了。 方法一:我們判斷了如果右擊點在窗口的客戶區域時顯示菜單,那么,如果不在這個區域內,就把消息再傳回給系統處理。 ~~~ else { return DefWindowProc(hwnd, msg, wParam, lParam); } ~~~ 方法二:在WindowsProc函數的最后,統一把所有消息都返回給操作系統處理。 ~~~ default: // 如果不處理消息,交回系統處理 return DefWindowProc(hwnd, msg, wParam, lParam); } return DefWindowProc(hwnd, msg, wParam, lParam); } ~~~ 反正目的只有一個,把WM_CONTEXTMENU消息路由回給系統處理就行了。現在再運行一下,系統菜單可以顯示。從這一點我們可以學到一個技巧,如果你想屏蔽窗口的系統菜單,你應該知道怎么做了,就是不讓系統有機會響應WM_CONTEXTMENU消息就行了。另外,**按Shift + F10快捷鍵也會收到WM_CONTEXTMENU消息**。 ![](https://box.kancloud.cn/2016-06-14_575fd2d0462d7.PNG) 完整的代碼清單如下: ~~~ #include <Windows.h> #include "resource.h" #include <WindowsX.h> LRESULT CALLBACK MyMainWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); int WINAPI WinMain( HINSTANCE hThisApp, HINSTANCE hPrevApp, LPSTR cmdLine, int nShow) { WNDCLASS wc = { }; wc.hbrBackground = (HBRUSH)COLOR_WINDOW; wc.lpszClassName = L"MyApp"; wc.style = CS_HREDRAW | CS_VREDRAW; wc.hInstance = hThisApp; wc.lpfnWndProc = (WNDPROC)MyMainWindowProc; //注冊窗口類 RegisterClass(&wc); //創建窗口 HWND hwnd = CreateWindow( L"MyApp", L"我的超級應用", WS_OVERLAPPEDWINDOW, 60, 25, 420, 300, NULL, NULL, hThisApp, NULL); if(hwnd == NULL) return 0; // 顯示窗口 ShowWindow(hwnd, nShow); //消息循環 MSG msg; while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return 0; } LRESULT CALLBACK MyMainWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_DESTROY: PostQuitMessage(0); return 0; case WM_COMMAND: { switch(LOWORD(wParam)) { case IDM_WANG: MessageBox(hwnd,L"你選擇了王維。",L"提示",MB_OK); break; case IDM_MENG: MessageBox(hwnd,L"你選擇了孟浩然。",L"提示",MB_OK); break; case IDM_LI: MessageBox(hwnd,L"你選擇了李白。",L"提示",MB_OK); break; } } return 0; case WM_CONTEXTMENU: { RECT rect; POINT pt; // 獲取鼠標右擊是的坐標 pt.x = GET_X_LPARAM(lParam); pt.y = GET_Y_LPARAM(lParam); //獲取客戶區域大小 GetClientRect((HWND)wParam, &rect); //把屏幕坐標轉為客戶區坐標 ScreenToClient((HWND)wParam, &pt); //判斷點是否位于客戶區域內 if(PtInRect(&rect, pt)) { //加載菜單資源 HMENU hroot = LoadMenu((HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), MAKEINTRESOURCE(IDR_CONTEXT)); if(hroot) { // 獲取第一個彈出菜單 HMENU hpop = GetSubMenu(hroot,0); // 把客戶區坐標還原為屏幕坐標 ClientToScreen((HWND)wParam, &pt); //顯示快捷菜單 TrackPopupMenu(hpop, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, 0, (HWND)wParam, NULL); // 用完后要銷毀菜單資源 DestroyMenu(hroot); } } else { return DefWindowProc(hwnd, msg, wParam, lParam); } } break; default: // 如果不處理消息,交回系統處理 return DefWindowProc(hwnd, msg, wParam, lParam); } } ~~~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看