菜单及库(Num28)
目录
一、菜单的分类:
菜单项:
二、静态菜单:
代码示例:
三、动态菜单:
快捷键创建:
Accelerator:直接修改
编辑
Menu:
代码示例:
注意:
四、快捷菜单:
右键弹出菜单:
代码示例:
五、静态库与动态库:
1.静态库:
优点:
缺点:
2.动态库:
优点:
缺点:
区别:
使用文件:
六、静态:
创建:
运行报错(静态库不能被执行):
编辑
代码示例:
头文件:
同名.cpp文件:
控制台应用源文件:
七、动态:
代码示例:
头文件:
同名.cpp文件:
控制台应用源文件:
一、菜单的分类:
从编程的角度来进行分类:
- 静态菜单:在菜单资源编辑器预先编辑好
- 动态菜单:在程序运行的过程中通过代码生成
- 快捷菜单:是前两种菜单的组合,在菜单资源编辑器中预先编辑好,然后在程序运行的过程中动态显示
菜单项:
菜单里面的每一个元素都是一个菜单项菜单项包含两个最基本的要素:
- 菜单项名字
- 该菜单项唯一的标识ID
每一个菜单项还可以是嵌套的子菜单数组
二、静态菜单:
代码示例:
wcex.lpszMenuName = NULL;//给空没有菜单BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{hInst = hInstance; // 将实例句柄存储在全局变量中HMENU mune = LoadMenu(hInst, MAKEINTRESOURCE(IDR_MENU1));//倒数第三个参也是加菜单HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,400,300, CW_USEDEFAULT, 0, nullptr,mune, hInstance, nullptr);if (!hWnd){return FALSE;}ShowWindow(hWnd, nCmdShow);UpdateWindow(hWnd);return TRUE;
}//静态菜单:在资源当中创建菜单,将菜单项和弹出菜单都写好,在WM_COMMAND消息当中去进行响应菜单项的点击case WM_COMMAND:{int wmId = LOWORD(wParam);// 分析菜单选择:switch (wmId){case ID_9_10:DestroyWindow(hWnd);break;case ID_32771://响应这个id对应的菜单项DestroyWindow(hWnd);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;
三、动态菜单:
快捷键创建:
Accelerator:直接修改
Menu:
代码示例:
#include "framework.h"
#include "Class_LING_04_1.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_CLASSLING041, szWindowClass, MAX_LOADSTRING);MyRegisterClass(hInstance);// 执行应用程序初始化:if (!InitInstance (hInstance, nCmdShow)){return FALSE;}HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_CLASSLING041));MSG msg;// 主消息循环:while (GetMessage(&msg, nullptr, 0, 0)){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_CLASSLING041));wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);wcex.lpszMenuName = NULL;//给空没有菜单wcex.lpszClassName = szWindowClass;wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));return RegisterClassExW(&wcex);
}//
// 函数: InitInstance(HINSTANCE, int)
//
// 目标: 保存实例句柄并创建主窗口
//
// 注释:
//
// 在此函数中,我们在全局变量中保存实例句柄并
// 创建和显示主程序窗口。
//
HMENU hMenu2;
HMENU popMenu;
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{hInst = hInstance; // 将实例句柄存储在全局变量中//HMENU mune = LoadMenu(hInst, MAKEINTRESOURCE(IDR_MENU1));HMENU hMenu1 = CreateMenu();//创建一个空菜单//尾部添加AppendMenu(hMenu1,//添加到哪个菜单0, //菜单风格1001,//菜单项的id,唯一id_T("打开(&K)\tALT+K"));AppendMenu(hMenu1, 0, 1002, _T("关闭"));InsertMenu(hMenu1, 0, MF_BYPOSITION, 1003, _T("新"));popMenu = CreateMenu();AppendMenu(popMenu, MF_POPUP,(UINT_PTR) hMenu1,_T("工具1"));AppendMenu(popMenu, MF_POPUP,(UINT_PTR) hMenu1,_T("工具2"));AppendMenu(popMenu, MF_POPUP,(UINT_PTR) hMenu1,_T("工具3"));hMenu2 = CreateMenu();AppendMenu(hMenu2, 0, 1004, _T("关闭1"));AppendMenu(hMenu2, 0, 1005, _T("关闭2"));AppendMenu(hMenu2, 0, 1006, _T("关闭3"));AppendMenu(hMenu2, 0, 1007, _T("关闭4"));AppendMenu(hMenu1, MF_POPUP, (UINT_PTR)hMenu2, _T("工具3"));EnableMenuItem(hMenu2, 1002, MF_GRAYED);//禁用,显示灰色EnableMenuItem(hMenu2, 1002, MF_ENABLED);//启用,回复原色EnableMenuItem(hMenu2,0, MF_GRAYED|MF_BYPOSITION);//禁用,第二个参数变为位置DeleteMenu(hMenu2,3,MF_BYPOSITION);//删除//倒数第三个参也是加菜单HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,400,300, CW_USEDEFAULT, 0, nullptr, popMenu, hInstance, nullptr);if (!hWnd){return FALSE;}ShowWindow(hWnd, nCmdShow);UpdateWindow(hWnd);return TRUE;
}//
// 函数: 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_LBUTTONDOWN:{AppendMenu(hMenu2, 0, 1007, _T("关闭N"));AppendMenu(popMenu, MF_POPUP, (UINT_PTR)hMenu2, _T("工具N"));SetMenu(hWnd, popMenu);//在主页面添加要加上SetMenu()才能主动添加,因为它不会自动更新}break;//静态菜单:在资源当中创建菜单,将菜单项和弹出菜单都写好,在WM_COMMAND消息当中去进行响应菜单项的点击case WM_COMMAND:{int wmId = LOWORD(wParam);// 分析菜单选择:switch (wmId){case 1001:MessageBox(0, _T("1001"), 0, 0);break;case 1002:DestroyWindow(hWnd);break;case ID_9_10:DestroyWindow(hWnd);break;case ID_32771://响应这个id对应的菜单项DestroyWindow(hWnd);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: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;
}
注意:
###1 对一个菜单重复操作不好,id重复也不好
###2 把一个东西插入到另一个东西中时,再调用插入的东西有可能不能用了
四、快捷菜单:
右键弹出菜单:
- 在资源编辑器中编辑好新的右键菜单
- 初始化加载,可以在WMCREATE内或者在主消息循环之前加载。 g_hRMemu=LoadMenu(hlnst, MAKEINTRESOURCE(IDR_MENU1));
- 在WM_RBUTTONDOWN内可以响应
代码示例:
case WM_CREATE://加载菜单h = LoadMenu(hInst, MAKEINTRESOURCE(IDR_MENU1));break;case WM_RBUTTONDOWN:{POINT pos;//GetCursorPos(&pos);//鼠标相对于桌面的坐标//获得的是相对于窗口的坐标pos.x = LOWORD(lParam);pos.y = HIWORD(lParam);ClientToScreen(hWnd, &pos);//把客户区坐标转换为屏幕坐标HMENU poppMenu = GetSubMenu(h, 0);//获取子级菜单TrackPopupMenu(popMenu,TPM_LEFTALIGN | TPM_TOPALIGN,//风格,对齐方式pos.x, pos.y,//弹出坐标0,hWnd, NULL);}break;
五、静态库与动态库:
1.静态库:
- 库是指我们的应用中,有一些公共代码是需要反复使用,就把这些代码编译为“库”,理解为“仓库”,在“仓库”中存储了很多东西,每次要使用时只需要去“仓库”拿就可以了
- 程序有“预处理”->“编译”->“链接”这几个步骤
- 静态库就不需要再次编译,只需要在“链接”步骤中,链接器将从“仓库”的文件中取得所需的代码,复制到生成的可执行文件中即可
优点:
代码装载速度快,执行速度略比动态链接库快
发布程序时不需考虑在用户的计算机上.lib文件是否存在以及版本问题
缺点:
使用静态链接生成的可执行文件体积较大,包含相同的公共代码,造成浪费
2.动态库:
动态库又称动态链接库。英文“dll”,是“Dynamic LinkLibrary”的缩写形式
DLL是一个包含可由多个程序同时使用的代码和数据的库
DLL不是可执行文件
动态链接提供了一种方法,使进程可以调用不属于自身应用程序的可执行代码(库函数)
函数的可执行代码位于一个DLL中,该DLL包含一个或多个已被编译好的函数、通过动态加载就能链接进应用程序中去执行
DLL还有助于共享数据和资源
多个应用程序可同时访问内存中单个DLL副本的内容
windows下动态库为.dll后缀。linux下为.so后缀
优点:
更加节省内存并减少页面交换
dll文件和exe文件独立,只要输出接口不变(即名称、参数、返回值类型和调用约定不变),更换dll文件不会对exe文件造成任何影响,因而极大地提高了可维护性和可扩展性
缺点:
- 使用动态链接库的应用程序不是自完备的,它依赖的DLL模块也要存在,如果使用载入时动态链接,程序启动时发现DLL不存在,系统将终止程序并给出错误信息
- 而使用运行时动态链接,系统不会终止,但由于DLL中的导出函数不可用,程序会加载失败;速度比静态链接慢
- 当某个模块更新后,如果新模块与旧的模块不兼容,那么那些需要该模块才能运行的软件,只能淘汰掉(早期Windows中很常见)
区别:
静态库在程序的链接阶段被复制到了程序中,和程序运行的时候没有关系
动态库在链接阶段没有被复制到程序中,而是程序在运行时由系统动态加载到内存中供程序调用
不同编程语言编写的程序只要按照函数调用约定,就可以调用同一个dll函数
适用于大规模的软件开发,使开发过程独立、耦合度小,便于不同开发者和开发组织之间进行开发和测试
使用文件:
- .h文件:编译时必须的,声明函数接口用
- .lib文件:链接时需要的,当我们在程序中引用了一个.h文件里面的函数,链接器怎么知道要调用哪个dll文件呢,这就是lib文件的作用。它告诉链接器调用的函数在哪个dll中,函数执行代码在dll中的什么位置。如果是生成静态库文件,没有dll文件,这个时候函数的可执行代码部分也在lib文件中。所以在链接时就能直接链接进exe文件
- .dll文件:运行时需要的,函数的可执行代码,静态库只用到前两种,动态库用到了所有的三种
六、静态:
创建:
运行报错(静态库不能被执行):
- 同名.cpp文件写完后,debug换成Release重新“生成”一下
- 创建一个控制应用:
- 将Release中生成的.lib文件和项目中的头文件一起复制到新建成的控制台应用中
- 新建项中右键头文件添加现有项,将静态库中的头文件添加进来
代码示例:
头文件:
#pragma once#ifndef __MYTOOL_H__
#define __MYTOOL_H__extern "C" int myfun1(int x, int y);
extern "C" int myfun2(int x, int y);#endif // !__MYTOOL_H__
同名.cpp文件:
#include "pch.h"
#include "mytool.h"int myfun1(int x, int y)
{return x+y;
}int myfun2(int x, int y)
{return x-y;
}
控制台应用源文件:
// ConsoleApplication2.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//#include <iostream>
using namespace std;
#include"mytool.h"
#pragma comment(lib,"Class_LING_04_2.lib")int main()
{cout << myfun1(1, 1) << endl;cout << myfun2(4, 2) << endl;getchar();
}
七、动态:
- 同上,外加一个把.dll文件也一同复制过来,以下是运行结果:
- 当仅剩下.exe文件时,则不能够直接运行:
- 这是因为缺少动态库.dll文件所导致的
- 如果现在功能变了,改动同名.cpp文件生成dll方案即可改变输出的内容
代码示例:
头文件:
#pragma once#ifndef __MYDLL_H__
#define __MYDLL_H__extern "C" _declspec(dllexport)void fun(int x, int y);#endif // !__MYDLL_H__
同名.cpp文件:
#include"pch.h"
#include"MyTool.h"
#include<stdio.h>void fun(int x, int y)
{for (int i = 0; i < x; i++){for (int j = 0; j < y; j++){printf(" *");}printf("\n");}printf("\n");
}
控制台应用源文件:
// ConsoleApplication2.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//#include <iostream>
using namespace std;
#include"MyTool.h"
#pragma comment(lib,"Class_LING_04_3.lib")int main()
{/* cout << myfun1(1, 1) << endl;cout << myfun2(4, 2) << endl;*/fun(10, 10);getchar();
}
- ###让新生成的.dll文件对旧的.dll文件进行覆盖