Recent

Author Topic: [SOLVED] TKMemo: Finding index of the block at which the caret is located?  (Read 3249 times)

CM630

  • Hero Member
  • *****
  • Posts: 1082
  • Не съм сигурен, че те разбирам.
    • http://sourceforge.net/u/cm630/profile/
I need to locate caret (cursor) to text coloured in red in a TKMemo. On next execution cursor shall go to the next red item.
Code below goes to the first red item.
My problem is that I cannot determine the index of the block in which caret is located, in order to start checking from that point on.
http://wiki.freepascal.org/KControls/KmemoNotes provides some info.
TKMemoSelectionIndex is mentioned, but i guess it is some undefined variable, used in the example.
IndexToBlockIndex is also mentioned, but it does not seem to do what is needed.
At least KMemo1.Blocks.IndexToBlockIndex(KMemo1.Blocks.RealSelEnd, LocalIndex); sets LocalIndex to 0 (I expect 2).

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3.  
  4. {$mode objfpc}{$H+}
  5.  
  6.  
  7. interface
  8.  
  9.  
  10. uses
  11.   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
  12.   kmemo, keditcommon;
  13.  
  14.  
  15. type
  16.  
  17.  
  18.   { TForm1 }
  19.  
  20.  
  21.   TForm1 = class(TForm)
  22.     Button1: TButton;
  23.     KMemo1: TKMemo;
  24.     Label1: TLabel;
  25.     procedure Button1Click(Sender: TObject);
  26.     procedure FormCreate(Sender: TObject);
  27.   private
  28.  
  29.  
  30.   public
  31.  
  32.  
  33.   end;
  34.  
  35.  
  36. var
  37.   Form1: TForm1;
  38.  
  39.  
  40. implementation
  41.  
  42.  
  43. {$R *.lfm}
  44.  
  45.  
  46. { TForm1 }
  47.  
  48.  
  49. procedure TForm1.FormCreate(Sender: TObject);
  50. var
  51.   TB: TKMemoTextBlock = Nil;
  52.   i: integer;
  53. begin
  54.   KMemo1.blocks.Clear;
  55.   for i:=1 to 10 do
  56.   begin
  57.     TB := KMemo1.Blocks.AddTextBlock('Line ' + IntToStr(i) + ',' + IntToStr(1));
  58.     TB.TextStyle.Font.Color := clBlue;
  59.     KMemo1.Blocks.AddParagraph();
  60.     TB := KMemo1.Blocks.AddTextBlock('Line ' + IntToStr(i) + ',' + IntToStr(2));
  61.     TB.TextStyle.Font.Color := clRed;
  62.     KMemo1.Blocks.AddParagraph();
  63.     TB := KMemo1.Blocks.AddTextBlock('Line ' + IntToStr(i) + ',' + IntToStr(3));
  64.     TB.TextStyle.Font.Color := clGreen;
  65.     if i<> 10 then KMemo1.Blocks.AddParagraph();
  66.   end;
  67. end;
  68.  
  69.  
  70. procedure TForm1.Button1Click(Sender: TObject);
  71. var
  72.   BlockIndex : integer;
  73.   BlockPos : trect;
  74.   LocalIndex: integer;
  75. begin
  76.   for BlockIndex:= 0 to KMemo1.Blocks.Count -1 do
  77.   begin
  78.     if KMemo1.Blocks[BlockIndex] is TKMemoTextBlock then
  79.       if TKMemoTextBlock(KMemo1.Blocks[BlockIndex]).TextStyle.Font.Color=clRed then
  80.         begin
  81.           BlockPos := KMemo1.BlockRect(KMemo1.Blocks[BlockIndex]);
  82.           KMemo1.ExecuteCommand(ecGotoXY, @BlockPos.TopLeft);
  83.           KMemo1.Blocks.IndexToBlockIndex(KMemo1.Blocks.RealSelEnd, LocalIndex);
  84.           Label1.Caption:= IntToStr(BlockIndex) + '    ' +IntToStr(KMemo1.Blocks.RealSelEnd) + '    ' + IntToStr(LocalIndex) ;
  85.           exit; //Commenting this line will go to last RED position
  86.         end;
  87.   end;
  88. end;
  89.  
  90.  
  91. end.
« Last Edit: November 28, 2018, 03:24:52 pm by CM630 »
Лазар 3,2 32 bit (sometimes 64 bit); FPC3,2,2; rev: Lazarus_3_0 on Win10 64bit.

dbannon

  • Hero Member
  • *****
  • Posts: 2786
    • tomboy-ng, a rewrite of the classic Tomboy
Re: TKMemo: Finding index of the block at which the caret is located?
« Reply #1 on: November 27, 2018, 01:07:26 pm »
I'm not in a position to try it out right now but I think you want something like this :

Code: Pascal  [Select][+][-]
  1. BlockNo := kmemo1.Blocks.IndexToBlockIndex(KMemo1.RealSelStart, PosInBlock);

RealSelStart tracks the cursor while a user is typing for example. PosinBlock is an "out" that ends up with a the offset within the block, zero if cursor is on first char of block etc.

Davo
Lazarus 3, Linux (and reluctantly Win10/11, OSX Monterey)
My Project - https://github.com/tomboy-notes/tomboy-ng and my github - https://github.com/davidbannon

CM630

  • Hero Member
  • *****
  • Posts: 1082
  • Не съм сигурен, че те разбирам.
    • http://sourceforge.net/u/cm630/profile/
Re: TKMemo: Finding index of the block at which the caret is located?
« Reply #2 on: November 27, 2018, 01:49:58 pm »

Thanks,
I have changed RealSelEnd to RealSelStart as you offered, but I still get a zero.
When excuting the code below I get in label 1: „2   9   0‟


Code: Pascal  [Select][+][-]
  1.    KMemo1.Blocks.IndexToBlockIndex(KMemo1.Blocks.RealSelStart, LocalIndex);
  2.    Label1.Caption:= IntToStr(BlockIndex) + '    ' +IntToStr(KMemo1.Blocks.RealSelStart) + '    ' + IntToStr(LocalIndex) ;
  3.  
Лазар 3,2 32 bit (sometimes 64 bit); FPC3,2,2; rev: Lazarus_3_0 on Win10 64bit.

dbannon

  • Hero Member
  • *****
  • Posts: 2786
    • tomboy-ng, a rewrite of the classic Tomboy
Re: TKMemo: Finding index of the block at which the caret is located?
« Reply #3 on: November 28, 2018, 05:37:20 am »
OK, here is my attempt to do what I think you want to.

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button2Click(Sender: TObject);
  2. var
  3.   BlockNo, PosInBlock : longint;
  4. begin
  5.     BlockNo := kmemo1.Blocks.IndexToBlockIndex(KMemo1.RealSelStart, PosInBlock) + 2;
  6.     while BlockNo < Kmemo1.Blocks.Count do
  7.         if TKMemoTextBlock(KMemo1.Blocks.Items[BlockNo]).TextStyle.Font.Color = clRed then break
  8.         else BlockNo := BlockNo + 2;
  9.     if BlockNo < Kmemo1.Blocks.Count then begin
  10.         Kmemo1.SelStart := KMemo1.Blocks.BlockToIndex(KMemo1.Blocks.Items[BlockNo]);
  11.         Kmemo1.SelEnd := KMemo1.Blocks.BlockToIndex(KMemo1.Blocks.Items[BlockNo]);
  12.         Kmemo1.SetFocus;
  13.     end;
  14. end;  

Note that when you click the button you move the focus away from KMemo1, I wonder if that was what was causing your problem ? (Note I has assumed every line is one block long so can index by 2 and skip paragraph marker, I'm sure you can do better in a real life app)

Davo
Lazarus 3, Linux (and reluctantly Win10/11, OSX Monterey)
My Project - https://github.com/tomboy-notes/tomboy-ng and my github - https://github.com/davidbannon

CM630

  • Hero Member
  • *****
  • Posts: 1082
  • Не съм сигурен, че те разбирам.
    • http://sourceforge.net/u/cm630/profile/
Re: TKMemo: Finding index of the block at which the caret is located?
« Reply #4 on: November 28, 2018, 03:26:28 pm »

Thanks,
It works!

Note that when you click the button you move the focus away from KMemo1, I wonder if that was what was causing your problem ?
This should not be the reason for my code not working. I have suspected that and I have tried Kmemo1.SetFocus; before.
And your code works without it.


  It is rather due to some difference (maybe a bug) in ExecuteCommand(ecGotoXY,...) and Kmemo1.SelXXX used in your code.
« Last Edit: November 28, 2018, 03:31:12 pm by CM630 »
Лазар 3,2 32 bit (sometimes 64 bit); FPC3,2,2; rev: Lazarus_3_0 on Win10 64bit.

 

TinyPortal © 2005-2018