win32程序之子窗口編程


              win32程序之子窗口編程

一丶簡介.什么是子窗口

  在前邊我們已經講解了窗口的本質.以及如何注冊窗口類跟創建窗口. 還講了消息循環.

那么有很多窗口其實Windows已經幫我們創建出來了.我們直接使用即可. 而這些窗口都有自己的消息循環. 只有改變狀態的時候.才會發送消息給我們的父窗口通知.

此時我們捕獲消息就可以進行處理了.

子窗口其實就是繪制在主窗口的一個窗口.  這些窗口包含了  BUTTON  (按鈕控件)  EDIT(編輯框控件) .....

 

二丶創建子窗口

1.創建EDIT子窗口

  創建子窗口很簡單. 使用CreteWindow API. 類名修改為EDIT. 父窗口句柄修改為我們的主窗口句柄.  並且為子窗口設置創建類型.  以及子窗口標識符即可.

具體代碼如下: 當主窗口創建消息來得時候.我們創建一個EDIT編輯框.

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

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include "WindoS.h"

#define MAX_LOADSTRING 100

// 全局變量: 
HINSTANCE g_hInst;                                // 當前實例
WCHAR szTitle[MAX_LOADSTRING]  = TEXT("第一個我的窗口");                  // 標題欄文本
WCHAR szWindowClass[MAX_LOADSTRING] = TEXT("MyWindow");            // 主窗口類名
#define IDC_MY_EDIT_ONE 10  //編輯框的ID 自己定義即可.
// 此代碼模塊中包含的函數的前向聲明: 

LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);


int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    //1.自定義窗口樣式
    g_hInst = hInstance;
    WNDCLASS wcex;


    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = WndProc;                          //設置回調
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WINDOS));
    wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_WINDOS);
    wcex.lpszClassName = szWindowClass;
    
    //2.注冊窗口類
    BOOL bRet = RegisterClass(&wcex); //A RegisterClass U RegisterClassW  擴展 RegisterClassExA /ExW
    if (bRet == FALSE)
    {
        return 0;
    }
    //3.創建窗口 並且顯示跟更新窗口
    HWND hWnd = CreateWindowW(
        szWindowClass,
        szTitle,
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT,
        0,
        CW_USEDEFAULT,
        0, 
        nullptr,
        nullptr,
        hInstance,
        nullptr);

    if (!hWnd)
    {
        return FALSE;
    }

    ShowWindow(hWnd, SW_SHOW);
    UpdateWindow(hWnd);

    //4.消息循環.
    MSG msg;
    /*    1參數是消息結構體.操作系統會往里面填寫消息. 
        2 參數窗口句柄 因為每個線程可以有多個窗口.表示我要取那個窗口的消息
        3.4 參數表示我要取這個窗口的那個消息. 后面三個參數屬於過濾條件


    */
    while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)        
    {
        if (bRet == -1)
        {
            // handle the error and possibly exit
        }
        else
        {
            TranslateMessage(&msg);      //鍵盤消息轉換為小寫.
            DispatchMessage(&msg);      //分發消息.將我們的消息傳遞給我們的回調函數處理.
        }
    }

    return 0;
}






//
//  函數: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  目的:    處理主窗口的消息。
//
//  WM_COMMAND  - 處理應用程序菜單
//  WM_PAINT    - 繪制主窗口
//  WM_DESTROY  - 發送退出消息並返回
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_CREATE:
    {
         CreateWindowW( //創建編輯框
            TEXT("EDIT"),
            TEXT("編輯框所處位置"),
            WS_CHILD | WS_VISIBLE | WS_VSCROLL, //前3個是通用風格.EDIT風格搜索MSDN 搜索Edit Style即可.
            10,10,800,400,             //設置X Y 坐標.設置高度跟寬度.
             hWnd,                    //父類句柄
            (HMENU)IDC_MY_EDIT_ONE,
            g_hInst,
            nullptr);
        break;
    }
    case WM_COMMAND:
        {
            int wmId = LOWORD(wParam);
            // 分析菜單選擇: 
            switch (wmId)
            {
            case IDM_EXIT:
                DestroyWindow(hWnd);
                break;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
            }
        }
        break;
    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            // TODO: 在此處添加使用 hdc 的任何繪圖代碼...
            
            EndPaint(hWnd, &ps);
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

上面紅色的那塊是很重要的. 重要參數標注出來.

1.窗口類名. 我們是使用的Windows默認的窗口類名.所以填寫EDIT

2.窗口風格. 窗口風格是使用的CreateWindow 中MSDN提供的默認風格. 當然編輯框也有自己的風格.我們可以MSDN搜尋 EDIT styles 查看說明.

3.父窗口句柄. 因為這個是創建在父窗口的所以我們的父窗口句柄一定要填寫.

4.實例句柄.這個必須要填寫的.已經改成全局變量了.

5.編輯框的ID.編輯框的ID屬於是控件ID. 這個位置在MSDN有說明. 如果創建的是父窗口.這個地方填寫的則是菜單.也就是HMENU類型的.但是如果是子窗口.那么這個位置就變成了控件ID了.

具體可以查看MSDN說明. 這個控件ID很重要.關乎到我們處理消息.

2.創建按鈕子窗口

  上面創建了EDIT.那我們也可以創建按鈕子窗口了.具體代碼跟創建EDIT位置處一樣.

     CreateWindowW(                                    //創建按鈕
             TEXT("BUTTON"),
             TEXT("設置"),
             WS_CHILD | WS_VISIBLE, //
             820, 30, 100, 40,             //設置X Y 坐標.設置高度跟寬度.
             hWnd,                    //父類句柄
             (HMENU)IDC_MY_BUTTON_ONE,
             g_hInst,
             nullptr);


         CreateWindowW(                                    //創建按鈕
             TEXT("BUTTON"),
             TEXT("獲取"),
             WS_CHILD | WS_VISIBLE, //
             820, 80, 100, 40,             //設置X Y 坐標.設置高度跟寬度.
             hWnd,                    //父類句柄
             (HMENU)IDC_MY_BUTTON_TWO,
             g_hInst,
             nullptr);

這兩行代碼放到創建EDIT下面即可.

關於按鈕的ID.我們設置一個自定義的整數值即可. 使用的時候需要強轉為HMENU類型.

 

結果演示.

 

 三丶響應子窗口的消息.

  現在我們已經創建完畢子窗口了.那么我們想的是我要響應按鈕消息什么的.

Windows雖然為每個子控件提供了消息處理函數. 也就是回調. 但是Windows為了讓我們處理消息. 所以子窗口有一個特性. 就是說當改變狀態的時候.會通知父窗口.

怎么理解.什么意思?  意思就是說.當我們點擊這個按鈕的時候.windows會發給我們父窗口一個消息. 我們只需要接受這個消息即可. 但是我們如何知道是哪個消息.?

既然我們知道了子窗口改變狀態會發送消息.那么我們可以調試一下.打印一下消息.

 

也就是在我們父窗口的消息處理回調中打印一下消息. 使用DebugView查看.或者調試查看都可以. 

因為當我們點擊才會出現這個消息.那么我們可以看下這個消息是什么消息.

我們可以隨便點擊一個消息.查看定義.即可看到Windows全部的消息了.  windows消息都放在了WinUser.h中

可以看到通知父窗口的是WM_COMMAND消息.

所以我們直接捕獲這個消息進行處理即可.

查詢MSDN 查詢WM_COMMAND消息.

詳細說明了.如果是WM_COMMAND消息. 那么參數三是控件ID.  還記得上面我們說的嗎. 要給每個控件分配一個控件ID. 就是在這里使用的.

具體看參數就如上圖所示. 告訴你了.低位才是 ID. 也就是 menu item標記. 所以我們需要取低位來判斷. 因為WPARAME 是32位.所以低位是16位.

我們可以自己使用位運算取.也可以使用操作系統提供的  LOWORD 來取.

具體代碼如下圖所示.  PS: 直接拷貝窗口回調函數了.

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	

    switch (message)
    {
	case WM_CREATE:
	{
		 CreateWindowW(									//創建編輯框
			TEXT("EDIT"),
			TEXT("編輯框所處位置"),
			WS_CHILD | WS_VISIBLE | WS_VSCROLL, //前3個是通用風格.EDIT風格搜索MSDN 搜索Edit Style即可.
			10,10,800,400,             //設置X Y 坐標.設置高度跟寬度.
			 hWnd,					//父類句柄
			(HMENU)IDC_MY_EDIT_ONE,
			g_hInst,
			nullptr);

		 CreateWindowW(									//創建按鈕
			 TEXT("BUTTON"),
			 TEXT("設置"),
			 WS_CHILD | WS_VISIBLE, //
			 820, 30, 100, 40,             //設置X Y 坐標.設置高度跟寬度.
			 hWnd,					//父類句柄
			 (HMENU)IDC_MY_BUTTON_ONE,
			 g_hInst,
			 nullptr);


		 CreateWindowW(									//創建按鈕
			 TEXT("BUTTON"),
			 TEXT("獲取"),
			 WS_CHILD | WS_VISIBLE, //
			 820, 80, 100, 40,             //設置X Y 坐標.設置高度跟寬度.
			 hWnd,					//父類句柄
			 (HMENU)IDC_MY_BUTTON_TWO,
			 g_hInst,
			 nullptr);


		break;
	}
    case WM_COMMAND:                               //獲取Command消息. 取出低位ID. 根據ID進行不同的操作.
        {
            int wmId = LOWORD(wParam);
            // 分析菜單選擇: 
            switch (wmId)
            {
            case IDM_EXIT:
                DestroyWindow(hWnd);
                break;
			case IDC_MY_BUTTON_ONE:    //按鈕設置點擊則回來
			{
				 //這個ID是按鈕設置的ID.所以當按鈕設置就會來這里了.
				SetDlgItemText(hWnd, IDC_MY_EDIT_ONE, TEXT("設置到編輯框的內容"));  //此API時設置指定窗口中控件ID的顯示名稱.我們給編輯框設置.所以ID是編輯框的ID.
				break;
			}
			case IDC_MY_BUTTON_TWO:
			{
				// ID同上所示
				TCHAR str[1024] = { NULL };
				GetDlgItemText(hWnd, IDC_MY_EDIT_ONE, str, sizeof(str));        //有設置就有獲取. 獲取就是需要提供緩沖區而已.然后Msg信息框彈出.
				MessageBox(hWnd, str, NULL, NULL);
				break;
			}
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
            }
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return DefWindowProc(hWnd, message, wParam, lParam);
} 

最終實現結果.

點擊設置后.編輯框的內容會改變.

 

 

 點擊獲取后則會獲取編輯框的內容.

四丶完整代碼.

最后附上完整代碼.拷貝就能使用. VS2015編寫.不確定是否可以.不過可以參考代碼.

代碼如下:

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

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include "WindoS.h"

#define MAX_LOADSTRING 100

// 全局變量: 
HINSTANCE g_hInst;                                // 當前實例
WCHAR szTitle[MAX_LOADSTRING]  = TEXT("第一個我的窗口");                  // 標題欄文本
WCHAR szWindowClass[MAX_LOADSTRING] = TEXT("MyWindow");            // 主窗口類名
#define IDC_MY_EDIT_ONE 10  //編輯框的ID 自己定義即可.
#define IDC_MY_BUTTON_ONE 11
#define IDC_MY_BUTTON_TWO 12
// 此代碼模塊中包含的函數的前向聲明: 

LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);


int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
	//1.自定義窗口樣式
	g_hInst = hInstance;
	WNDCLASS wcex;


	wcex.style = CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc = WndProc;                          //設置回調
	wcex.cbClsExtra = 0;
	wcex.cbWndExtra = 0;
	wcex.hInstance = hInstance;
	wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WINDOS));
	wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
	wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
	wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_WINDOS);
	wcex.lpszClassName = szWindowClass;
	
	//2.注冊窗口類
	BOOL bRet = RegisterClass(&wcex); //A RegisterClass U RegisterClassW  擴展 RegisterClassExA /ExW
	if (bRet == FALSE)
	{
		return 0;
	}
	//3.創建窗口 並且顯示跟更新窗口
	HWND hWnd = CreateWindowW(
		szWindowClass,
		szTitle,
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT,
		0,
		CW_USEDEFAULT,
		0, 
		nullptr,
		nullptr,
		hInstance,
		nullptr);

	if (!hWnd)
	{
		return FALSE;
	}

	ShowWindow(hWnd, SW_SHOW);
	UpdateWindow(hWnd);

	//4.消息循環.
	MSG msg;
	/*	1參數是消息結構體.操作系統會往里面填寫消息. 
		2 參數窗口句柄 因為每個線程可以有多個窗口.表示我要取那個窗口的消息
		3.4 參數表示我要取這個窗口的那個消息. 后面三個參數屬於過濾條件


	*/
	while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)        
	{
		if (bRet == -1)
		{
			// handle the error and possibly exit
		}
		else
		{
			TranslateMessage(&msg);      //鍵盤消息轉換為小寫.
			DispatchMessage(&msg);      //分發消息.將我們的消息傳遞給我們的回調函數處理.
		}
	}

	return 0;
}






//
//  函數: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  目的:    處理主窗口的消息。
//
//  WM_COMMAND  - 處理應用程序菜單
//  WM_PAINT    - 繪制主窗口
//  WM_DESTROY  - 發送退出消息並返回
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	

    switch (message)
    {
	case WM_CREATE:
	{
		 CreateWindowW(									//創建編輯框
			TEXT("EDIT"),
			TEXT("編輯框所處位置"),
			WS_CHILD | WS_VISIBLE | WS_VSCROLL, //前3個是通用風格.EDIT風格搜索MSDN 搜索Edit Style即可.
			10,10,800,400,             //設置X Y 坐標.設置高度跟寬度.
			 hWnd,					//父類句柄
			(HMENU)IDC_MY_EDIT_ONE,
			g_hInst,
			nullptr);

		 CreateWindowW(									//創建按鈕
			 TEXT("BUTTON"),
			 TEXT("設置"),
			 WS_CHILD | WS_VISIBLE, //
			 820, 30, 100, 40,             //設置X Y 坐標.設置高度跟寬度.
			 hWnd,					//父類句柄
			 (HMENU)IDC_MY_BUTTON_ONE,
			 g_hInst,
			 nullptr);


		 CreateWindowW(									//創建按鈕
			 TEXT("BUTTON"),
			 TEXT("獲取"),
			 WS_CHILD | WS_VISIBLE, //
			 820, 80, 100, 40,             //設置X Y 坐標.設置高度跟寬度.
			 hWnd,					//父類句柄
			 (HMENU)IDC_MY_BUTTON_TWO,
			 g_hInst,
			 nullptr);


		break;
	}
    case WM_COMMAND:
        {
            int wmId = LOWORD(wParam);
            // 分析菜單選擇: 
            switch (wmId)
            {
            case IDM_EXIT:
                DestroyWindow(hWnd);
                break;
			case IDC_MY_BUTTON_ONE:
			{
				 //這個ID是按鈕設置的ID.所以當按鈕設置就會來這里了.
				SetDlgItemText(hWnd, IDC_MY_EDIT_ONE, TEXT("設置到編輯框的內容"));
				break;
			}
			case IDC_MY_BUTTON_TWO:
			{
				// ID同上所示
				TCHAR str[1024] = { NULL };
				GetDlgItemText(hWnd, IDC_MY_EDIT_ONE, str, sizeof(str));
				MessageBox(hWnd, str, NULL, NULL);
				break;
			}
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
            }
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return DefWindowProc(hWnd, message, wParam, lParam);
}

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM