2

我发现标准 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.
4

0 回答 0