Set tabs by buttonClick

General TRichView support forum. Please post your questions here
Post Reply
j&b
Posts: 184
Joined: Mon Sep 05, 2005 1:35 pm

Set tabs by buttonClick

Post by j&b »

Question to Pieters ruler:

Who can tell me how I can set 2 tabs by buttonClick. One right tab at 4 cm and one left tab at 12cm ?

Jürgen
Sergey Tkachenko
Site Admin
Posts: 17559
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

As en edting operation (which can be undone by user)? For the selected paragraphs?
j&b
Posts: 184
Joined: Mon Sep 05, 2005 1:35 pm

Post by j&b »

Hello Sergey,

yes for both (which can be undone and for selected paragraphs).

Thanks,

Jürgen
Sergey Tkachenko
Site Admin
Posts: 17559
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

Ok. Assuming that you do not use RichViewActions... All editing operations on paragraph attributes, including tabs, must be implemented using ApplyParaStyleConversion procedure + OnParaStyleConversion event.

How to add this command to the demo in Demos\Delphi\Editors\Editor 2\:

Open Unit1.pas.
Find declaration of PARA_* constants.
Add a new constant, with unique value among them:

Code: Select all

PARA_TAB        = 5;
Place a button, call in its OnClick:

Code: Select all

  rve.ApplyParaStyleConversion(PARA_TAB);
Add RVFuncs in uses.

Add the following function, converting mm to pixels:

Code: Select all

function MMToPixels(mm: Integer): Integer;
var ppi: Integer;
begin
  ppi := RichViewPixelsPerInch;
  if ppi=0 then
    ppi := Screen.PixelsPerInch;
  Result := Round ( mm * 5 * ppi / 127 );
end;
Find TForm1.rveParaStyleConversion. Add

Code: Select all

    Tabs: TRVTabInfos;
to its vars.
In its case operator, add:

Code: Select all

      PARA_TAB:
         begin
           Tabs := TRVTabInfos.Create(nil);
           with Tabs.Add do begin
             Position := MMToPixels(40);
             Align := rvtaRight;
           end;
           with Tabs.Add do begin
             Position := MMToPixels(130);
             Align := rvtaLeft;
           end;
           ParaInfo.Tabs.AddFrom(Tabs);
           Tabs.Free;
         end;
Pieter Zijlstra
Posts: 42
Joined: Sat Oct 08, 2005 3:56 pm
Location: The Netherlands
Contact:

Post by Pieter Zijlstra »

Funny, just mailed a similar answer. Is there any specific reason you're using the way of creating TRVTabInfos and assigning it to ParaInfo.Tabs instead of using ParaInfo.Tabs directly?

Code: Select all

ParaInfo.Tabs.Clear;
with ParaInfo.Tabs.Add do begin
  Position := MMToPixels(40); 
  Align := rvtaLeft;
end;
// etc
j&b
Posts: 184
Joined: Mon Sep 05, 2005 1:35 pm

Post by j&b »

Hello Sergey, hello Pieter,

thanks for your answers.

It has a simple reason why I want to set a tab stop about delphi-code (= buttonClick).
People write a text (in rveMemo). My program has the option to set a text as '------- Ende des Berichts ----' 2 lines under the last line of user-text.

First I attach the line with 35 spaces before Text:
<35 spaces>+'------- Ende des Berichts ----'.

After writing much (many) memos I saw that the attached text doesn't begin at the same position (it depends from the the attributes of last line before I attached the 'Ende des Berichts'-line. Spaces with font.size 20 are more broadly as spaces with font.size 10.

I thought that it may be a simple way to start the 'Ende..'- text always at the same position about tab-stops.

If there is no (simple ?) solution I want to go following way:

I save the last text-attributes and create a new font.size, font.name etc for the new line and set the line as before (<35 spaces>+'------- Ende des Berichts ----').
After that I attach the old attributes.

Independently of it I want to know how I can set a tab-stop (left, right, middle) to a wanted position of a (wanted) line.

I hope you have a simple solution.

Jürgen
Sergey Tkachenko
Site Admin
Posts: 17559
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

Pieter, your code clears all existing tabs and then adds new tabs. My code adds new tabs in addition to the existing tabs.

Without clearing, you should search if some tab exists at the given position (using ParaInfo.Tabs.Find), and, if exists, update its properties instead of adding a new tab. Using a local tab collection + AddFrom is a bit simpler.

Well, in the original post it was not specified clearly if the existing tabs should be kept or not.
Sergey Tkachenko
Site Admin
Posts: 17559
Joined: Sat Aug 27, 2005 10:28 am
Contact:

Post by Sergey Tkachenko »

j&b, so, as I understand, you need to create a paragraph style with the given tab stops to add some text lines formatted with this paragraph style.

Code: Select all

{ This function returns index of paragraph style with the
  specified collection of tabs. If such paragraph style does not
  exist, this function adds it.
  (this function uses MMToPixels from the previous example)
}
function GetParaStyleWithTabs(rvs: TRVStyle): Integer;
var ParaInfo: TParaInfo;
begin
  ParaInfo := TParaInfo.Create(nil);
  with ParaInfo.Tabs.Add do begin
    Position := MMToPixels(40);
    Align := rvtaRight;
  end;
  with ParaInfo.Tabs.Add do begin
    Position := MMToPixels(130);
    Align := rvtaLeft;
  end;
  Result := rvs.ParaStyles.FindSuchStyle(0,ParaInfo,RVAllParaInfoProperties);
  if Result=-1 then begin
    rvs.ParaStyles.Add;
    Result := rvs.ParaStyles.Count-1;
    rvs.ParaStyles[Result].Assign(ParaInfo);
    rvs.ParaStyles[Result].Standard := False;
  end;
  ParaInfo.Free;
end;
How to add line of the given paragraph style to the end of document

1) As an editing operation, using current text style

Code: Select all

var ItemNo, Offs: Integer;

ItemNo := rve.ItemCount-1;
Offs := rve.GetOffsAfterItem(ItemNo);
rve.SetSelectionBounds(ItemNo, Offs, ItemNo, Offs);
rve.InsertText(#13);
rve.ApplyParaStyle(GetParaStyleWithTabs(rve.Style));
rve.InsertText(#9'------- Ende des Berichts ----');
2) Not as en editing operation. Works both for TRichView and TRichViewEdit.

Code: Select all

var i, ParaNo, StyleNo: Integer;

// searching for the last text item, using its text style
StyleNo := 0;
for i := rve.ItemCount-1 downto 0 do
  if rve.GetItemStyle(i)>=0 then begin
    StyleNo := rve.GetItemStyle(i);
    break;
  end;
ParaNo := GetParaStyleWithTabs(rve.Style);
// you cannot use AddNL for strings with tab characters
rve.AddTextNLA((#9'------- Ende des Berichts ----', StyleNo, ParaNo, ParaNo);
rve.Format;
rve.ClearUndo; // if called for editor
I hope this is what you asked for.
j&b
Posts: 184
Joined: Mon Sep 05, 2005 1:35 pm

Post by j&b »

Thanks for your help !

I have solved my problems with your help.
I have prefered Sergeys solution because I only have to add some lines (look at "<-----")
My example has one problem:
Today I don't know how many tab_1 (up to tab_n) I need in some days.
How can I solve this problem and how can I optize my code (look at TForm1.TabSetzenClick and
to the part "PARA_TAB: //<-------ADD---------------" of TForm1.memoParaStyleConversion(...)

Jürgen


Code: Select all

procedure TForm1.TabSetzenClick(Sender: TObject);  //<--------------
begin
  tab_clear:=true; 
  tab_1:=   5;  tab_1_align:= 1;    //1: left, 2: center, 3: right
  tab_2:= 12;  tab_2_align:= 2;  
  memo.ApplyParaStyleConversion(PARA_TAB);
end;

--------------------------------------------
0.
uses ..., RVFuncs;


1.
 private
 //rv
 ..., tab_clear: Boolean;
 ..., tab_1, tab_2,    tab_1_align, tab_2_align: Integer;
 //rv-Ende


2. 
{$R *.dfm}

const
  //rv
  rv_MAKEBOLD = 1;
  ...
 
 // Parameters for ApplyParaStyleConversion
  PARA_ALIGNMENT  = 1;
  PARA_INDENTINC  = 2;
  PARA_INDENTDEC  = 3;
  PARA_COLOR      = 4;
  PARA_TAB        = 5;  <-------------------
 //rv-Ende


3.
procedure TForm1.memoParaStyleConversion(Sender: ....);

  function MMToPixels(mm: Integer): Integer;  //<------------
    var ppi: Integer; 
  begin 
    ppi := RichViewPixelsPerInch; 
    if ppi=0 then ppi := Screen.PixelsPerInch; 
    Result := Round ( mm * 5 * ppi / 127 ); 
  end;                                                            //<--------------
  
var ParaInfo: TParaInfo;
        Tabs: TRVTabInfos;                             //<--------------
begin
  ParaInfo := TParaInfo.Create(nil);
  try
    ParaInfo.Assign(rvs.ParaStyles[StyleNo]); 
    case UserData of
      PARA_ALIGNMENT: ParaInfo.Alignment := GetAlignmentFromUI;
      PARA_INDENTINC:
        begin
          ParaInfo.LeftIndent := ParaInfo.LeftIndent+20;
          if ParaInfo.LeftIndent>200 then ParaInfo.LeftIndent := 200;
        end;
      PARA_INDENTDEC:
        begin
          ParaInfo.LeftIndent := ParaInfo.LeftIndent-20;
          if ParaInfo.LeftIndent<0 then ParaInfo.LeftIndent := 0;
        end;
      PARA_TAB:    //<---------------------------------------
        begin 
          Tabs := TRVTabInfos.Create(nil); 
          if tab_clear=true then begin ParaInfo.Tabs.clear; tab_clear:= false; end;
          if tab_1>0 then  begin
            with Tabs.Add do begin 
              Position := MMToPixels(tab_1); 
              if tab_1_align=1 then Align := rvtaLeft
              else if tab_1_align=2 then Align := rvtaCenter
              else if tab_1_align=3 then Align := rvtaRight; 
            end; 
          end;
          if tab_2>0 then  begin
            with Tabs.Add do begin 
              Position := MMToPixels(tab_2); 
              if tab_2_align=1 then Align := rvtaLeft
              else if tab_2_align=2 then Align := rvtaCenter
              else if tab_2_align=3 then Align := rvtaRight; 
            end;
          end;  
          ParaInfo.Tabs.AddFrom(Tabs); 
          Tabs.Free; 
      end;                   //<---------------------------------------
      PARA_COLOR: ParaInfo.Background.Color := cd.Color;
    end;  //o case
    NewStyleNo := rvs.ParaStyles.FindSuchStyle(StyleNo,ParaInfo,RVAllParaInfoProperties);
    if NewStyleNo=-1 then begin
      rvs.ParaStyles.Add;
      NewStyleNo := rvs.ParaStyles.Count-1;
      rvs.ParaStyles[NewStyleNo].Assign(ParaInfo);
      rvs.ParaStyles[NewStyleNo].Standard := False;
    end;
  finally
    ParaInfo.Free;
  end;
end;
Pieter Zijlstra
Posts: 42
Joined: Sat Oct 08, 2005 3:56 pm
Location: The Netherlands
Contact:

Post by Pieter Zijlstra »

Sergey, I misread, I was pretty sure I read Assign() instead AddFrom() :o

j&b, You don't have to create the TabList inside the OnParaStyleConversion. You could also create it outside it and assign the list to ParaInfo.Tabs in the OnParaStyleConversion.

Code: Select all

  private
    { Private declarations }
    FTabs: TRVTabInfos;
Inside the OnParaStyleConversion...

Code: Select all

    case UserData of
      // ...
      PARA_TAB: begin
                  if Assigned(FTabs) then
                    ParaInfo.Tabs.Assign(FTabs);
                 end;
      // ...
    end;
In your button click...

Code: Select all

  FTabs := TRVTabInfos.Create(nil);
  try
    with FTabs.Add do begin
      Position := MMToPixels(50);
      Align := rvtaLeft;
    end;
    with FTabs.Add do begin
      Position := MMToPixels(120);
      Align := rvtaLeft;
    end;
    RichViewEdit1.ApplyParaStyleConversion(PARA_TAB);
  finally
    FreeAndNil(FTabs);
  end;

Instead of creating/freeing the list all the times it should be pretty save to keep you own list, create it at startup, fill it with the settings read from an ini-file for instance and assign that list to ParaInfo.Tabs.Assign().
Post Reply