一个仿照windows系统的记事本(vs2022),顺便问个问题,怎么实现这个剪切功能?
#include <Windows.h>
#include <CommCtrl.h>
#include <fstream>
#include<string>
#include<vector>
#pragma comment(lib, "comctl32.lib")
static HWND hEdit;
static LOGFONT lf = { 0 };
#define CHAR_PER_LINE 1000
HFONT printt;
// 窗口类名和菜单ID
const CHAR g_szClassName[] = "MyNotepadWndClass";
const int IDM_FILE_OPEN = 1001;
const int IDM_FILE_SAVE = 1002;
const int IDM_FILE_EXIT = 1003;
const int IDM_FORMAT_FONT = 2001;
const int IDM_FORMAT_SIZE = 2002;
#define IDM_FILE_PRINT 2345
#define IDM_EDIT_COPY 23456
#define IDM_EDIT_CUT 986
#define IDM_EDIT_PASTE 5678
const int IDM_HELP_ABOUT = 9903;
// 控件ID
void SetAppAsDefaultForFileExtension(const char* fileExtension, const char* appName, const char* appPath) {
// 创建注册表键值
HKEY hKey = NULL;
if (RegCreateKeyExA(HKEY_CURRENT_USER, "SOFTWARE\\Classes", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL) == ERROR_SUCCESS)
{
// 设置文件扩展名关联
HKEY hExtKey = NULL;
if (RegCreateKeyExA(hKey, fileExtension, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hExtKey, NULL) == ERROR_SUCCESS)
{
RegSetValueExA(hExtKey, NULL, 0, REG_SZ, (const BYTE*)appName, strlen(appName) + 1);
RegCloseKey(hExtKey);
}
// 设置应用程序关联
HKEY hAppKey = NULL;
if (RegCreateKeyExA(hKey, appName, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hAppKey, NULL) == ERROR_SUCCESS)
{
HKEY hCommandKey = NULL;
if (RegCreateKeyExA(hAppKey, "shell\\open\\command", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hCommandKey, NULL) == ERROR_SUCCESS)
{
std::string command = appPath;
command.append(" \"%1\"");
RegSetValueExA(hCommandKey, NULL, 0, REG_SZ, (const BYTE*)command.c_str(), command.length() + 1);
RegCloseKey(hCommandKey);
}
RegCloseKey(hAppKey);
}
RegCloseKey(hKey);
}
}
const int IDC_EDIT = 100;
WINUSERAPI int WINAPI Edit_GetText(_In_ HWND hWnd, _Out_writes_to_(cchTextMax, return) LPSTR lpchText, _In_ int cchTextMax);
WINUSERAPI BOOL WINAPI Edit_SetSel(_In_ HWND hWnd, _In_ int nStartChar, _In_ int nEndChar);
void DoFilePrint(HWND hwnd, HFONT font) {
HDC hdc = GetDC(hwnd);
DOCINFO di = { sizeof(DOCINFO), "Print Job" };
if (StartDoc(hdc, &di) > 0) {
TEXTMETRIC tm;
GetTextMetrics(hdc, &tm);
int lineHeight = tm.tmHeight + tm.tmExternalLeading;
int pageCount = 0;
// 获取编辑框的文本
int textLength = GetWindowTextLength(hwnd);
char* buffer = new char[textLength + 1];
GetWindowText(hwnd, buffer, textLength + 1);
RECT rect;
GetClientRect(hwnd, &rect);
int y = 0;
// 分页打印
for (int i = 0; i < textLength; i += rect.bottom / lineHeight) {
int remainingChars = textLength - i;
int charsToPrint = min(rect.bottom / lineHeight, remainingChars);
// 创建一页的打印页面
HDC printHdc = CreateCompatibleDC(hdc);
HBITMAP printBmp = CreateCompatibleBitmap(hdc, rect.right, rect.bottom);
SelectObject(printHdc, printBmp);
SelectObject(printHdc, font);
// 设置打印页面的背景色和文本颜色
SetBkColor(printHdc, GetSysColor(COLOR_WINDOW));
SetTextColor(printHdc, GetSysColor(COLOR_WINDOWTEXT));
// 打印文本
RECT printRect = { 0, 0, rect.right, lineHeight };
DrawText(printHdc, buffer + i, charsToPrint, &printRect, DT_LEFT);
// 打印页面
BitBlt(hdc, 0, y, rect.right, rect.bottom, printHdc, 0, 0, SRCCOPY);
// 清除打印页面资源
DeleteDC(printHdc);
DeleteObject(printBmp);
y += rect.bottom;
pageCount++;
}
// 结束打印任务
EndDoc(hdc);
delete[] buffer;
}
ReleaseDC(hwnd, hdc);
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static OPENFILENAME ofn;
static char szFileName[MAX_PATH] = "";
static CHOOSEFONT cf;
switch (msg)
{
case WM_CREATE:
{
// 创建编辑框控件
hEdit = CreateWindowEx(
0,
"EDIT",
"",
WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL,
0, 0, 0, 0,
hwnd,
(HMENU)IDC_EDIT,
GetModuleHandle(NULL),
NULL
);
// 创建菜单
HMENU hMenu, hSubMenu;
hMenu = CreateMenu();
hSubMenu = CreatePopupMenu();
AppendMenu(hSubMenu, MF_STRING, IDM_FILE_OPEN, "打开(&O)");
AppendMenu(hSubMenu, MF_STRING, IDM_FILE_SAVE, "保存(&S)");
AppendMenu(hSubMenu, MF_STRING, IDM_FILE_PRINT, "打印(&P)");
AppendMenu(hSubMenu, MF_SEPARATOR, 0, NULL);
AppendMenu(hSubMenu, MF_STRING, IDM_FILE_EXIT, "退出(&X)");
AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hSubMenu, "文件(&F)");
// 增加格式菜单
hSubMenu = CreatePopupMenu();
AppendMenu(hSubMenu, MF_STRING, IDM_FORMAT_FONT, "字体(&F)");
AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hSubMenu, "格式(&O)");
hSubMenu = CreatePopupMenu();
AppendMenu(hSubMenu, MF_STRING, IDM_EDIT_COPY, "复制");
AppendMenu(hSubMenu, MF_STRING, IDM_EDIT_CUT, "剪切(暂时不可使用)");
AppendMenu(hSubMenu, MF_STRING, IDM_EDIT_PASTE, "粘贴");
AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hSubMenu, "编辑");
hSubMenu = CreatePopupMenu();
AppendMenu(hSubMenu, MF_STRING, IDM_HELP_ABOUT, "关于");
AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hSubMenu, "帮助");
SetMenu(hwnd, hMenu);
// 初始化打开文件对话框
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hwnd;
ofn.lpstrFilter = "文本文件(*.txt)\0*.txt\0所有文件(*.*)\0*.*\0";
ofn.lpstrFile = szFileName;
ofn.nMaxFile = MAX_PATH;
ofn.lpstrDefExt = "txt";
// 初始化字体选择对话框
ZeroMemory(&cf, sizeof(cf));
cf.lStructSize = sizeof(cf);
cf.hwndOwner = hwnd;
cf.lpLogFont = &lf;
cf.Flags = CF_SCREENFONTS | CF_EFFECTS;
INITCOMMONCONTROLSEX ic;
ic.dwSize = sizeof(ic);
ic.dwICC = ICC_STANDARD_CLASSES;
InitCommonControlsEx(&ic);
break;
}
case WM_SIZE:
{
// 调整编辑框尺寸
RECT rcClient;
GetClientRect(hwnd, &rcClient);
SetWindowPos(hEdit, NULL, 0, 0, rcClient.right, rcClient.bottom, SWP_NOZORDER);
break;
}
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
// 处理打开文件命令
case IDM_FILE_OPEN:
{
// 打开文件
if (GetOpenFileName(&ofn) == TRUE)
{
std::ifstream file(ofn.lpstrFile, std::ios::binary);
if (file.is_open())
{
// 清空编辑框内容
SendMessage(hEdit, WM_SETTEXT, 0, (LPARAM)L"");
// 获取文件大小
file.seekg(0, std::ios::end);
std::streamsize fileSize = file.tellg();
file.seekg(0, std::ios::beg);
// 分配内存存储文件内容
std::vector<char> buffer(fileSize);
file.read(buffer.data(), fileSize);
// 关闭文件
file.close();
// 转换编码并显示文本
int requiredSize = MultiByteToWideChar(CP_UTF8, 0, buffer.data(), fileSize, nullptr, 0);
std::wstring text(requiredSize, L'\0');
MultiByteToWideChar(CP_UTF8, 0, buffer.data(), fileSize, &text[0], requiredSize);
SetWindowTextW(hEdit, text.c_str());
}
}
break;
}
// 处理保存文件命令
// 处理保存文件命令
case IDM_FILE_SAVE:
{
if (GetSaveFileName(&ofn) == TRUE)
{
std::ofstream file(ofn.lpstrFile);
if (file.is_open())
{
// 将编辑框中的文本保存到文件
int nLength = GetWindowTextLength(hEdit);
char* pBuffer = new char[nLength + 1];
memset(pBuffer, 0, nLength + 1);
GetWindowText(hEdit, pBuffer, nLength + 1);
file << pBuffer;
file.close();
delete[] pBuffer;
}
}
break;
}
case IDM_HELP_ABOUT: {
MessageBox(hwnd, "记事本实验版1.3.3\n李想制作\n详情请见官网:\nwww.lixiangnotepad.com", "记事本实验版", MB_OK | MB_ICONINFORMATION);
break;
}
// 处理退出命令
case IDM_FILE_EXIT:
DestroyWindow(hwnd);
break;
// 处理字体命令
// 处理字号命令
case IDM_FORMAT_FONT:
{
CHOOSEFONT cfSize;
LOGFONT lfSize = { 0 };
ZeroMemory(&cfSize, sizeof(cfSize));
cfSize.lStructSize = sizeof(cfSize);
cfSize.hwndOwner = hwnd;
cfSize.lpLogFont = &lfSize;
cfSize.Flags = CF_SCREENFONTS | CF_EFFECTS | CF_INITTOLOGFONTSTRUCT;
cfSize.nSizeMin = 8;
cfSize.nSizeMax = 72;
if (ChooseFont(&cfSize) == TRUE)
{
// 设置编辑框字号
int nFontSize; // 存储字体大小
// 获取字体大小
HFONT hFont = CreateFontIndirect(&lfSize);
printt = hFont;
SendMessage(hEdit, WM_SETFONT, (WPARAM)hFont, TRUE);
}
break;
}
case IDM_EDIT_PASTE:
SendMessage(hEdit, WM_PASTE, 0, 0);
break;
case IDM_EDIT_COPY: {
SendMessage(hEdit, WM_COPY, 0, 0);
break;
}
case IDM_FILE_PRINT: {
DoFilePrint(hwnd, printt);
break;
}
}
break;
}
// 处理窗口关闭事件
case WM_CLOSE:
DestroyWindow(hwnd);
break;
// 处理窗口销毁事件
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
// 1. 注册窗口类
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if (!RegisterClassEx(&wc))
{
MessageBox(NULL, "窗口类注册失败!", "Error", MB_ICONERROR);
return 0;
}
const char* appName = "MyNotepad";
const char* appPath = "C:\\Path\\To\\Your\\Program.exe";
// 设置默认打开TXT文件的程序
SetAppAsDefaultForFileExtension(".txt", appName, appPath);
// 2. 创建窗口
HWND hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
"My Notepad",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 640, 480,
NULL, NULL, hInstance, NULL
);
if (hwnd == NULL)
{
MessageBox(NULL, "窗口创建失败!", "Error", MB_ICONERROR);
return 0;
}
// 3. 显示窗口
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
// 4. 消息循环
MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}