Page 1 of 1
Set tabs by buttonClick
Posted: Mon Nov 13, 2006 3:31 pm
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
Posted: Tue Nov 14, 2006 5:46 pm
by Sergey Tkachenko
As en edting operation (which can be undone by user)? For the selected paragraphs?
Posted: Tue Nov 14, 2006 8:29 pm
by j&b
Hello Sergey,
yes for both (which can be undone and for selected paragraphs).
Thanks,
Jürgen
Posted: Tue Nov 14, 2006 9:19 pm
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:
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
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;
Posted: Tue Nov 14, 2006 9:39 pm
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
Posted: Wed Nov 15, 2006 6:16 am
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
Posted: Wed Nov 15, 2006 2:33 pm
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.
Posted: Wed Nov 15, 2006 3:01 pm
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.
Posted: Wed Nov 15, 2006 4:56 pm
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;
Posted: Wed Nov 15, 2006 10:24 pm
by Pieter Zijlstra
Sergey, I misread, I was pretty sure I read Assign() instead AddFrom()
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().