Jump to content
JohnLM

TMemo - loading a file but keeping last screen layout

Recommended Posts

I have been searching via google but not turned up any answer to this. 

 

1. Say I have multiple files of similar text and I save them.

2. Then, when I load (or open) any of those text files in TMemo, I want to maintain the last screen layout (line) within the dimensions.

 

I am comparing structures of column (hex/ascii) data in these text files and if I am in the middle of the file in the tmemo and I decide to load another file to quickly compare back/forth with, I want the layout the remain the same but not start from the top of the text file. 

 

I know I have to save the last topmost line in a variable but I don't know how to go further in this. TIA. 

 

im_tmemo_layout_a.thumb.png.0e9cf69f1d389d945389bbbd5861f47e.png

Fig A - this is the layout that opens by default for every load. But I want Fib B if I am scrolling down and stop and decide to load another file. 

 

 

im_tmemo_layout_b.thumb.png.0492e3372191399b758595efe4fe40e9.png

Fig B - if I open at the last layout position this is what I want to see.., not Fig A. 

 

Edited by JohnLM
added images

Share this post


Link to post

If i understand your request, then you need to restore the position of first visible line

In that case you can use this

type
  TForm11 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
  private
    FMemo1Position: Integer;
    procedure Memo1SavePosition;
    procedure Memo1RestorePosition;
  public
    procedure LoadContent;
  end;

var
  Form11: TForm11;

implementation

{$R *.dfm}

procedure TForm11.Button1Click(Sender: TObject);
begin
  LoadContent;
end;

procedure TForm11.LoadContent;
begin
  Memo1SavePosition;
  Memo1.Lines.BeginUpdate;
  try
    Memo1.Lines.Clear;
    while Memo1.Lines.Count < 100 do
      Memo1.Lines.Add(IntToStr(Memo1.Lines.Count));
  finally
    Memo1.Lines.EndUpdate;
  end;
  Memo1RestorePosition;
end;

procedure TForm11.Memo1RestorePosition;
var
  Current: Integer;
begin
  Current := Memo1.perform(EM_GETFIRSTVISIBLELINE, 0, 0);
  Memo1.perform(EM_LINESCROLL, 0, FMemo1Position - Current);
  // or
  //Memo1.perform(EM_LINESCROLL, 0, FMemo1Position -  Memo1.perform(EM_GETFIRSTVISIBLELINE, 0, 0));
end;

procedure TForm11.Memo1SavePosition;
begin
  FMemo1Position := Memo1.perform(EM_GETFIRSTVISIBLELINE, 0, 0);
end;

 

Share this post


Link to post

Hi.  I had found something that works (but does not account for the cursor at this time) but had not the time to post back how I did it.  But I will read/consider your method as a possible option, thank you. 

 

The method that I have been testing is below. 

 

I have a [Load] button that loads streams that I save using the sfBinary format of TStream/TMemoryStream. 

var
  form1: TForm1;
  topline: integer=0; 

... 

procedure TForm1.btnLoadClick(Sender: TObject);
begin
  if mem1.Active then begin
    mem1.LoadFromFile(txtFilename.text,sfjson);
    // store the top line of memo into global var on load
    TopLine := memo1.Perform(EM_GETFIRSTVISIBLELINE, 0, 0); 
  end;

  btnbufArray.Click; // process array into hex and ascii code and show in memo1

  // now, if at any time I was in the memo and scrolling up/down and TopLine > 0 then I update the memo's viewing position. 
  if TopLine > 0 then begin
    SendMessage(memo1.Handle, EM_LINESCROLL, 0, TopLine);
  end;

 

 

 

Share this post


Link to post

The trouble with memo need to set word wrap to false to track lines.   

 

Here's a way to simply output to image or Paintbox. Painting StringGrid is above my paygrade.  To call it pass self and a canvas when the view or the data is changed.

procedure DrawCanvasPat(Sender: Tobject; Canvas: TCanvas);
begin
  with Canvas do
  begin
    Pen.Width := 3;
    for var C in [0 .. 9] do // := Low to High do FAD here
    begin
      var
      R := 0;
      var
      fields := ['First', '', '', '', 'Mid', '', '', 'H', '', 'Last', 'Ten'];
      // ShowMessage(fields[0]);

      TextOut(C * 45 + 45, R + 23, fields[C]);
      for R in [CSVHeaderTopLine .. 9] do
      begin
        var
        value := (Random(20) - 10);
        if value > 0 then
          Pen.Color := clGreen
        else
          Pen.Color := clRed;
        Rectangle(C * 45 + 60, R * 23 + 30, C * 45 + 64, R * 23 + 33);
        TextOut(C * 45 + 45, R * 23 + 23, value.ToString);

        // ColorDrawItem2(sgUI, sgUI.Canvas,cellValue.tostring,Lrect,TRue);
      end;
    end;
  end;

end;

    

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×