Numbering with TRichEdit in Delphi - delphi-xe3

I am trying to implement numbering in TRichEdit component, Delphi. Ideally I want to get the same behavior as in these 3rd party component:
As you can see Numbering button works similar way as Bullet button. I mean it sets FirstIdent or LeftIdent (I am not sure) and put the numbers 1,2,3,... instead of bullets. When you move cursor to the left close to number it does not allow to move onto number but jumps one line up.
This is what I got so far:
procedure TMainForm.NumberingButtonClick(Sender: TObject);
var
i: Integer;
s: String;
begin
if NumberingButton.Down then
begin
Editor.Paragraph.Numbering := nsNone;
i := Editor.ActiveLineNo;
s := Editor.Lines[i];
insert(inttostr(i)+'. ', s, 1);
//Editor.Paragraph.LeftIndent := 10;
Editor.Paragraph.FirstIndent := 10;
Editor.Lines[i] := s;
end;
end;
But it does not work as I want. Anybody have any ideas?

This code works exactly how I expected:
procedure TMainForm.NumberingButtonClick(Sender: TObject);
var
i: Integer;
s: String;
fmt: TParaFormat2;
begin
FillChar(fmt, SizeOf(fmt), 0);
fmt.cbSize := SizeOf(fmt);
fmt.dwMask := PFM_NUMBERING or PFM_NUMBERINGSTART or
PFM_NUMBERINGSTYLE or PFM_NUMBERINGTAB;
if NumberingButton.Down then
fmt.wNumbering := 2
else
fmt.wNumbering := 0;
// wNumbering:
// 0 - no numbering
// 1 - bullet list (·, ·, ·, ...).
// 2 - Arabic numbers (1, 2, 3, ...).
// 3 - small letters (a, b, c, ...).
// 4 - capital letters (A, B, C, ...).
// 5 - small Roman numbers (i, ii, iii, ...).
// 6 - capital Roman numbers (I, II, III, ...).
// 7 - Unicode character sequence
fmt.wNumberingStart := 1;
// wNumberingStart:
// The number at which the numbering starts.
fmt.wNumberingStyle := $200;
// wNumberingStyle:
// Numbering Style
// 0 : 1)
// $100 : (1)
// $200 : 1.
// $300 : 1
// $400 : remove list
// $8000 : continues to number the list without changing the style
fmt.wNumberingTab := 1440 div 4;
// wNumberingTab:
// the space between number and paragraph text
Editor.Perform( EM_SETPARAFORMAT, 0, lParam( #fmt ) );
if BulletsButton.Down then
BulletsButton.Down := False;
end;
Thanks to www.decoding.dax.ru

Related

Removing char from string in pascal cause question marks in console pascal

I am trying write simple program that will remove all 'o' letters from the string.
Example :
I love cats
Output:
I lve cats
I wrote following code :
var
x:integer;
text:string;
text_no_o:string;
begin
text:='I love cats';
for x := 0 to Length(text) do
//writeln(Ord(text[6]));
if(Ord(text[x])=111) then
else
text_no_o[x]:=text[x];
write(text_no_o);
end.
begin
end;
end.
When text is in English program works fine .
But if i change it to Russian . It returns we question marks in console.
Code with small modifications for Russian language.
var
x:integer;
text:string;
text_no_o:string;
begin
text:='Русский язык мой родной';
for x := 0 to Length(text) do
//writeln(Ord(text[6]));
if(Ord(text[x])=190) then
else
text_no_o[x]:=text[x];
write(text_no_o);
end.
begin
end;
end.
And result in console that i receive is :
Русский язык м�й р�дн�й
I expect receive
Русский язык мй рднй
As I got the problem can be caused incorrect encoding settings in console, so i should force pascal to use CP1252 instead ANSI .
I am using Free Pascal Compiler version 3.2.0+dfsg-12 for Linux .
P.S I am not allowed to use StringReplace or Pos
Simple solution:
function Simple_StripO (Text : String) : String;
var
i : integer;
Text2 : string;
begin
Text2 := '';
for i := 1 to Length(Text) do
if Text[i] <> 'o' then
Text2 := Text2 + Text[i];
Result := Text2; // Or Simple_StripO := Text2;
end;
The string is likely to be UTF8 encoded. So the cyrillic o is encoded as two chars $d0 $be. Here you replace one $be (=190). You need to replace both chars, though you cannot just test for the value of the char, because their meaning depends of surrounding chars.
Here is a way, remembering the current state (outside of letter or after first byte)
var
c: char;
text: string;
state: (sOutside, sAfterD0);
begin
text:= 'Русский язык мой родной';
state:= sOutside;
for c in text do
begin
if state = sOutside then
begin
if c = #$D0 then // may be the start of the letter
state := sAfterD0
else
write(c); // output this char because not part of letter
end
else if state = sAfterD0 then
begin
if c = #$BE then state := sOutside // finished skipping
else
begin
// chars do not form letter so output skipped char
write(#$D0, c);
state := sOutside;
end;
end
end;
writeln;
end.

Call by Reference and Call by Value Result

Well, there was a debate on the below code between me and my friend. We're a bit confused about the output it produce. Can someone clarify the call-by-reference and call-by value result for the below piece of code?
program params;
var i: integer;
a: array[1..2] of integer;
procedure p(x,y: integer);
begin
x := x + 1;
i := i + 1;
y := y + 1;
end;
begin
a[1] := 1;
a[2] := 2;
i := 1;
p( a[i],a[i] );
output( a[1],a[2] );
end.
The resulting output of this program in the case that the
parameters are transmitted to procedure p by value-result and by reference.
Call by Value
x and y in p are local variables initialized with the actual parameters, while i is a global variable, so the call p( a[i],a[i] ) is equivalent to:
x := 1 /* The value of a[i] */
y := 1 /* The value of a[i] */
x := 2 /* x + 1 */
i := 2 /* i + 1 */
y := 2 /* y + 1 */
and at the end the values 1, 2 are printed since they are the values of a[1], a[2] which weren't changed.
Call by Reference
Both x and y in p are alias for a[1] and (again) a[1] (since i = 1 when the procedure is called), so the call is equivalent to:
a[1] := 2 /* a[1] + 1 */
i := 2 /* i + 1 */
a[1] := 3 /* a[1] + 1 */
and at the end the values 3, 2 are printed.
Call by Name
Call by Name is equivalent to Call by Reference when simple variables are passed as parameters, but is different when you pass an expression that denotes a memory location, like a subscript. In this case the actual parameter is re-evaluated each time it is encountered. So in this case, this is the effect of the call of p( a[i],a[i] ):
a[1] := 2 /* since i = 1, the result is equal to a[1] + 1 */
i := 2 /* i + 1 */
a[2] := 3 /* since i is now 2, the result is equal to a[2] + 1 */
and at the end the values 2, 3 are printed. In practice the implementation calls an anonymous function (a “thunk”), each time it must evaluate a parameter.
Call by Value Result
Just to complete the discussion, here is the case for the value-result parameter passing, in which x and y are initialized at the beginning of the procedure execution with the values of the actual parameters, and, at the end of the execution of the procedure, are copied back to the original variables addresses:
x := 1 /* The value of a[i] */
y := 1 /* The value of a[i] */
x := 2 /* x + 1 */
i := 2 /* i + 1 */
y := 2 /* y + 1 */
a[1] := 2 /* the value of x is copied back to a[1] */
a[1] := 2 /* the value of y is copied back to a[1] (not a[2]!) */
and at the end the values 2, 2 are printed.
For a discussion of the different ways of passing parameters, see for instance this.
procedure p(x, y: integer);
begin
end;
In this case the varaibles passed as parameters are never modified. They are copied either to two registers (likely x: EAX and y: ECX) or to the stack. (depending on the compiler ABI)
procedure p(var x, y: integer);
begin
end;
In this case the original parameters are modified. x and y are pointers to the original variables passed as parameters.

How to get/find the variable that caused Division By Zero error in delphi?

I know how to do basic exception handling. So i can raise a message on divide by zero using the 'try except' method.
What i would like to do is, find the variable that causes this error and then change its value on run time.
For Ex:
procedure Calculate();
var
a, b, c : Double;
begin
try
a := 4; //suppose i take this value from user and he enters 4
b := 0; //suppose i take this value from user and he enters 0
c := a/b;
ShowMessage(FloatToStr(c));
except
on E : EZeroDivide do
begin
ShowMessage('Exception message = '+E.Message);
//i am not sure how to identify that its variable 'b' that is causing the error and has to be changed by a default value
get(E....errorVaraiable);
E....errorVaraiable := 0.00001;
c := a/E....errorVariable;
ShowMessage(FloatToStr(c));
end;
end;
Please, can anyone help me with this?
Here's a modified version of your example that does what you want.
procedure Calculate();
var
a, b, c : Double;
begin
a := 4; //suppose i take this value from user and he enters 4
b := 0; //suppose i take this value from user and he enters 0
if IsZero(b) then
begin
ShowMessage('b cannot be 0')
end
else
begin
c := a/b;
ShowMessage(FloatToStr(c));
end;
end;

How to prevent forms moving of screen

I use the following helper for preventing forms moving of screen and it is most of the time working OK. But if I open a wsNormal form in a MDI app then the form might show up of the area where it is supposed to be. I can then just move it a bit and then the unit here takes over and moves it in place.
My question is now: how can I either prevent this from happening or send a message to the form saying it is moving so the unit her can do its job.
unit U_FormsMove;
interface
uses
Messages, Windows, Forms;
{$M+}
type
TForm = class(Forms.TForm)
private
protected
procedure WMMoving(var message : TWMMoving); message WM_MOVING;
published
public
end;
implementation
function GetMovementArea: TRect;
var
MovementRect: TRect;
begin
if Application.MainForm.FormStyle = fsMDIForm then
Windows.GetWindowRect(Application.MainForm.ClientHandle, MovementRect)
else
SystemParametersInfo(SPI_GETWORKAREA, 0, #MovementRect, 0);
if MovementRect.Top < 150 then
MovementRect.Top := 150;
MovementRect.Top := MovementRect.Top + 5;
MovementRect.Left := MovementRect.Left + 5;
MovementRect.Right := MovementRect.Right - 5;
MovementRect.Bottom := MovementRect.Bottom - 5;
Result := MovementRect;
end;
{ TFormHelper }
procedure TForm.WMMoving(var Message: TWMMoving);
var
rec: ^TRect;
wrk: TRect;
begin
wrk := GetMovementArea;
rec := Pointer(Message.DragRect);
if rec^.Left < wrk.Left then
begin
rec^.Right := rec^.Right - (rec^.Left - wrk.Left);
rec^.Left := wrk.Left;
end
else if rec^.Right > wrk.Right then
begin
rec^.Left := rec^.Left - (rec^.Right - wrk.Right);
rec^.Right := wrk.Right;
end;
if rec^.Top < wrk.Top then
begin
rec^.Bottom := rec^.Bottom - (rec^.Top - wrk.Top);
rec^.Top := wrk.Top;
end
else if rec^.Bottom > wrk.Bottom then
begin
rec^.Top := rec^.Top - (rec^.Bottom - wrk.Bottom);
rec^.Bottom := wrk.Bottom;
end;
end;
end.

Display Serial Number as Roman letters in Crystal Reports

need to display serial no as roman letters(i,ii,iii,iv etc) in my crystal reports. I have the serial number captured as record number (1,2,3,4...).so what i have to do for it in crystal report.
Just use the Roman() function provided by Crystal Reports
I can't take much of the credit; I simply ported the code from this VB Helper article into Crystal, but it was a fun exercise:
NumberVar iCounter := 0;
Local StringVar ch := "";
Local NumberVar result := 0;
Local NumberVar new_value := 0;
Local NumberVar old_value := 0;
Local StringVar temp := "";
temp := UpperCase({?#Roman});
old_value = 1000;
For iCounter := 1 To Len(temp) do
(
// See what the next character is worth.
ch := Mid(temp, iCounter, 1);
if ch = "I" then new_value := 1
else if ch = "V" then new_value := 5
else if ch = "X" then new_value := 10
else if ch = "L" then new_value := 50
else if ch = "C" then new_value := 100
else if ch = "D" then new_value := 500
else if ch = "M" then new_value := 1000;
// See if this character is bigger
// than the previous one.
If new_value > old_value Then
// The new value > the previous one.
// Add this value to the result
// and subtract the previous one twice.
result := result + new_value - 2 * old_value
Else
// The new value <= the previous one.
// Add it to the result.
result := result + new_value;
old_value := new_value;
);
// Format the number without commas or decimals
ToText(result, 0, "");
Simply replace my {?#Roman} parameter placeholder with your variable, and you're all set.
I tried to fix it [enter image description here][1]
<https://www.tek-tips.com/viewthread.cfm?qid=887691>
or
<https://www.tek-tips.com/viewthread.cfm?qid=1613334>
and
<https://www.youtube.com/watch?v=X_UaulmICtM&list=TLPQMTUwMjIwMjMRAYZJzCsXDQ&index=6>
specifically: at crystal report
TH1: Fomula fields/new/"nameabc"/enter/"Roman(GroupNumber)"/ ctrl+S/and pull it out
TH2: Fomula fields/new/"nameabc"/enter/
select GroupNumber
case 1 : " I"
case 2 : " II"
case 3 : " III"
case 4 : " IV"
case 5 : " V"
case 6 : " VI"
case 7 : " VII"
case 8 : "VIII"
case 9 : " IX"
case 10 : " X"
case 11 : " XI"
case 12 : " XII"
case 13 : "XIII"
case 14 : " XIV"
case 15 : " XV"
case 16 : " XVI"
case 17 : "XVII"
default : ""
/ ctrl+S/and pull it out
But it really doesn't help t so there will be this 3 case (t improved from link 2-3) it can apply to the 3rd or even 10th group of headings
TH3: ex: (you want to create a text message for group 3)
Formula fields/new/"nameabc"/enter/
"
WHILEPRINTINGRECORDS;
GLOBAL NUMBERVAR INTSTTGRTEST;
INTSTTGRTEST :=0;
/ ctrl+S/ drag it out and put it in heading group 2 and hide it (= right click/format field/common/ check Suppress/ok) you can go to link 3 to see
Formula fields/new/"nameabcd"/enter/
"
WHILEPRINTINGRECORDS;
GLOBAL numbervar INTSTTGRTEST := INTSTTGRTEST + 1;
stringvar y;
STRINGVAR ARRAY X := ["A","B","C","D","E","F","G","H","I","J","K", "L","M","N","O","P","Q","R","S","T","U","V","W","X ","Y","Z"];
if INTSTTGRTEST <= 26 then (
redim preserve X[INTSTTGRTEST];
y := X[INTSTTGRTEST]
);
y;
/ ctrl+S/and pull it out and place it at group 3
and the alphabet can be whatever we want. ex:
X := ["I","II","III","IV","V","VI","VII","VIII","IX","X","XI" ,"XII","XIII","XIV","XV","XVI","XVII","XVIII","XIX","XX","XXI","XXII","XXIII"," XXIV","XXV","XXVI","XXVII","XXVIII","XXIX","XXX","XXXI","XXXII","XXXIII","XXXIV","XXXV","XXXVI" ,"XXXVII","XXXVIII","XXXIX","XL","XLI","XLII","XLIII","XLIV","XLV","XLVI","XLVII","XLVIII"," XLIX","L"];
or
X := ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"];
hope it can help you
enter code here [1]: https://i.stack.imgur.com/OeBBQ.png