win32消息與菜單創建

一 鼠標消息

  1 鼠標消息
    1) 基本鼠標消息
    WM_LBUTTONDOWN   左鍵按下
    WM_LBUTTONUP     左鍵擡起
    WM_RBUTTONDOWN   右鍵按下
    WM_RBUTTONUP     右鍵擡起
    WM_MOUSEMOVE     鼠標移動
    2) 雙擊消息
    WM_LBUTTONDBLCLK 左鍵雙擊
    WM_RBUTTONDBLCLK 右鍵雙擊
    3) 滾輪消息
    WM_MOUSEWHEEL    鼠標滾輪
 
  2 消息的參數
    WPARAM - 當前鍵盤和鼠標按鍵狀態,例如MK_CONTROL/
        MK_SHIFT,MK_LBUTTON等
    LPARAM - 當前鼠標的座標,座標的原點是窗口
      客戶區的左上角.
       X座標 - LOWORD(lParam),低16位
       Y座標 - HIWORD(lParam),高16位
    參數具體內容和具體鼠標消息有稍微不同.
   
  3 消息的使用
 
    3.1 基本鼠標消息,只需在窗口處理函數增加
      消息處理即可. 當消息來臨,獲取鼠標和按鍵
      狀態.例如:
       case WM_MOUSEMOVE:
    {
     int nX = LOWORD(lParam);
     int nY = HIWORD(lParam);
    }
    
    附:座標轉換的函數 ClientToScreen
      可以將鼠標座標轉換爲屏幕的座標.

   3.2 雙擊消息
   3.2.1 窗口註冊要增加 CS_DBLCLKS 類型
    wce.style = CS_DBLCLKS|...;
   3.2.2 在窗口處理函數中增加消息處理
   3.2.3 產生過程,例如:WM_LBUTTONDBLCLK
      WM_LBUTTONDOWN
      WM_LBUTTONUP
      WM_LBUTTONDBLCLK
      WM_LBUTTONUP
      連續兩次LBUTTONDOWN的時間間隔小於
      預定的雙擊時間間隔,就會產生
      LBUTTONDBLCLK消息.
      雙擊時間間隔可以通過控制面板調整.

 3.3 滾輪消息
  3.3.1 由於WM_MOUSEWHEEL需要Winnt4.0以上
    版本支持,所以需要包含在windows.h的頭
    文件前,增加 _WIN32_WINNT 宏定義,
        #define _WIN32_WINNT 0x0400
    3.3.2 在窗口處理函數中增加消息處理
    3.3.3 參數
     LPARAM 與其它鼠標消息類同
     WPARAM - LOWORD(WPARAM) 表示按鍵狀態
              HIWORD(WPARAM) 滾輪滾動幅度,
                120的倍數,可以爲正負值.
        正值: 滾輪向上滾動, 一般窗口向上滾動
        負值: 滾輪向下滾動, 一般窗口向下滾動


二 定時器消息

 1 定時器消息 WM_TIMER
   按照定時器設置時間段,自動向窗口發送一個
   定時器消息WM_TIMER. 優先級比較低.
   定時器精度比較低,毫秒級別.消息產生時間
   也精度比較低.
  
 2 消息和函數
   2.1 WM_TIMER  - 消息ID
    wParam: 定時器的ID
    lParam: 定時器的處理函數

   2.2 SetTimer  - 設置一個定時器
     UINT SetTimer(
    HWND hWnd, //窗口的句柄,可以爲NULL
    UINT nIDEvent,//定時器的ID,0爲不預設ID
    UINT uElapse,//定時器時間間隔,毫秒級別
    TIMERPROC lpTimerFunc );//定時器的處理函數,可以爲NULL
   返回一個創建好的定時器ID

  2.3 KillTimer - 結束一個定時器
    BOOL KillTimer(
      HWND hWnd,//窗口句柄
      UINT uIDEvent );//定時器ID
    
  2.4 TimerProc - 定時器處理函數
    VOID CALLBACK TimerProc(
     HWND hwnd, //窗口句柄
    UINT uMsg, //WM_TIMER消息ID
    UINT idEvent,//定時器ID
    DWORD dwTime   );//當前系統時間

  3 使用方式
    3.1 創建定時器 SetTimer
     3.1.1 指定窗口句柄HWND,那麼 TIMERPROC 參數
       可以爲空,那麼WM_TIMER消息將會發送給指定
       窗口. 如果未指定, TIMERPROC不能空, 必須
       指定定時器處理程序.
     3.1.2 如果指定定時器ID,SetTimer會按照這個
       ID創建定時器, 如果未指定,會返回一個創建
       定時器ID.
        nTimerID = SetTimer( NULL, 0, 7 * 1000,
           TimerProc1 );
    3.2 處理消息
      可以根據消息傳入定時器ID號,分別處理.
    3.3 結束定時器
      在不使用時, KillTimer結束定時器.
    KillTimer( hWnd, 1000 );

三 菜單
  1 菜單基礎
    菜單 - 每個菜單會有一個HMENU句柄
    菜單項 - 每個菜單項會有一個ID號,可以
          根據這個ID執行不同的操作
  2 菜單的使用
    2.1 菜單創建
      2.1.1 CreateMenu - MENU 菜單
      2.1.2 CreatePopupMenu -
         POPUPMENU 彈出式菜單
      2.1.3 AppenedMenu - 增加菜單項
     BOOL AppendMenu(
     HMENU hMenu, //菜單句柄
     UINT uFlags, //菜單項標示
     UINT uIDNewItem, //菜單項的ID或者子菜單句柄
     LPCTSTR lpNewItem ); //菜單項的名稱
    uFlags:
      MF_STRING - lpNewItem是一個字符串
      MF_POPUP  - uIDNewItem是一個子菜單句柄
      MF_SEPARATOR - 增加分隔項
      MF_CHECKED/MF_UNCHECKED -
        設置和取消菜單項的對勾
      MF_DISABLED/MF_ENABLE - 菜單項禁止和
        允許狀態
   2.2 菜單的命令響應
     2.2.1 WM_COMMAND消息
       當用戶點擊菜單、按鈕控件等時,系統會向
       窗口發送WM_COAMMD消息。
         WPARAM:HIWORD - 通知消息標識
                 LOWORD - 菜單項的ID號
         LPARAM:控件的句柄
     2.2.2 命令處理
        根據菜單項的ID號作相應處理。
       
   2.3 菜單項的狀態
      2.3.1 WM_INITMENUPOPUP消息
        當用戶點擊菜單,顯示彈出菜單之前,系統
        會向窗口發送WM_INITMENUPOPUP消息。
        WPARAM:是菜單句柄
        LPARAM:LOWORD - 菜單位置
                HIWORD - 是否是系統菜單
      2.3.2 命令處理
        根據WPARAM的菜單句柄,使用MenuAPI函數,
        修改菜單狀態。
         CheckMenuItem - 選擇
         EnableMenuItem - 允許和禁止
         SetMenuItemInfo - 可以設置更多信息

 

 

代碼:

// WinMessage.cpp : 定義應用程序的入口點。
//

#include "stdafx.h"
#include "WinMessage.h"

#define MAX_LOADSTRING 100
#define  WM_FirstMsg WM_USER + 1
#define  WM_SecondMsg WM_USER + 2
// 全局變量:
HINSTANCE hInst;        // 當前實例
TCHAR szTitle[MAX_LOADSTRING];     // 標題欄文本
TCHAR szWindowClass[MAX_LOADSTRING];   // 主窗口類名
HWND g_button;
HANDLE g_consHandle;
// 此代碼模塊中包含的函數的前向聲明:
ATOM    MyRegisterClass(HINSTANCE hInstance);
BOOL    InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
void newConsole()
{
 AllocConsole();
 g_consHandle = GetStdHandle(STD_OUTPUT_HANDLE);
 CHAR p[] = "debug message .....";
 WriteConsole(g_consHandle,p,strlen(p),NULL,NULL);

}
int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
 UNREFERENCED_PARAMETER(hPrevInstance);
 UNREFERENCED_PARAMETER(lpCmdLine);

  // TODO: 在此放置代碼。
 MSG msg;
 HACCEL hAccelTable;
 newConsole();
 // 初始化全局字符串
 LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
 LoadString(hInstance, IDC_WINMESSAGE, szWindowClass, MAX_LOADSTRING);
 MyRegisterClass(hInstance);

 // 執行應用程序初始化:
 if (!InitInstance (hInstance, nCmdShow))
 {
  return FALSE;
 }

 hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WINMESSAGE));

 // 主消息循環:
 while (GetMessage(&msg, NULL, 0, 0))
 {
  if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
  {
   TranslateMessage(&msg);
   DispatchMessage(&msg);
  }
 }

 return (int) msg.wParam;
}

 

//
//  函數: MyRegisterClass()
//
//  目的: 註冊窗口類。
//
//  註釋:
//
//    僅當希望
//    此代碼與添加到 Windows 95 中的“RegisterClassEx”
//    函數之前的 Win32 系統兼容時,才需要此函數及其用法。調用此函數十分重要,
//    這樣應用程序就可以獲得關聯的
//    “格式正確的”小圖標。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
 WNDCLASSEX wcex;

 wcex.cbSize = sizeof(WNDCLASSEX);

 wcex.style   = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
 wcex.lpfnWndProc = WndProc;
 wcex.cbClsExtra  = 0;
 wcex.cbWndExtra  = 0;
 wcex.hInstance  = hInstance;
 wcex.hIcon   = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WINMESSAGE));
 wcex.hCursor  = LoadCursor(NULL, IDC_ARROW);
 wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
 wcex.lpszMenuName = MAKEINTRESOURCE(IDC_WINMESSAGE);
 wcex.lpszClassName = szWindowClass;
 wcex.hIconSm  = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

 return RegisterClassEx(&wcex);
}

//
//   函數: InitInstance(HINSTANCE, int)
//
//   目的: 保存實例句柄並創建主窗口
//
//   註釋:
//
//        在此函數中,我們在全局變量中保存實例句柄並
//        創建和顯示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;

   hInst = hInstance; // 將實例句柄存儲在全局變量中

   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}
VOID CALLBACK TimerProc1(
 HWND hwnd,         // handle to window
 UINT uMsg,         // WM_TIMER message
 UINT_PTR idEvent,  // timer identifier
 DWORD dwTime       // current system time
 )
{
 char str[30];
 sprintf_s(str,"TimerProc1\n");
 WriteConsole(g_consHandle,str,strlen(str),NULL,NULL);
}
HMENU hPopMenu ;
void OnCreate(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{
 LPCREATESTRUCT pCreate = (LPCREATESTRUCT)lParam;
 
 //MessageBox(NULL,pCreate->lpszName,_T("onCreate"),MB_OK);
 //CreateWindowEx(WS_EX_STATICEDGE,_T("BUTTON"),_T("my button"),WS_CHILD ,20,20,20,20,hWnd,NULL,hInst,0);
 HWND m_hwnd = CreateWindow(_T("BUTTON"),_T("my button"),WS_CHILD ,10,0,70,20,hWnd,NULL,hInst,0);

 SetTimer(hWnd,1,1000,NULL);//有hwnd,
 SetTimer(NULL,2,1000,TimerProc1);

 //創建主菜單
 HMENU hMenu = CreateMenu();
 //創建子菜單
 hPopMenu = CreatePopupMenu();
 AppendMenu(hPopMenu,MF_STRING,1001,"修改");
 AppendMenu(hPopMenu,MF_SEPARATOR,0,NULL);
 AppendMenu(hPopMenu,MF_STRING,1002,"編輯");
 AppendMenu(hPopMenu,MF_STRING,1003,"刪除");
 AppendMenu(hMenu,MF_STRING,1011,"新建");
 AppendMenu(hMenu,MF_STRING|MF_POPUP,(UINT)hPopMenu,"文件(&F)"); //加了(&F)自動使用快捷鍵alt + F
 //創建子菜單
 HMENU hPopMenu1 = CreatePopupMenu();
 AppendMenu(hPopMenu,MF_STRING,1004,"hell");
 AppendMenu(hPopMenu,MF_STRING,1005,"aa");
 AppendMenu(hMenu,MF_STRING|MF_POPUP|MF_CHECKED,(UINT)hPopMenu1,"移動");
 //設置主菜單
 SetMenu(hWnd,hMenu);
 ShowWindow(m_hwnd, SW_SHOWNORMAL);
 UpdateWindow(m_hwnd);
 SendMessage(hWnd,WM_FirstMsg,0,0);
 //PostMessage(hWnd,WM_FirstMsg,0,0);
 g_button = m_hwnd;
}
void OnSize(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{
 int width = LOWORD(lParam);
 int height = HIWORD(lParam);

 CHAR buf[256] = {0};
 sprintf_s(buf,"width:%d,height:%d",width,height);
 if(g_button != NULL)
 {

  MoveWindow(g_button,(width-70)/2,(height-20)/2,70,20,TRUE);
 }
 //printf(buf);
}
void OnSysCommand(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{
 switch(wParam)
 {

 case  SC_CLOSE:
   MessageBox(hWnd,_T("是否將窗口關閉?"),_T(""),MB_YESNO);
  PostQuitMessage(0);
  //else return FALSE;
  break;
 }
 //return TRUE;
}
//
//  函數: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  目的: 處理主窗口的消息。
//
//  WM_COMMAND - 處理應用程序菜單
//  WM_PAINT - 繪製主窗口
//  WM_DESTROY - 發送退出消息並返回
//
//
int x,y;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 int wmId, wmEvent;
 PAINTSTRUCT ps;
 char str[40];
 HDC hdc;
  BOOL f = FALSE;
  
  POINT p;
 switch (message)
 {
 case WM_COMMAND:
  wmId    = LOWORD(wParam);
  wmEvent = HIWORD(wParam);
  // 分析菜單選擇:
  switch (wmId)
  {
  case IDM_ABOUT:
   DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
   break;
  case IDM_EXIT:
   DestroyWindow(hWnd);
   break;
 
  default:
   return DefWindowProc(hWnd, message, wParam, lParam);
  }
  break;
 case WM_PAINT:
  hdc = BeginPaint(hWnd, &ps);
  // TODO: 在此添加任意繪圖代碼...
  //TextOut(hdc,x,y,"hello",strlen(
  // "hello"));
  EndPaint(hWnd, &ps);
  break;
 case WM_DESTROY:
  KillTimer(hWnd,1);
  KillTimer(hWnd,2);
  PostQuitMessage(0);
  break;

 case WM_CREATE:
  OnCreate(hWnd,message,wParam,lParam);
  break;
 case WM_SIZE:
  OnSize(hWnd,message,wParam,lParam);
  break;
 case WM_SYSCOMMAND:
 
   OnSysCommand(hWnd,message,wParam,lParam);
  
  break;
 case WM_FirstMsg:
  //MessageBox(hWnd,_T("firsstMsg"),_T(""),0);
  break;
 case WM_LBUTTONDOWN:

  sprintf_s(str,"WM_LBUTTONDOWN\n");
  WriteConsole(g_consHandle,str,strlen(str),NULL,NULL);

  break;
 case WM_RBUTTONDOWN:
  sprintf_s(str,"WM_RBUTTONDOWN\n");
  WriteConsole(g_consHandle,str,strlen(str),NULL,NULL);
  TrackPopupMenu(hPopMenu,MF_POPUP,x,y,0,hWnd,NULL);
  break;
 case WM_MBUTTONDOWN:
  sprintf_s(str,"WM_MBUTTONDOWN\n");
  WriteConsole(g_consHandle,str,strlen(str),NULL,NULL);
  break;
 case WM_MOUSEMOVE:
         
    if(wParam & MK_CONTROL)
     {
      sprintf_s(str,"MK_CONTROL\n");
     WriteConsole(g_consHandle,str,strlen(str),NULL,NULL);
    }
  
  x = LOWORD(lParam);
  y = HIWORD(lParam);
  InvalidateRect(hWnd,NULL,TRUE);
  p.x = x;
  p.y = y;
  ClientToScreen(hWnd,&p);
  sprintf_s(str,"WM_MOUSEMOVE,X =%dY =%d\n",p.x,p.y);
  WriteConsole(g_consHandle,str,strlen(str),NULL,NULL);
  break;
 case WM_LBUTTONDBLCLK:
  sprintf_s(str,"WM_LBUTTONDBLCLK\n");
  WriteConsole(g_consHandle,str,strlen(str),NULL,NULL);
  break;
 case WM_MOUSEWHEEL:
  sprintf_s(str,"WM_MOUSERWHEEL\n");
  WriteConsole(g_consHandle,str,strlen(str),NULL,NULL);
  break;
 case WM_TIMER:
  sprintf_s(str,"WM_TIMER%d\n",wParam);
  WriteConsole(g_consHandle,str,strlen(str),NULL,NULL);
  break;
 default:
  return DefWindowProc(hWnd, message, wParam, lParam);
 }
 return 0;
}

 


// “關於”框的消息處理程序。
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
 UNREFERENCED_PARAMETER(lParam);
 switch (message)
 {
 case WM_INITDIALOG:
  return (INT_PTR)TRUE;

 case WM_COMMAND:
  if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
  {
   EndDialog(hDlg, LOWORD(wParam));
   return (INT_PTR)TRUE;
  }
  break;
 

 }
 return (INT_PTR)FALSE;
}

 

 

 


        

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章