我发现标准 Windowsedit
控件的工作方式有些奇怪。
当自动换行打开时,它接受整个逻辑行,但根据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.