Я обнаружил некоторую странность в том, как работает стандартный элемент управления Windows edit
.
Когда включена перенос слов, он принимает целые логические строки, но возвращает строки экрана по запросу EM_GETLINE
. Тем не менее, он корректно работает при изменении размера окна и заново разделяет текст относительно исходных CR-LF.
Итак, моя идея выяснить исходные логические строки состояла в том, чтобы запросить строки экрана с помощью EM_GETLINE
, одну за другой, и обнаружить CR-LF в конце последней строки экрана в блоке.
К сожалению, строки, запрошенные EM_GETLINE
, вообще не содержат CR-LF.
Кажется, что элемент управления хранит CR-LF внутри, но не возвращает их на EM_GETLINE
. Их можно получить только при запросе всего контрольного текста с помощью WM_GETTEXT
.
Возможно, существует какой-то другой способ запрашивать фрагменты текста между смежными CR-LF, кроме как получить весь текст и разбить его?
program WindowsEditControl;
uses
Winapi.Windows, Winapi.Messages, System.SysUtils;
const
IDM_EXIT = 100;
GAP = 10;
var
hEdit: HWND;
hFnt: HFONT;
function GetLine(hEdit: HWND; Index: Integer): string;
var
Text: array[0..4095] of Char;
begin
Word((@Text)^) := Length(Text);
SetString(Result, Text, SendMessage(hEdit, EM_GETLINE, Index, LPARAM(@Text)));
end;
function GetTxt(hEdit: HWND): string;
var
Len: Integer;
begin
Len := SendMessage(hEdit, WM_GETTEXTLENGTH, 0, 0);
SetString(Result, PChar(nil), Len);
if Len <> 0 then
begin
Len := Len - SendMessage(hEdit, WM_GETTEXT, Len + 1, LongWord(PChar(Result)));
if Len > 0 then
SetLength(Result, Length(Result) - Len);
end;
end;
function WndFunc(h: HWND; iMessage: UINT; w: WPARAM; l: LPARAM): LRESULT; stdcall;
var
nWidth, nHeight: NativeUInt;
i, j, lineLength: Integer;
s: string;
begin
case iMessage of
WM_CREATE: begin
hEdit := CreateWindowEx(WS_EX_NOPARENTNOTIFY, 'edit', 'Control #1',
WS_BORDER or WS_VISIBLE or WS_CHILD or ES_LEFT or ES_MULTILINE or ES_READONLY or WS_VSCROLL, GAP, GAP,
810 - GAP*2 - 15, 260, h, 0, hInstance, nil);
hFnt := CreateFont(20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'Calibri');
SendMessage(h, WM_SETFONT, hFnt, MakeLong(1, 0));
SendMessage(hEdit, WM_SETFONT, hFnt, MakeLong(1, 0));
for i := 0 to 10 do begin
for j := 0 to 20 do s := s + 'Item' + IntToStr(i) + '.' + IntToStr(j) + ' ';
s := s + #13#10;
end;
SendMessage(hEdit, WM_SETTEXT, 0, LongWord(PWideChar(s)));
//Attempts to query the edit control:
//This gets the first SCREEN line of the edit control. CR-LFs aren't there.
MessageBox(h, PWideChar('|'+GetLine(hEdit, 0)+'|'), 'Screen line 1', 0);
//This gets the second SCREEN line of the edit control. CR-LFs aren't there.
MessageBox(h, PWideChar('|'+GetLine(hEdit, 1)+'|'), 'Screen line 2', 0);
//In a whole text are all the CR-LFs there
MessageBox(h, PWideChar(GetTxt(hEdit)), 'Whole text', 0);
end;
WM_DESTROY: begin
DeleteObject(hFnt);
PostQuitMessage(0);
Result := 0;
end;
WM_SIZE: begin
nWidth := LOWORD(l);
nHeight := HIWORD(l);
SetWindowPos(hEdit, 0, GAP, GAP, nWidth - GAP*2, nHeight - GAP*2, 0);
Result := 0;
end;
WM_COMMAND: if w = IDM_EXIT then PostMessage(h, WM_CLOSE, 0, 0);
else
Result := DefWindowProc(h, iMessage, w, l);
end;
end;
var
wndClass: TWndClass;
h: HWND;
msg: TMsg;
begin
wndClass.style := CS_HREDRAW or CS_VREDRAW;
wndClass.lpfnWndProc := @WndFunc;
wndClass.cbClsExtra := 0;
wndClass.cbWndExtra := 0;
wndClass.hInstance := hInstance;
wndClass.hIcon := 0;
wndClass.hCursor := LoadCursor(0, IDC_ARROW);
wndClass.hbrBackground := GetStockObject(WHITE_BRUSH);
wndClass.lpszMenuName := nil;
wndClass.lpszClassName := 'EditTest';
if RegisterClass(wndClass) = 0 then Halt(0);
h := CreateWindow(wndClass.lpszClassName, 'Edit Test', WS_OVERLAPPEDWINDOW, 35, 35, 810, 320, 0, 0, hInstance, nil);
ShowWindow(h, SW_SHOW);
while GetMessage(msg, 0, 0, 0) do begin
TranslateMessage(msg);
DispatchMessage(msg);
end;
Halt(msg.wParam);
end.