CreateWindow("EDIT", ...);
. Вы можете использовать CreateWindowEx
, если хотите, но это не обязательно. Чтобы использовать его, вы также обычно хотите, чтобы ваше окно отвечало на WM_FOCUS
, вызывая SetFocus
, чтобы установить фокус на элементе управления редактированием. Как правило, вы также хотите ответить на WM_MOVE
(или это WM_SIZE
- я не помню), изменив размер элемента управления для редактирования, чтобы он соответствовал клиентской области родительского окна.
Конечно, вы также можете создать диалог (DialogBox
или DialogBoxEx
), содержащий элемент управления для редактирования. Это позволяет избежать необходимости вручную устанавливать фокус и т. Д.
Итак, вот простая демонстрационная программа. Это создает главное окно и заполняет его клиентскую область элементом управления редактирования. Он может открывать и сохранять файлы, выполнять вырезание / копирование / вставку данных в элементе управления и выбирать шрифт для отображения данных в элементе управления. У него есть таблица ускорителей, поэтому он знает об обычных сочетаниях клавиш для большинства из них (например, ctrl-x = cut, ctrl-c = copy, ctrl-v = paste).
Во-первых, основной исходный код:
// notepad.cpp
#include <windows.h>
#include "notepad.h"
#include <string.h>
#include <string>
#include <fstream>
#include <sstream>
HINSTANCE hInst;
HWND hwnd;
static const HMENU edit_id = HMENU(100);
static HWND hwndEdit;
void Invalidate(HWND window) {
RECT rect;
GetClientRect(window, &rect);
InvalidateRect(window, &rect, TRUE);
}
class file {
std::string filename;
char buffer[FILENAME_MAX];
void write_file() {
size_t size = SendMessage(hwndEdit, WM_GETTEXTLENGTH, 0, 0);
std::string buffer(size+1, '\0');
SendMessage(hwndEdit, WM_GETTEXT, size + 1, (LPARAM)&buffer[0]);
std::ofstream out(filename);
out.write(&buffer[0], size);
}
long long get_size(std::string const& filename) {
WIN32_FIND_DATA data;
auto h = FindFirstFile(filename.c_str(), &data);
long long size = data.nFileSizeHigh;
size <<= 32;
size |= data.nFileSizeLow;
return size;
}
void read_file() {
std::ifstream in(filename);
std::string buffer;
long long size = get_size(filename);
if (size > 1024 * 1024) {
MessageBox(hwnd, "File too large", "", MB_OK);
return;
}
buffer.resize(size+1);
in.read(&buffer[0], size);
std::string::size_type pos = 0;
unsigned count = 0;
while ((pos = buffer.find('\n', pos)) != std::string::npos) {
buffer.replace(pos, 1, "\r\n");
pos += 2;
++count;
}
SendMessage(hwndEdit, WM_SETTEXT, 0, (LPARAM)buffer.c_str());
}
public:
file() : buffer("\0\0") {}
bool open() {
if (SendMessage(hwndEdit, EM_GETMODIFY, 0, 0)) {
if (MessageBox(hwnd, "Open without saving current text?", "Buffer Modified", MB_OKCANCEL) == IDCANCEL)
return false;
}
OPENFILENAMEA spec{};
spec.lStructSize = sizeof(spec);
spec.hwndOwner = hwnd;
spec.lpstrFile = buffer;
spec.nMaxFile = sizeof(buffer);
spec.Flags = OFN_ENABLESIZING | OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_SHAREAWARE | OFN_FILEMUSTEXIST;
if (GetOpenFileName(&spec)) {
filename = spec.lpstrFile;
read_file();
return true;
}
return false;
}
bool save() {
if (filename.empty())
return save_as();
write_file();
SendMessage(hwndEdit, EM_SETMODIFY, 0, 0);
return true;
}
bool save_as() {
OPENFILENAMEA spec{};
spec.lStructSize = sizeof(spec);
spec.hwndOwner = hwnd;
spec.lpstrFile = buffer;
spec.nMaxFile = sizeof(buffer);
spec.Flags = OFN_OVERWRITEPROMPT | OFN_ENABLESIZING | OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_SHAREAWARE;
if (GetSaveFileName(&spec)) {
filename = spec.lpstrFile;
write_file();
SendMessage(hwndEdit, EM_SETMODIFY, 0, 0);
return true;
}
return false;
}
} file;
class font {
HFONT current;
LOGFONT log_font;
CHOOSEFONT spec;
bool choose() {
spec.lStructSize = sizeof(spec);
spec.hwndOwner = hwnd;
spec.lpLogFont = &log_font;
spec.Flags = CF_INITTOLOGFONTSTRUCT | CF_FORCEFONTEXIST | CF_SCREENFONTS;
return ChooseFont(&spec);
}
public:
font()
: current(NULL)
, log_font{}
, spec{}
{}
bool select() {
if (!choose())
return false;
current = CreateFontIndirect(&log_font);
SendMessage(hwndEdit, WM_SETFONT, *reinterpret_cast<WPARAM *>(¤t), TRUE);
return true;
}
} font;
LRESULT CALLBACK MainWndProc(HWND hwnd,
UINT message,
WPARAM wparam,
LPARAM lparam)
{
PAINTSTRUCT ps;
HDC dc;
RECT rect;
int i;
switch (message) {
case WM_PAINT:
dc = BeginPaint(hwnd, &ps);
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_CREATE:
hwndEdit = CreateWindowEx(
0,
"EDIT",
NULL,
WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN,
0, 0, 0, 0,
hwnd,
edit_id,
hInst,
NULL);
if (hwndEdit == nullptr)
return -1;
return 0;
case WM_SIZE: {
int width = LOWORD(lparam);
int height = HIWORD(lparam);
MoveWindow(hwndEdit, 0, 0, width, height, TRUE);
break;
}
case WM_SETFOCUS:
SetFocus(hwndEdit);
break;
case WM_COMMAND :
switch(LOWORD(wparam)) {
case ID_EXIT:
if (wparam == ID_EXIT)
PostMessage(hwnd, WM_DESTROY, 0, 0);
break;
case ID_FILE_OPEN:
if (file.open())
return 0;
break;
case ID_FILE_SAVE:
if (file.save())
return 0;
break;
case ID_FILE_SAVEAS:
if (file.save_as())
return 0;
break;
case ID_EDIT_UNDO:
if (SendMessage(hwndEdit, EM_CANUNDO, 0, 0))
SendMessage(hwndEdit, WM_UNDO, 0, 0);
return 0;
case ID_EDIT_SELECT_ALL:
SendMessage(hwndEdit, EM_SETSEL, 0, -1);
return 0;
case ID_EDIT_CUT:
SendMessage(hwndEdit, WM_CUT, 0, 0);
break;
case ID_EDIT_COPY:
SendMessage(hwndEdit, WM_COPY, 0, 0);
break;
case ID_EDIT_PASTE:
SendMessage(hwndEdit, WM_PASTE, 0, 0);
break;
case ID_VIEW_FONT:
return font.select();
default: {
return DefWindowProc(hwnd, message, wparam, lparam);
}
}
}
return DefWindowProc(hwnd, message, wparam, lparam);
}
BOOL Init(HINSTANCE hInstance, int nCmdShow)
{
WNDCLASSEX wc;
hInst = hInstance;
wc.cbSize = sizeof(WNDCLASSEX);
wc.hIconSm = (HICON)LoadImage(hInstance,
MAKEINTRESOURCE(IDI_APPICON),
IMAGE_ICON,
16, 16,
0);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPICON));
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = "MAINMENU";
wc.lpszClassName = title;
if (!RegisterClassEx(&wc))
return FALSE;
hwnd = CreateWindow(title,
title,
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
CW_USEDEFAULT, 0,
CW_USEDEFAULT, 0,
NULL,
NULL,
hInstance,
NULL);
if (!hwnd) {
return FALSE;
}
ShowWindow(hwnd, SW_SHOWNORMAL);
UpdateWindow(hwnd);
return TRUE;
}
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
HACCEL AccelTable;
if (!Init(hInstance, nCmdShow))
return FALSE;
AccelTable = LoadAccelerators(hInstance, "SHORTCUTS");
while (GetMessage(&msg, NULL, 0, 0))
if (!TranslateAccelerator(hwnd, AccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
Заголовок:
// notepad.h
#define ID_EXIT 100
#define ID_FILE_OPEN 101
#define ID_FILE_SAVE 102
#define ID_FILE_SAVEAS 103
#define ID_EDIT_CUT 201
#define ID_EDIT_COPY 202
#define ID_EDIT_PASTE 203
#define ID_EDIT_UNDO 204
#define ID_EDIT_FIND 211
#define ID_EDIT_FIND_NEXT 212
#define ID_EDIT_REPLACE 213
#define ID_EDIT_SELECT_ALL 214
#define ID_VIEW_WRAP 301
#define ID_VIEW_FONT 302
#define IDI_APPICON 400
static char title[] = "Minimum Window";
Примечание: заголовок включает определения для нескольких команд (find / find-next / replace), которые не реализованы в программе.
Тогда вам нужен файл ресурса в следующем порядке:
// notepad.rc
#include "notepad.h"
MAINMENU MENU
BEGIN
POPUP "&File"
BEGIN
MENUITEM "Open\tCtrl+O", ID_FILE_OPEN
MENUITEM "Save\tCtrl+S", ID_FILE_SAVE
MENUITEM "Save As", ID_FILE_SAVEAS
MENUITEM "E&xit", ID_EXIT
END
POPUP "&Edit"
BEGIN
MENUITEM "Undo\tCtrl+Z", ID_EDIT_UNDO
MENUITEM "Cut\tCtrl+X", ID_EDIT_CUT
MENUITEM "Copy\tCtrl+C", ID_EDIT_COPY
MENUITEM "Paste\tCtrl+V", ID_EDIT_PASTE
MENUITEM SEPARATOR
MENUITEM "Find...\tCtrl+F", ID_EDIT_FIND
MENUITEM "Find Next", ID_EDIT_FIND_NEXT
MENUITEM "Replace...\tCtrl+H", ID_EDIT_REPLACE
MENUITEM "Select All\tCtrl+A", ID_EDIT_SELECT_ALL
END
POPUP "Format"
BEGIN
MENUITEM "&Font", ID_VIEW_FONT
END
END
SHORTCUTS ACCELERATORS
BEGIN
"^O", ID_FILE_OPEN, ASCII
"^S", ID_FILE_SAVE, ASCII
"^A", ID_EDIT_SELECT_ALL, ASCII
"^Z", ID_EDIT_UNDO, ASCII
"^X", ID_EDIT_CUT, ASCII
"^C", ID_EDIT_COPY, ASCII
"^V", ID_EDIT_PASTE, ASCII
END
Хотя это и не обязательно, Makefile для его сборки пригодится:
notepad.exe: notepad.obj notepad.res
link notepad.obj user32.lib gdi32.lib comdlg32.lib notepad.res
notepad.res: notepad.rc
rc -r notepad.rc
notepad.obj: notepad.cpp
cl -c notepad.cpp
clean:
del *.res
del *.obj
Итак, если вы сохраните их в каталог, откроете командную строку для компилятора Microsoft и наберите nmake
в этом каталоге, он должен создать notepad.exe
, который будет слегка урезанной версией обычной Windows блокнот. В нем отсутствует поиск / замена, печать и пара других вещей, но, по крайней мере, этого достаточно, чтобы дать достойную отправную точку для создания и использования элемента управления для редактирования.
О - еще одна нота. В основном это быстро взламывается из кусочков старого кода, с небольшим количеством новой клейкой ленты (так сказать), чтобы связать их вместе. Это ни в коем случае не является примером наилучшей возможной практики кодирования во всем (мягко говоря).