Home > Net >  FMX TMemo and BeginUpdate
FMX TMemo and BeginUpdate

Time:10-04

How do I prevent a FMX TMemo from updating while loading data into it? Memo1.Lines.BeginUpdate doesn't seems to be the answer.

Code to reproduce:

Create a new FMX application Place a TMemo on the form Add a OnDoubleClickEvent to it and then the following code:

procedure TForm2.Memo1DblClick(Sender: TObject);
var
  i: Integer;
const
  Line = '1234567890_1234567890_1234567890_1234567890_1234567890_1234567890';
begin
  Memo1.Lines.Clear;
  Memo1.ControlType := TControlType.Platform;
  Memo1.Lines.BeginUpdate;
  for i := 1 to 1000 do
    Memo1.Lines.Add(Line);
  Memo1.Lines.EndUpdate;
end;

While running the program you'll see the Memo gets updated while adding data despite the call to BeginUpdate / EndUpdate

CodePudding user response:

The easiest way is to not update the memo directly, but via another object, like a TStringList:

procedure TForm2.Memo1DblClick(Sender: TObject);
var
  i: Integer;
  sl: TStrings;
const
  Line = '1234567890_1234567890_1234567890_1234567890_1234567890_1234567890';
begin
  Memo1.ControlType := TControlType.Platform;
  sl:=TStringList.Create;
  try
    for i := 1 to 1000 do
      sl.Add(Line);
    ..either..
    Memo1.Lines.Clear;
    Memo1.Lines.AddStrings(sl);
    ..or..
    Memo1.Lines.Text:=s1.Text;
  finally
    sl.free
  end
end;

An alternative (WINDOWS ONLY) is to disable screen updates while adding:

Uses WinAPI.Windows, WinAPI.Messages, FMX.Platform.Win;

procedure TForm2.Memo1DblClick(Sender: TObject);
var
  i: Integer;
const
  Line = '1234567890_1234567890_1234567890_1234567890_1234567890_1234567890';
begin
  Memo1.Lines.Clear;
  Memo1.ControlType := TControlType.Platform;
  PostMessage(FmxHandleToHWND(Handle),WM_SETREDRAW,0,0);
  try
    for i := 1 to 1000 do
      Memo1.Lines.Add(Line);
  finally
    PostMessage(FmxHandleToHWND(Handle),WM_SETREDRAW,1,0);
    Memo1.Invalidate // May be unnecessary //
  end;
end;

This will disable all screen updates to the form while updating. I believe it will also disable the Memo1 screen updates as well. Unfortuntely, FMX objects are not Windows objects, so you cannot disable screen updates directly for the Memo itself.

You can implement the LockDrawing/UnlockDrawing on the TForm level by including this CLASS HELPER:

{$IFDEF MSWINDOWS }
  Uses WinAPI.Windows, WinAPI.Messages, FMX.Platform.Win;
{$ENDIF }

TYPE
  TFormHelper   = CLASS HELPER FOR TForm
                    PROCEDURE   LockDrawing;
                    PROCEDURE   UnlockDrawing;
                  END;

{ TFormHelper }

PROCEDURE TFormHelper.LockDrawing;
  BEGIN
    {$IFDEF MSWINDOWS }
      PostMessage(FmxHandleToHWND(Handle),WM_SETREDRAW,0,0);
    {$ENDIF }
  END;

PROCEDURE TFormHelper.UnlockDrawing;
  BEGIN
    {$IFDEF MSWINDOWS }
      PostMessage(FmxHandleToHWND(Handle),WM_SETREDRAW,1,0);
      RedrawWindow(FmxHandleToHWND(Handle),NIL,0,RDW_ERASE OR RDW_FRAME OR RDW_INVALIDATE OR RDW_ALLCHILDREN)
    {$ENDIF }
  END;

That would make your event handler look like this:

procedure TForm2.Memo1DblClick(Sender: TObject);
var
  i: Integer;
const
  Line = '1234567890_1234567890_1234567890_1234567890_1234567890_1234567890';
begin
  Memo1.Lines.Clear;
  Memo1.ControlType := TControlType.Platform;
  LockDrawing;
  try
    for i := 1 to 1000 do
      Memo1.Lines.Add(Line);
  finally
    UnlockDrawing
  end;
end;

CodePudding user response:

The FMX TControl class has BeginUpdate() / EndUpdate() methods, so just try this:

procedure TForm2.Memo1DblClick(Sender: TObject);
var
  i: Integer;
const
  Line = '1234567890_1234567890_1234567890_1234567890_1234567890_1234567890';
begin
  Memo1.Lines.Clear;
  Memo1.BeginUpdate;
  for i := 1 to 1000 do
    Memo1.Lines.Add(Line);
  Memo1.EndUpdate;
end;
  • Related