前面我们学习了win32消息机制,我们都知道一个软件的展开,出现在我们面前的就是一个界面,而我们在选择操作的时候,就会有很多的选项,这个就叫做菜单。菜单的设置以及库的应用,对我们开发软件会有很多的帮助。
从编程的角度来说,可以分以下几类:
①.静态菜单:在菜单资源编译器中提前编译好。
②.动态菜单:在程序运行的过程中通过代码实现。
③.快捷菜单:是前两种菜单的组合,在菜单资源编辑器中预先编辑好,然后在程序运行过程中动态的显示。
对于菜单而言,可以理解为一个二维数组。
例如:
vs编译器,最上层的就是菜单。
菜单里面的每一个元素都是一个菜单项。
菜单项包含两个最基本的要素:1.菜单项名字
2.菜单项唯一标识ID;
每一个菜单还可以是嵌套的子菜单数组;
wndWindowsProject2pszMenuName=MAKEINTRESOURCE(IDR_MENU1)
;
在注册窗口中,找到图中的代码,只需要在这里改变参数,也就是将菜单的标识ID输入进去,就可以完成窗口的加载,除了这里,还有一个地方就是:
这两处只需要一处填写就可以了.
HMENU hmenu=LoadMenu(Hinstance,MAKEINTRESOURCE(INR_MENU1));
HWND hWnd = CreateWindowW(szWindowClass, //窗口类名,注意,必须是已经注册的窗口类名;
szTitle, //窗口标题名;
WS_OVERLAPPEDWINDOW| WS_VSCROLL, // 窗口风格;
CW_USEDEFAULT, //窗口的坐标x
0, // 窗口的y坐标
CW_USEDEFAULT, //窗口的宽度
0, //窗口的高度
nullptr, //父窗口菜单句柄
hMenu, // 窗口菜单句柄,这里可以加载窗口;
hInstance, //当前实例句柄
nullptr); // 保留参数;
// 动态加载
//1.创建一个新菜单
HMENU hmenu = nullptr;
hmenu = CreateMenu();
//2.向菜单中添加选项;
AppendMenu(hmenu,/*在哪一个菜单中添加;*/ MF_POPUP, 1086, _T("新建(&N)"));
AppendMenu(hmenu,/*在哪一个菜单中添加;*/ MF_POPUP, 1087, _T("打开(&O)"));
HMENU hmenu3 = CreateMenu();
AppendMenu(hmenu3, MF_POPUP, 1088, _T("转到(&G)"));
AppendMenu(hmenu3, MF_POPUP, 1089, _T("替换(&F)"));
HMENU hmenu2 = CreateMenu();
AppendMenu(hmenu2, MF_POPUP, (UINT)hmenu, _T("文件(&F)"));
AppendMenu(hmenu2, MF_POPUP, (UINT)hmenu3, _T("编辑(&E)"));
如果要达到菜单响应,就在WM_COMMEND消息中响应;
case 1086:
MessageBox(hWnd, _T("快捷键Ctrl+N,新建文件"), _T("提示"), 0);
break;
case 1087:
MessageBox(hWnd, _T("快捷键Ctrl+O,打开文件"), _T("提示"), 0);
break;
case 1088:
MessageBox(hWnd, _T("快捷键Ctrl+E,转到文件"), _T("提示"), 0);
break;
case 1089:
MessageBox(hWnd, _T("快捷键Ctrl+F,查找文件"), _T("提示"), 0);
break;
我们在使用一个软件的时候会发现点击鼠标右键会出现一列菜单,而这个菜单是已经编辑好的,但是是动态显示的,在我们需要的时候就直接点击鼠标右键。而这种菜单也叫做快捷菜单。
1.在资源编辑器中编辑好新的右键菜单。
2.初始化加载,可以在WM_CREATEMENU内或者在主消息循环之前加载。
g_hRMenu=LoadMenu(hInstance,MAKEINTRESOURCE(IDR_MENU1))
3.在WM_RBUTTONDOWN内可以响应
POINT pt;
pt.x=LOWORD(LParam);
pt.y=LOWORD(LParam);
//把客户区坐标转为屏幕坐标;
ClientToScreen(hWnd,&pt);
//也可以直接使用GetCurSorPos(&pt);来获取鼠标的坐标;
HMENU tempMenu=GetSubMenu(g_hRMenu,1); //把g_hRMenu里面的0列表示的菜单绘制到tempMenu;
//弹出右键菜单
TrackPopupMenu(tempMenu,
TpM_LEFTALIGN,
pt.x,
pt.y,
0,
hWnd,
nullptr);
静态库是指我们的应用中,有一些公共代码是需要反复使用的,就把这些代码编译为库,理解为仓库,在仓库中存储了很多的东西,每次使用就只需要去仓库拿就可以了。
在创建项目时就选择创建静态库,然后再静态库中创建头文件,以及实现头文件函数的cpp文件,然后就可以了。最后将静态库的文件复制到新的项目中就可以使用了。
动态库又称动态链接库,英文“dll”,是“Dynamic Link Library”的缩写。
DLL是一个包含可有多个程序同时使用的代码和数据的库;
DLL不是可执行文件。
动态链接提供了一种方法,使进程可以调用不属于其可执行代码的函数。
函数的可执行代码位于一个DLL中,该DLL包含一个或多个已被编译,连接并使用他们的进程的函数。
windows下一般文件后缀为“.dll”,Linux下为“.so”后缀。
创建动态库和静态库相似。
1.静态库在程序的连接阶段被复制到了程序中,和程序运行的时候没有关系。
2.动态库再链接阶段没有被复制到程序中,而是在程序运行中由系统加载到内存中供使用。
1.代码装载速度快,执行速度比链接速度略快。
2.发布程序时不需要考录到计算机上是否还存在“.ib文件"
1.更加节省内存,减少页面交换。
2.dll文件和exe文件独立,只要输出接口不变(即名称,参数,返回值类型不变),DLL文件不会对exe文件造成任何影响,因而极大的提高了程序的可维护性,和课拓展性;
3.不同编程语言编写的程序只要按照函数调用约定就可以调用同一个DLL文件。
4.适用于大规模的软件开发,使开发过程独立,耦合度小,便于不同的开发者和组织之间进行开发和测试。
// WindowsProject2.cpp : 定义应用程序的入口点。
//
/*
1.入口函数;
2.窗口注册函数
3.窗口创建函数
4.显示窗口
5.更新窗口
6.主消息循环
7.入口函数返回;
*/
#include "framework.h"
#include "WindowsProject2.h"
#define MAX_LOADSTRING 100
// 全局变量:
HINSTANCE hInst; // 当前实例
WCHAR szTitle[MAX_LOADSTRING]; // 标题栏文本
WCHAR szWindowClass[MAX_LOADSTRING]; // 主窗口类名
// 此代码模块中包含的函数的前向声明:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance, //入口函数;
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: 在此处放置代码。
// 初始化全局字符串
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_WINDOWSPROJECT2, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// 执行应用程序初始化:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WINDOWSPROJECT2));
// MSG msg;
/* //窗口示例,如果需要就可以去掉;
if (MessageBox(0, _T("你是否要选择轰炸"), _T("提示"), MB_ABORTRETRYIGNORE) == IDABORT)
{
MessageBoxW(0, _T("对你要轰炸的对象操作"), _T("选择按钮"), 0);
}*/
//自己添加的消息提示
// 主消息循环:
//while (GetMessage(&msg, nullptr, 0, 0)) //当获得的消息为真时,就返回true;
//{
// if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) //判断是不是快捷键;
// {
// TranslateMessage(&msg);
// DispatchMessage(&msg);
// }
//}
MSG msg; //使用peekMessage()
ZeroMemory(&msg, sizeof(msg)); //初始化;
/*
VOID ZeroMemory(
PVOID 【目的地】, //填写零的块地址
DWORD 【长度】 //以块的大小(以字节为单位)填充零
);
*/
while (msg.message != WM_QUIT) //如果不是退出的消息,就执行消息循环;
{
if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) //只要鼠标移动,就执行; PM_NOEMOVE是不移动;
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) //判断是不是快捷键;
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
return (int) msg.wParam;
}
//
// 函数: MyRegisterClass()
//
// 目标: 注册窗口类。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex; //表示一个窗口类型的结构体变量;
wcex.cbSize = sizeof(WNDCLASSEX); //表示的是自身这个类型的大小;
wcex.style = CS_HREDRAW | CS_VREDRAW; //风格;
wcex.lpfnWndProc = WndProc; //**非常重要(窗口消息处理函数)
wcex.cbClsExtra = 0; //类的额外信息;
wcex.cbWndExtra = 0; //窗口的额外信息;
wcex.hInstance = hInstance; //当前实例句柄;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WINDOWSPROJECT2)); //图标,菜单栏图标;
wcex.hCursor = LoadCursor(0, nullptr); //光标;
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); // 背景,一般不需要改变;
wcex.lpszMenuName = MAKEINTRESOURCEW(IDR_MENU1); // 菜单;
wcex.lpszClassName = szWindowClass; // 窗口类名;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); //图标,窗口左上角的图标;
return RegisterClassExW(&wcex);
}
//
// 函数: InitInstance(HINSTANCE, int)
//
// 目标: 保存实例句柄并创建主窗口
//
// 注释:
//
// 在此函数中,我们在全局变量中保存实例句柄并
// 创建和显示主程序窗口。
//
//创建窗口函数;
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // 将实例句柄存储在全局变量中
//HMENU hMenu = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MENU1)); //从资源中加载窗口;
// 动态加载
//1.创建一个新菜单
HMENU hmenu = nullptr;
hmenu = CreateMenu();
//2.向菜单中添加选项;
AppendMenu(hmenu,/*在哪一个菜单中添加;*/ MF_POPUP, 1086, _T("新建(&N)"));
AppendMenu(hmenu,/*在哪一个菜单中添加;*/ MF_POPUP, 1087, _T("打开(&O)"));
HMENU hmenu3 = CreateMenu();
AppendMenu(hmenu3, MF_POPUP, 1088, _T("转到(&G)"));
AppendMenu(hmenu3, MF_POPUP, 1089, _T("替换(&F)"));
HMENU hmenu2 = CreateMenu();
AppendMenu(hmenu2, MF_POPUP, (UINT)hmenu, _T("文件(&F)"));
AppendMenu(hmenu2, MF_POPUP, (UINT)hmenu3, _T("编辑(&E)"));
HWND hWnd = CreateWindowW(szWindowClass, //窗口类名,注意,必须是已经注册的窗口类名;
szTitle, //窗口标题名;
WS_OVERLAPPEDWINDOW| WS_VSCROLL, // 窗口风格;
CW_USEDEFAULT, //窗口的坐标x
0, // 窗口的y坐标
CW_USEDEFAULT, //窗口的宽度
0, //窗口的高度
nullptr, //父窗口菜单句柄
hmenu2, // 窗口菜单句柄,这里可以加载窗口;
hInstance, //当前实例句柄
nullptr); // 保留参数;
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
//
// 函数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// 目标: 处理主窗口的消息。
//
// WM_COMMAND - 处理应用程序菜单
// WM_PAINT - 绘制主窗口
// WM_DESTROY - 发送退出消息并返回
//
//
HMENU g_Menu;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
{
g_Menu = LoadMenu(hInst, MAKEINTRESOURCE(IDR_MENU2));
}
break;
case WM_RBUTTONDOWN:
{
POINT pt;
/*pt.x = LOWORD(lParam);
pt.y = LOWORD(lParam);
ClientToScreen(hWnd, &pt);*/
GetCursorPos(&pt);
HMENU tempmenu = GetSubMenu(g_Menu, 0);
TrackPopupMenu(tempmenu, TPM_LEFTALIGN, pt.x, pt.y, 0, hWnd, nullptr);
}
break;
case WM_CHAR: //字符消息;
{
switch (wParam)
{
case VK_RETURN:
MessageBoxA(hWnd, "回车键", "提示", 0);
break;
case 'Z':
{
HDC hdc = GetDC(hWnd);
TextOutA(hdc, 30, 30, "快捷键Alt+X",8 );
ReleaseDC(hWnd, hdc);
}
break;
}
}
//case WM_ACTIVATE: //窗口激活;
//{
// switch (wParam)
// {
// case WA_CLICKACTIVE: //鼠标点击激活;
// {
// HDC hdc = GetDC(hWnd);
// static int j = 0;
// TextOutA(hdc, 0, j, "加油,未来可期", 7);
// j += 20;
// }
// break;
//case WA_ACTIVE: //通过鼠标以外的方式激活;
//{
// HDC hdc = GetDC(hWnd);
// static int j = 0;
// TextOutA(hdc, 30, j, "加油,未来可期", 7);
// j += 20;
//}
// break;
//case WA_INACTIVE: //停用;
//{
// MessageBoxA(hWnd, "停用", "提示", 0);
//}
//break;
/* }
}*/
//case WM_CREATE: //窗口创建;
// MessageBoxA(hWnd,"你是否要打开窗口"," 提示",0); //利用弹窗来显示窗口创建成功;
// break;
case WM_COMMAND: //菜单命令;
{
int wmId = LOWORD(wParam);
// 分析菜单选择:
switch (wmId)
{
break;
case 1086:
MessageBox(hWnd, _T("快捷键Ctrl+N,新建文件"), _T("提示"), 0);
break;
case 1087:
MessageBox(hWnd, _T("快捷键Ctrl+O,打开文件"), _T("提示"), 0);
break;
case 1088:
MessageBox(hWnd, _T("快捷键Ctrl+E,转到文件"), _T("提示"), 0);
break;
case 1089:
MessageBox(hWnd, _T("快捷键Ctrl+F,查找文件"), _T("提示"), 0);
break;
case ID_32774:
{
int i = 0;
HWND hwnd = FindWindowA(0, "我的Android手机"); //查找窗口;
for (i = 0; i < 10; i++)
{
PostMessage(hwnd, WM_PASTE, 0, 0);
PostMessage(hwnd, WM_KEYDOWN, VK_RETURN, 0);
}
MessageBox(hwnd,_T("消息轰炸开始"),_T("提示"),0);
}
case IDB_BITMAP1:
MessageBox(0, 0, 0, 0);
break;
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:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: 在此处添加使用 hdc 的任何绘图代码...
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
//MessageBoxA(hWnd, "你将会关闭窗口", "警告", MB_OKCANCEL); //弹窗显示;
PostQuitMessage(0);
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;
}
`win32的内容就更到这里了,下面就是mfc内容了,win32需要记的东西很多,需要花大量时间去熟悉,多去尝试就能够掌握。