文章目录
一、界面开发三步走
①纯API进行窗口的[手动]创建+[手动]创建控件+[手动]响应消息;
②纯API进行对话框窗口的[半手动]创建+[自动]创建控件+[手动]响应消息;
③MFC窗口的[自动]创建+[自动]创建控件+[自动]响应消息;
备注。为保持程序的灵活性,以及让大家学到更多的东西,针对第③点我们只是界面部分用MFC,其余逻辑部分仍然用WinAPI进行开发。
二、纯API进行窗口的[手动]创建+[手动]创建控件+[手动]响应消息
1.Win32窗口程序的创建流程[手动]
第一步:注册窗口类,指定窗口类的名称与窗口回调函数
第二步:创建窗口,指定注册窗口类,窗口标题,窗口的大小
第三步:显示窗口
第四步:开始消息循环
第五步:窗口函数中处理窗口消息
代码如下:
#include <windows.h>
#include <tchar.h>
static TCHAR szWindowClass[] = _T("WindowClass"); //窗口类名
static TCHAR szTitle[] = _T("我的第一个程序"); //窗口标题
//第五步:窗口函数中处理窗口消息
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
//消息处理函数.参数:窗口句柄,消息,消息参数,消息参数
{
PAINTSTRUCT ps;
HDC hdc;
TCHAR greeting[] = _T("大家好!"); //窗口内容
switch (uMsg)//处理所需的消息
{
case WM_CLOSE://窗口关闭的时候添加确认提示框,取消则不关闭窗口
{
int iRet = MessageBox(hWnd, _T("要关闭窗口吗?"), _T("Tip"), MB_OKCANCEL);
if (iRet == IDOK) return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
break;
case WM_SIZE://窗口被最大化的时候添加 MessageBox 提示框;
{
if (wParam == SIZE_MAXIMIZED)
{MessageBox(hWnd, _T("窗口被最大化啦!"), _T("Tip"), MB_OK);}
}
break;
case WM_CREATE://窗口创建的时候添加提示框;
MessageBox(hWnd, _T("窗口被创建啦!"), _T("Tip"), MB_OK);
break;
case WM_PAINT://窗口绘制消息
hdc = BeginPaint(hWnd, &ps);
TextOut(hdc, 5, 5, greeting, _tcslen(greeting));
EndPaint(hWnd, &ps);
break;
case WM_DESTROY://当用户关闭窗口,窗口销毁,程序需结束,发退出消息,以退出消息循环
PostQuitMessage(0);
break;
default://其他消息交给由系统提供的缺省处理函数
return DefWindowProc(hWnd, uMsg, wParam, lParam);
break;
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
//应用程序主函数。参数:实例句柄、前一个实例的句柄、命令行参数、窗口显示方式
{
//第一步:注册窗口类,指定窗口类的名称与窗口回调函数
WNDCLASSEX wcex = { 0 };//RegisterClassEx中的结构指针
wcex.cbSize = sizeof(WNDCLASSEX);//WNDCLASSEX 的大小
wcex.lpfnWndProc = WindowProc; //关联消息处理函数
wcex.lpszClassName = szWindowClass;//类名称
if (!RegisterClassEx(&wcex))
//RegisterClassEx注册窗口类,如果函数成功,返回这个窗口类型的标识号;如果函数失败,返回值为FALSE
{
MessageBox(NULL, _T("注册窗口失败"), _T("Tip"), NULL);
return 1;
}
//第二步:创建窗口,指定注册窗口类,窗口标题,窗口的大小
HWND hWnd = CreateWindow( //创建一个重叠窗口
szWindowClass, //窗口类名
szTitle, //窗口标题,最开头定义过
WS_OVERLAPPEDWINDOW, //指定创建窗口的风格
CW_USEDEFAULT, CW_USEDEFAULT,//窗口初始位置
500, 300, //窗口初始宽、高
NULL, //指向被创建窗口的父窗口或所有者窗口的句柄
NULL, //菜单句柄,或依据窗口风格指明一个子窗口标识
hInstance, //与窗口相关联的模块实例的句柄。
NULL //指向一个值的指针,该值传递给窗口WM_CREATE消息。
);
if (!hWnd)//CreateWindow函数执行成功,返回新创建窗口的窗口句柄,函数执行失败返回NULL
{
MessageBox(NULL, _T("创建窗口失败!"), _T("Tip"), NULL);
return 1;
}
//第三步:显示窗口
ShowWindow(hWnd, nCmdShow);//窗口句柄,窗口激活方式
// 第四步:开始消息循环
MSG msg = { 0 };
while (GetMessage(&msg, NULL, 0, 0))//从消息队列中取消息
{
TranslateMessage(&msg); // 将虚拟键消息转换为字符消息
DispatchMessage(&msg);//派发消息
}
return (int)msg.wParam;
}
2.Win32窗口控件的创建与响应[手动]
(1)控件的创建时机
①在WinMain函数中创建,即调用完CreateWindow函数创建完父窗口之后,再调用CreateWindow函数来创建主窗口上面的子控件;
②在窗口创建后,显示之前,即调用CreateWindow函数创建主窗口返回之前,我们的窗口函数会收到WM_CREATE消息,此时,我们响应它的号召,艰苦奋斗的创建各个子控件。这种做法是常规正常的做法,我们以下也使用这种做法。 (推荐第二种)
#include <windows.h>
#include <tchar.h>
#include <commctrl.h>
static TCHAR szWindowClass[] = _T("WindowClass");
static TCHAR szTitle[] = _T("窗口标题");
//控件ID
UINT IDC_BUTTON_1 = 200;
UINT IDC_BUTTON_2 = 201;
//第五步:窗口函数中处理窗口消息
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
TCHAR greeting[] = _T("窗口中内容");
switch (uMsg)
{
case WM_CREATE: //创建两个按钮
{
HWND hButtonWnd1 = CreateWindow(WC_BUTTON, _T("按钮一"), WS_CHILD | BS_PUSHBUTTON | WS_VISIBLE, 100, 100, 100, 50, hWnd, (HMENU)IDC_BUTTON_1, NULL, NULL);
HWND hButtonWnd2 = CreateWindow(WC_BUTTON, _T("按钮二"), WS_CHILD | BS_PUSHBUTTON | WS_VISIBLE, 100, 200, 100, 50, hWnd, (HMENU)IDC_BUTTON_2, NULL, NULL);
//1、ws_CHILD样式:控件是放在窗口上的,自然要作为窗口的子窗口;
//2、ws_VISIBLE样式:既然要使用控件,自然要让别人看得见;
//3、BS_PUSHBUTTON样式:作为下压式按钮存在。
//4、控件基本都要指定一个整型的不重复的ID,这样以后操作起来可以直接使用控件的ID来找到并操作控件,不然还得记住每个控件的窗口句柄。
}
break;
case WM_COMMAND:
{
UINT nCtrlID = LOWORD(wParam); //低字节表示ID号
UINT nCode = HIWORD(wParam); //高字节表示通知码BN_CLICKED
if (nCode == BN_CLICKED)
{
if (nCtrlID == IDC_BUTTON_1)
{
MessageBox(hWnd, _T("按键1被按下了"), _T("Tip"), MB_OK);
}
else if (nCtrlID == IDC_BUTTON_2)
{
MessageBox(hWnd, _T("按键2被按下了"), _T("Tip"), MB_OK);
}
}
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
TextOut(hdc, 5, 5, greeting, _tcslen(greeting));
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
break;
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
//第一步:注册窗口类,指定窗口类的名称与窗口回调函数
WNDCLASSEX wcex = { 0 };
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.lpfnWndProc = WindowProc;
wcex.lpszClassName = szWindowClass;
if (!RegisterClassEx(&wcex))
{
MessageBox(NULL, _T("注册窗口失败"), _T("Tip"), NULL);
return 1;
}
//第二步:创建窗口,指定注册窗口类,窗口标题,窗口的大小
HWND hWnd = CreateWindow(
szWindowClass,
szTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
500, 300,
NULL,
NULL,
hInstance,
NULL
);
if (!hWnd)
{
MessageBox(NULL, _T("创建窗口失败!"), _T("Tip"), NULL);
return 1;
}
第一种方式:在这里创建子窗口或者控件 CreateWindow
//第三步:显示窗口
ShowWindow(hWnd, nCmdShow);
// 第四步:开始消息循环
MSG msg = { 0 };
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);//消息分发
}
return (int)msg.wParam;
}
(2)小作业
- 作业1:按钮(标题)文本动态变化,显示该按钮被点击的次数,每点击一次,次数加1s;
- 作业2:动态创建编辑框控件;
- 作业3:点击按钮时,弹出提示框,提示框的内容是编辑框中的字符串;
//控件ID
UINT IDC_BUTTON_1 = 200;
UINT IDC_BUTTON_2 = 201;
UINT IDC_EDIT_1 = 301;
//第五步:窗口函数中处理窗口消息
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
TCHAR greeting[] = _T("窗口中内容!");
switch (uMsg)
{
case WM_CREATE:
{
HWND hButtonWnd1 = CreateWindow(WC_BUTTON, _T("我是按钮1"), WS_CHILD | BS_PUSHBUTTON | WS_VISIBLE, 30, 40, 180, 30, hWnd, (HMENU)IDC_BUTTON_1, NULL, NULL);
HWND hButtonWnd2 = CreateWindow(WC_BUTTON, _T("我是按钮2"), WS_CHILD | BS_PUSHBUTTON | WS_VISIBLE, 260, 40, 180, 30, hWnd, (HMENU)IDC_BUTTON_2, NULL, NULL);
HWND hEditWnd1 = CreateWindow(WC_EDIT, _T("编辑框中文字"), WS_CHILDWINDOW | WS_BORDER | WS_VISIBLE | ES_AUTOHSCROLL,260, 100, 180, 30, hWnd, (HMENU)IDC_EDIT_1, NULL, NULL); //作业2
}
break;
case WM_COMMAND:
{
UINT nCtrlID = LOWORD(wParam);
UINT nCode = HIWORD(wParam); //BN_CLICKED
if (nCode == BN_CLICKED)
{
if (nCtrlID == IDC_BUTTON_1)
{
static int nButton1_Times = 0;
TCHAR szButton1Times[128] = { 0 };
_stprintf(szButton1Times, _T("按钮1被点击了 %d 次!"), ++nButton1_Times);
//MessageBox(hWnd, szButton1Times, _T("Tip"), MB_OK);
SetWindowText(GetDlgItem(hWnd, nCtrlID), szButton1Times); //作业1
TCHAR szEditText[256] = { 0 };
GetDlgItemText(hWnd, IDC_EDIT_1, szEditText, 256);
MessageBox(hWnd, szEditText, _T("Tip"), MB_OK); //作业3
}
else if (nCtrlID == IDC_BUTTON_2)
{
static int nButton2_Times = 0;
TCHAR szButton2Times[128] = { 0 };
_stprintf(szButton2Times, _T("按钮2被点击了 %d 次!"), ++nButton2_Times);
//MessageBox(hWnd, szButton2Times, _T("Tip"), MB_OK);
SetWindowText(GetDlgItem(hWnd, nCtrlID), szButton2Times);//作业1
}
}
}
break;
(3)各类控件
UINT IDC_STATIC = 200;
UINT IDC_BUTTON = 201;
UINT IDC_RADIO1 = 301;
UINT IDC_RADIO2 = 302;
UINT IDC_SCBL = 303;
UINT IDC_COMBOX = 304;
UINT IDC_LISTBOX = 305;
switch (uMsg)
{
case WM_CREATE:
{
//创建静态文本框
HWND hStatic = CreateWindow(TEXT("STATIC"), TEXT("Test String"), WS_CHILD|WS_VISIBLE, 10, 10, 100, 50, hWnd, (HMENU)IDC_STATIC, NULL, NULL);
SetWindowText(hStatic, L"更改后的内容!");
//创建button
CreateWindow(TEXT("BUTTON"), TEXT("Click Me"), WS_CHILD | WS_VISIBLE, 10, 40, 80, 20, hWnd, (HMENU)IDC_BUTTON, NULL, NULL);
//创建单选框
CreateWindow(TEXT("BUTTON"), TEXT("radio button"), WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON, 134, 10, 40, 20, hWnd, (HMENU)IDC_RADIO1, NULL, NULL);
//创建复选框
CreateWindow(TEXT("BUTTON"), TEXT("radio button"), WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX, 134, 40, 40, 20, hWnd, (HMENU)IDC_RADIO2, NULL, NULL);
//创建滚动条
CreateWindow(TEXT("SCROLLBAR"), NULL, WS_CHILD | WS_VISIBLE | SBS_HORZ, 10, 70, 200, 20, hWnd, (HMENU)IDC_SCBL, NULL, NULL);
//创建组合框
CreateWindow(TEXT("COMBOBOX"), NULL, WS_CHILD | WS_VISIBLE | WS_VSCROLL | CBS_AUTOHSCROLL | CBS_DROPDOWNLIST, 10, 100, 100, 90, hWnd, (HMENU)IDC_COMBOX, NULL, NULL);
//创建列表框
CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("LISTBOX"), NULL, WS_CHILD | WS_VISIBLE | LBS_STANDARD, 10, 140, 80, 90, hWnd, (HMENU)IDC_LISTBOX, NULL, NULL);
}
break;
}
3.Win32窗口高级列表控件的使用
(1)列表控件的操作流程(主动)
#include <windows.h>
#include <tchar.h>
#include <commctrl.h>
static TCHAR szWindowClass[] = _T("WindowClass");
static TCHAR szTitle[] = _T("窗口标题");
//控件ID
UINT IDC_BUTTON_1 = 200;
UINT IDC_BUTTON_2 = 201;
UINT IDC_LIST = 301;
//第五步:窗口函数中处理窗口消息
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
TCHAR greeting[] = _T("窗口中内容");
switch (uMsg)
{
case WM_CREATE: //创建两个按钮
{
HWND hButtonWnd1 = CreateWindow(WC_BUTTON, _T("按钮一"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 100, 50, 100, 50, hWnd, (HMENU)IDC_BUTTON_1, NULL, NULL);
HWND hButtonWnd2 = CreateWindow(WC_BUTTON, _T("按钮二"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 100, 150, 100, 50, hWnd, (HMENU)IDC_BUTTON_2, NULL, NULL);
HWND hListCtrl = CreateWindow(WC_LISTVIEW, _T(""), WS_CHILD | WS_VISIBLE | WS_BORDER|LWS_REPORT|LVS_SHOWSELALWAYS, 150, 200, 200, 200, hWnd, (HMENU)IDC_LIST, NULL, NULL);
//子控件 | 可见 |边框 |报表样式 | 一直显示选中...
}
break;
case WM_COMMAND:
{
UINT nCtrlID = LOWORD(wParam); //低字节表示ID号
UINT nCode = HIWORD(wParam); //高字节表示通知码BN_CLICKED
if (nCode == BN_CLICKED)
{
if (nCtrlID == IDC_BUTTON_1)
{
MessageBox(hWnd, _T("按键1被按下了"), _T("Tip"), MB_OK);
}
else if (nCtrlID == IDC_BUTTON_2)
{
MessageBox(hWnd, _T("按键2被按下了"), _T("Tip"), MB_OK);
}
}
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
TextOut(hdc, 5, 5, greeting, _tcslen(greeting));
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
break;
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
//第一步:注册窗口类,指定窗口类的名称与窗口回调函数
WNDCLASSEX wcex = { 0 };
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.lpfnWndProc = WindowProc;
wcex.lpszClassName = szWindowClass;
if (!RegisterClassEx(&wcex))
{
MessageBox(NULL, _T("注册窗口失败"), _T("Tip"), NULL);
return 1;
}
//第二步:创建窗口,指定注册窗口类,窗口标题,窗口的大小
HWND hWnd = CreateWindow(
szWindowClass,
szTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
500, 300,
NULL,
NULL,
hInstance,
NULL
);
if (!hWnd)
{
MessageBox(NULL, _T("创建窗口失败!"), _T("Tip"), NULL);
return 1;
}
第一种方式:在这里创建子窗口或者控件 CreateWindow
//第三步:显示窗口
ShowWindow(hWnd, nCmdShow);
// 第四步:开始消息循环
MSG msg = { 0 };
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);//消息分发
}
return (int)msg.wParam;
}
三、MFC窗口的[自动]创建+[自动]创建控件+[自动]响应消息
工程自带的两个类
新生成的对话框工程主要有两个类:主线程类、主对话框类。
主线程类的初始化函数中创建主对话框,主对话框类负责界面显示。
总结
以上就是Windows 窗口界面的简单实现。