1. 程式人生 > >走進windows編程的世界-----消息處理函數(4)

走進windows編程的世界-----消息處理函數(4)

rpo 擴展 hinstance adding 3.1 eof client cnblogs set

一 右鍵菜單
1 右鍵菜單
當在窗體點擊鼠標右鍵時,彈出的菜單。
2 右鍵菜單的使用
2.1 創建菜單
CreatePopupMenu
2.2 菜單添加
AppendMenu
2.3 菜單的顯示、

BOOL TrackPopupMenu(
    HMENU hMenu, //顯示的菜單句柄
    UINT uFlags, //顯示的方式
  int x, //菜單的X屏幕坐標
  int y, //菜單的Y屏幕坐標
  int nReserved, //保留,必須為0
  HWND hWnd, //處理菜單命令的窗體句柄
  CONST RECT *prcRect ); //忽略

2.4 菜單的命令處理

WM_COMMAND
2.5 使用右鍵菜單的位置
2.5.1 WM_RBUTTONUP 消息
在WM_RBUTTONUP中,加入菜單的創建及顯示,
右鍵消息坐標,轉換成屏幕坐標使用.
ClientToScreen.
2.5.2 WM_CONTEXTMENU 消息
用於顯示右鍵的菜單的消息.
WPARAM - 右鍵擡起時相應窗體句柄
LPARAM - 右鍵擡起時鼠標的屏幕坐標位置
LOWORD(lParam) - X屏幕坐標
HIWORD(lParam) - Y屏幕坐標
2.5.3 WM_RBUTTONUP和WM_CONTEXTMENU對照
1) 坐標系不同, WM_RBUTTONUP客戶區坐標,WM_CONTEXTMENU屏幕坐標
2) 先有WM_RBUTTONUP消息,後有WM_CONTEXTMENU消息

/* File : winPopMenu.cpp  
 * Auth : sjin  
 * Date : 20140706  
 * Mail : [email protected]  
 */    
    
#include <Windows.h>    
#include <stdio.h>


HINSTANCE g_hInst = NULL;

void OnRButtonUp( HWND hWnd, UINT nMsg, 
        WPARAM wParam, LPARAM lParam )
{    // 創建彈出式菜單
    HMENU hPopMenu = CreatePopupMenu( );
    // 添加菜單項
    AppendMenu( hPopMenu, MF_STRING, 1001, "測試1");
    AppendMenu( hPopMenu, MF_SEPARATOR, 0, NULL );
    AppendMenu( hPopMenu, MF_STRING, 1002, "退出");
    // 獲取菜單位置
    POINT point = { 0 };
    point.x = LOWORD( lParam );
    point.y = HIWORD( lParam );
    ClientToScreen( hWnd, &point );
    // 顯示菜單
    TrackPopupMenu( hPopMenu, TPM_LEFTALIGN,
        point.x, point.y, 0, hWnd, NULL );
}

void OnContextMenu( HWND hWnd, UINT nMsg, 
    WPARAM wParam, LPARAM lParam )
{   // 創建彈出式菜單
    HMENU hPopMenu = CreatePopupMenu( );
    // 添加菜單項
    AppendMenu( hPopMenu, MF_STRING, 1001, "測試2");
    AppendMenu( hPopMenu, MF_SEPARATOR, 0, NULL );
    AppendMenu( hPopMenu, MF_STRING, 1002, "退出");
    // 坐標獲取
    int nX = LOWORD( lParam );
    int nY = HIWORD( lParam );
    // 顯示菜單
    TrackPopupMenu( hPopMenu, TPM_LEFTALIGN,
        nX, nY, 0, hWnd, NULL );
    // 刪除菜單
    DestroyMenu( hPopMenu );
}

void OnCommand( HWND hWnd, UINT nMsg, 
        WPARAM wParam, LPARAM lParam )
{
    int nCmdID = LOWORD( wParam );
    switch( nCmdID )
    {
    case 1001:
        MessageBox( NULL, "Hello Popmenu",
            "PopMenu", MB_OK );
        break;
    case 1002:
        PostQuitMessage( 0 );
        break;
    }
}



LRESULT CALLBACK WndProc( HWND   hWnd, 
                          UINT   nMsg,
                          WPARAM wParam,
                          LPARAM lParam )
{
    switch( nMsg )
    {
    case WM_RBUTTONUP:
        //OnRButtonUp( hWnd, nMsg, wParam, lParam );
        break;
    case WM_CONTEXTMENU:
        OnContextMenu( hWnd, nMsg, wParam, lParam );
        break;
    case WM_COMMAND:
        OnCommand( hWnd, nMsg, wParam, lParam );
        break;
    case WM_DESTROY:
        PostQuitMessage( 0 );
        return 0;
    }
    return DefWindowProc( hWnd, nMsg,
        wParam, lParam );
}

BOOL RegisterWnd( LPSTR pszClassName )
{
    WNDCLASSEX wce = { 0 };
    wce.cbSize        = sizeof( wce );
    wce.cbClsExtra    = 0;
    wce.cbWndExtra    = 0;
    wce.hbrBackground = HBRUSH(COLOR_WINDOW);
    wce.hCursor       = NULL;
    wce.hIcon         = NULL;
    wce.hIconSm       = NULL;
    wce.hInstance     = g_hInst;
    wce.lpfnWndProc   = WndProc;
    wce.lpszClassName = pszClassName;
    wce.lpszMenuName  = NULL;
    wce.style         = CS_HREDRAW|CS_VREDRAW;

    ATOM nAtom = RegisterClassEx( &wce );
    if( 0 ==  nAtom )
    {
        return FALSE;
    }

    return TRUE;
}

HWND CreateWnd( LPSTR pszClassName )
{
    HWND hWnd = CreateWindowEx( 0,
        pszClassName, "MyWnd", 
        WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
        CW_USEDEFAULT, CW_USEDEFAULT,
        CW_USEDEFAULT, NULL, NULL, g_hInst,
        NULL );
    return hWnd;
}

void DisplayWnd( HWND hWnd )
{
    ShowWindow( hWnd, SW_SHOW );
    UpdateWindow( hWnd );
}

void Message( )
{
    MSG msg = { 0 };
    while( GetMessage( &msg, NULL, 0, 0 ) )
    {
        TranslateMessage( &msg );
        DispatchMessage( &msg );
    }
}

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
    g_hInst = hInstance;
    RegisterWnd( "MYWND" );
    HWND hWnd = CreateWnd( "MYWND" );
    DisplayWnd( hWnd );
    Message( );
    return 0;
}

二、資源的使用

1 資源文件
圖標、光標、字符串、菜單、加速鍵和對話框資源,位圖資源等等。
資源腳本文件 - 擴展名為RC文件。

定義了資源和相關文件等等信息。


資源編譯器 - RC.exe

2 圖標資源ICON

2.1 經常使用的幾種大小: 16X16, 32X32,48X48
2.2 使用
HICON LoadIcon(
HINSTANCE hInstance, //應用程序的句柄
LPCTSTR lpIconName );//圖標的ID字符串
2.3 系統提供的圖標
hInstance為空, lpIconName為定義的系統圖標.
2.4 自己繪制的圖標
hInstance為圖標所在的應用程序的實例句柄
2.5 註意點:
一個圖標文件裏,能夠包括多種大小、顏色不同的圖標,系統使用圖標時,通過大小來匹配。假設未找到大小全然一致的,那麽會使用大小最接近的圖標格式替換。



3 光標資源

3.1 光標資源
熱點 Hotspot - 能夠產生鼠標點擊的位置
3.2 使用
HCURSOR LoadCursor(
HINSTANCE hInstance, //應用程序實例句柄
LPCTSTR lpCursorName); //光標的ID
3.3 系統的光標
hInstance為空,lpCursorName指定為系統的光標就可以獲得
3.4 自繪制的光標
hInstance不能為空。


3.5 WM_SETCURSOR消息
當鼠標在窗體內就會產生。

能夠在程序運行的過程中改動鼠標樣式。
wParam - 窗體句柄;
LOWORD(lParam) - 所在位置的標識
HIWORD(lParam) - 鼠標的消息ID
SetCursour 設置當前窗體的光標

/* File : winRes.cpp   
 * Auth : sjin   
 * Date : 20140710   
 * Mail : [email protected]   
 */      
      
#include <Windows.h>      
#include <stdio.h>
#include <WinUser.h>
#include "Resource.h"

HINSTANCE g_hInst = NULL;
 
BOOL OnSetCursor( HWND hWnd, UINT nMsg, 
    WPARAM wParam, LPARAM lParam )
{
    int nHitTest = LOWORD( lParam );
    if( HTCLIENT != nHitTest )/*為了僅僅處理客戶區消息。須要添加這個設置*/
    {
       // return FALSE;
    }

    //獲得窗體的客戶區
    RECT rcClient = { 0 };
    GetClientRect( hWnd, &rcClient );
    //獲得當前光標的位置
    POINT ptPos = { 0 };
    GetCursorPos( &ptPos );
    ScreenToClient( hWnd, &ptPos );
    //依據位置載入光標
    HCURSOR hCursor = NULL;
    if( ptPos.x < rcClient.right/2 )
    {
        if( ptPos.y < rcClient.bottom/2 )
        {
			/*HCURSOR LoadCursor(
			 *	HINSTANCE hInstance, //應用程序實例句柄
			 *	LPCTSTR lpCursorName); //光標的ID
			 *  系統光標: hInstance為NULL,lpCursorName:光標資源ID
			 *  自繪制光標:hInstance不能為NULL。lpCursorName:自繪光標資源ID
			 */
            hCursor = LoadCursor( NULL, IDC_SIZEALL );
        }
        else
        {
            hCursor = LoadCursor( NULL, IDC_CROSS );
        }
    }
    else
    {
        if( ptPos.y < rcClient.bottom/2 )
        {
            hCursor = LoadCursor( NULL, IDC_WAIT );
        }
        else
        {
            hCursor = LoadCursor( NULL, IDC_UPARROW );
        }
    }
    // 設置光標
    SetCursor( hCursor );
    return TRUE;
}

LRESULT CALLBACK WndProc( HWND   hWnd, 
                          UINT   nMsg,
                          WPARAM wParam,
                          LPARAM lParam )
{
    switch( nMsg )
    {
		/*當鼠標在窗體內就會觸發這個消息。能夠再程序運行過程中改動光標的樣式*/
    case WM_SETCURSOR:

        if( TRUE == OnSetCursor( hWnd, nMsg, wParam, lParam ) )
        {
			/*設置光標屬性生效,必須返回*/
            return 0;
        }
        break;
    case WM_DESTROY:
        PostQuitMessage( 0 );
        return 0;

    }
	/*運行默認的光標屬性*/
    return DefWindowProc( hWnd, nMsg,
        wParam, lParam );
}

BOOL RegisterWnd( LPSTR pszClassName )
{
    WNDCLASSEX wce = { 0 };
    wce.cbSize        = sizeof( wce );
    wce.cbClsExtra    = 0;
    wce.cbWndExtra    = 0;
    wce.hbrBackground = HBRUSH(COLOR_WINDOW);
    wce.hCursor       = LoadCursor( g_hInst, MAKEINTRESOURCE(IDC_POINTER) );
    wce.hIcon         = LoadIcon( g_hInst, MAKEINTRESOURCE(IDI_MAIN) );
    wce.hIconSm       = NULL;
    wce.hInstance     = g_hInst;
    wce.lpfnWndProc   = WndProc;
    wce.lpszClassName = pszClassName;
    wce.lpszMenuName  = NULL;
    wce.style         = CS_HREDRAW|CS_VREDRAW;

    ATOM nAtom = RegisterClassEx( &wce );
    if( 0 ==  nAtom )
    {
        return FALSE;
    }

    return TRUE;
}

HWND CreateWnd( LPSTR pszClassName )
{
    HWND hWnd = CreateWindowEx( 0,
        pszClassName, "MyWnd", 
        WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
        CW_USEDEFAULT, CW_USEDEFAULT,
        CW_USEDEFAULT, NULL, NULL, g_hInst,
        NULL );
    return hWnd;
}

void DisplayWnd( HWND hWnd )
{
    ShowWindow( hWnd, SW_SHOW );
    UpdateWindow( hWnd );
}

void Message( )
{
    MSG msg = { 0 };
    while( GetMessage( &msg, NULL, 0, 0 ) )
    {
        TranslateMessage( &msg );
        DispatchMessage( &msg );
    }
}

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
    g_hInst = hInstance;
    RegisterWnd( "MYWND" );
    HWND hWnd = CreateWnd( "MYWND" );
    DisplayWnd( hWnd );
    Message( );
    return 0;
}
4 字符串資源

4.1 包括字符串的資源
4.2 使用
int LoadString(
HINSTANCE hInstance,//程序句柄
UINT uID, //字符串資源的ID
LPTSTR lpBuffer, //存放字符串的BUFF
int nBufferMax ); //BUFF的大小
返回獲取字符串的長度

5 菜單資源
5.1 加入菜單資源
5.2 載入菜單資源
HMENU LoadMenu(
HINSTANCE hInstance, //應用程序句柄
LPCTSTR lpMenuName );//菜單ID字符串
返回載入成功的菜單的句柄
5.3 命令處理

使用加入的菜單ID的宏,在WM_COMMAND消息中,處理菜單命令.

6 加速鍵資源
6.1 加速鍵的作用
能夠使用加速鍵運行命令. 比如Ctrl+S存盤.
6.2 加速鍵資源的加入
6.3 加速鍵的使用
6.3.1 載入
HACCEL LoadAccelerators(
HINSTANCE hInstance,//資源所在的應用程序句柄
LPCTSTR lpTableName ); //加速鍵表的ID字符串
載入成功返回加速鍵表的句柄
6.3.2 添加消息處理

  int TranslateAccelerator(
     HWND hWnd, //處理加速鍵的窗體句柄
   HACCEL hAccTable, //加速鍵表
   LPMSG lpMsg );//MSG結構的地址

6.4 關於加速鍵的消息
TranslateAccelerator的作用是將WM_KEYDOWN或者WM_SYSKEYDOWN消息,翻譯成WM_COMMAND或者WM_SYSCOMMAND消息.
當收到KEYDOWN或者SYSKEYDOWN的消息時,會依據加速鍵表中按鍵和命令ID相應關系,找到相應的命令ID,然後調用窗體處理函數,運行WM_COMMAND或者WM_SYSCOMMAND消息.
當找到相應命令ID並運行後,TranslateAccelerator返回非零。那麽就不再運行興許的處理,消息循環等候下一條消息。

否則,繼續讓消息循環中的TansnlateMessage和DispatchMessage處理。

/* File : winRes.cpp   
 * Auth : sjin   
 * Date : 20140710   
 * Mail : [email protected]   
 */      
      
#include <Windows.h>      
#include <stdio.h>
#include <WinUser.h>
#include "Resource.h"

HINSTANCE g_hInst = NULL;
 
BOOL OnSetCursor( HWND hWnd, UINT nMsg, 
    WPARAM wParam, LPARAM lParam )
{
    int nHitTest = LOWORD( lParam );
    if( HTCLIENT != nHitTest )/*為了僅僅處理客戶區消息,須要添加這個設置*/
    {
       // return FALSE;
    }

    //獲得窗體的客戶區
    RECT rcClient = { 0 };
    GetClientRect( hWnd, &rcClient );
    //獲得當前光標的位置
    POINT ptPos = { 0 };
    GetCursorPos( &ptPos );
    ScreenToClient( hWnd, &ptPos );
    //依據位置載入光標
    HCURSOR hCursor = NULL;
    if( ptPos.x < rcClient.right/2 )
    {
        if( ptPos.y < rcClient.bottom/2 )
        {
			/*HCURSOR LoadCursor(
			 *	HINSTANCE hInstance, //應用程序實例句柄
			 *	LPCTSTR lpCursorName); //光標的ID
			 *  系統光標: hInstance為NULL,lpCursorName:光標資源ID
			 *  自繪制光標:hInstance不能為NULL,lpCursorName:自繪光標資源ID
			 */
            hCursor = LoadCursor( NULL, IDC_SIZEALL );
        }
        else
        {
            hCursor = LoadCursor( NULL, IDC_CROSS );
        }
    }
    else
    {
        if( ptPos.y < rcClient.bottom/2 )
        {
            hCursor = LoadCursor( NULL, IDC_WAIT );
        }
        else
        {
            hCursor = LoadCursor( NULL, IDC_UPARROW );
        }
    }
    // 設置光標
    SetCursor( hCursor );
    return TRUE;
}

void OnCommand(HWND hWnd, UINT nMsg, 
    WPARAM wParam, LPARAM lParam )
{
	/*ID 號*/
	int nCmdID = LOWORD(wParam);

	switch(nCmdID){

	case ID_40001:
		PostQuitMessage(0);
		break;

	case ID_40002:
		break;

	default:
		break;
	}
}

LRESULT CALLBACK WndProc( HWND   hWnd, 
                          UINT   nMsg,
                          WPARAM wParam,
                          LPARAM lParam )
{
    switch( nMsg )
    {
		/*當鼠標在窗體內就會觸發這個消息,能夠再程序運行過程中改動光標的樣式*/
    case WM_SETCURSOR:

        if( TRUE == OnSetCursor( hWnd, nMsg, wParam, lParam ) )
        {
			/*設置光標屬性生效,必須返回*/
            return 0;
        }
        break;

	case WM_COMMAND:/*處理菜單的命令*/
		OnCommand(hWnd, nMsg, wParam, lParam);
		break;
    case WM_DESTROY:
        PostQuitMessage( 0 );
        return 0;

    }
	/*運行默認的光標屬性*/
    return DefWindowProc( hWnd, nMsg,
        wParam, lParam );
}

BOOL RegisterWnd( LPSTR pszClassName )
{
    WNDCLASSEX wce = { 0 };
    wce.cbSize        = sizeof( wce );
    wce.cbClsExtra    = 0;
    wce.cbWndExtra    = 0;
    wce.hbrBackground = HBRUSH(COLOR_WINDOW);
    wce.hCursor       = LoadCursor( g_hInst, MAKEINTRESOURCE(IDC_POINTER) );
    wce.hIcon         = LoadIcon( g_hInst, MAKEINTRESOURCE(IDI_MAIN) );
    wce.hIconSm       = NULL;
    wce.hInstance     = g_hInst;
    wce.lpfnWndProc   = WndProc;
    wce.lpszClassName = pszClassName;
    wce.lpszMenuName  = NULL;
    wce.style         = CS_HREDRAW|CS_VREDRAW;

    ATOM nAtom = RegisterClassEx( &wce );
    if( 0 ==  nAtom )
    {
        return FALSE;
    }

    return TRUE;
}

HWND CreateWnd( LPSTR pszClassName )
{
	/*載入字符串資源
	 * int LoadString(
     *      HINSTANCE hInstance,//程序句柄
     *      UINT uID, //字符串資源的ID
     *      LPTSTR lpBuffer, //存放字符串的BUFF
     *      int nBufferMax ); //BUFF的大小
     *     返回獲取字符串的長度
	 *  用戶:在多語言支持中使用字符串資源。

*/ char buf[256] = {‘\0‘}; LoadString(g_hInst,IDS_MAIN,buf,256); /*載入菜單資源 * HMENU LoadMenu( * HINSTANCE hInstance, //應用程序句柄 * LPCTSTR lpMenuName );//菜單ID字符串 * * 返回載入成功的菜單的句柄 */ HMENU hMenu = LoadMenu(g_hInst,MAKEINTRESOURCE(IDR_MAIN)); HWND hWnd = CreateWindowEx( 0, pszClassName, /*"MyWnd"*/buf, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, hMenu, g_hInst, NULL ); return hWnd; } void DisplayWnd( HWND hWnd ) { ShowWindow( hWnd, SW_SHOW ); UpdateWindow( hWnd ); } void Message(HWND hWnd ) { /*載入加速鍵表 * */ HACCEL hAccel = LoadAccelerators(g_hInst,MAKEINTRESOURCE(IDR_ACCEL)); MSG msg = { 0 }; while( GetMessage( &msg, NULL, 0, 0 ) ) { /*添加加速鍵的消息處理*/ if(!TranslateAccelerator(hWnd,hAccel,&msg)){ TranslateMessage( &msg ); DispatchMessage( &msg ); } } } int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { g_hInst = hInstance; RegisterWnd( "MYWND" ); HWND hWnd = CreateWnd( "MYWND" ); DisplayWnd( hWnd ); Message(hWnd ); return 0; }




走進windows編程的世界-----消息處理函數(4)