Indenting bullets - delphi

It is not bad enough that I am so new to programming; This week I have done more Google searching and less Google finding than I have ever before.
Delphi v7
I have figured out how to create bullets in my richedit control. What I can't find out is how to indent them when the user creates them.
Any ideas?

Set the TRichEdit.Paragraph.FirstIndent. The bullets will be indented by the additional amount of FirstIndent. (You use FirstIndent because a bullet item is the first line of a new paragraph.)
RichEdit1.Paragraph.FirstIndent := RichEdit1.Paragraph.FirstIndent + 10;
Here's a quick demo based on the RichEdit demo that's shipped with Delphi for years. I simply added two new TToolButtons to the ToolBar (the two right-most buttons, named tbLessIndent and tbMoreIndent respectively, with glyphs from the GlyFx images supplied with Delphi), and added the following event handlers to the existing form as the ToolButton.OnClick events:
procedure TMainForm.tbLessIndentClick(Sender: TObject);
begin
Editor.Paragraph.FirstIndent := Editor.Paragraph.FirstIndent - 10;
tbLessIndent.Enabled := Editor.Paragraph.FirstIndent > 9;
end;
procedure TMainForm.tbMoreIndentClick(Sender: TObject);
begin
Editor.Paragraph.FirstIndent := Editor.Paragraph.FirstIndent + 10;
tbLessIndent.Enabled := True;
end;
Here's a sample new document with a few items added:
For more info, see the documentation on Numbering and FirstIndent (XE2 docs, but they're about the same)

Related

problem with reset series points in teechart pro Delphi

I use Teechart pro VCL v2018.24.18 32bit.
I wrote some code that plots a chart from input data, which the user can save in a file or DB.
I have one problem, however. This process may be repeated several times, and I need create a new project. I reset the series value before receiving new input data:
if DbChart1.SeriesCount <> 0 then // clear all series data
begin
for dp := 0 to DbChart1.SeriesCount-1 do
begin
DbChart1.Series[dp].Clear;
DbChart1.Series[dp].XValues.FillSequence;
DbChart1.Series[dp].YValues.FillSequence;
dbchart1.Series[dp].CleanupInstance;
end;
end;
Dbchart1.BottomWall.EndPosition := 0;
Dbchart1.LeftWall.EndPosition := 0;
Dbchart1.DepthAxis.Maximum := 0;
All series points have been removed except the last point!
I want the serial to be clean, like the first time the program ran. How do I do this?
problem solved. the last point in series do not remove ( why ? maybe a Bug ).at the first i use another codes for remove points but problem not solved. look at this codes :
With Dbchart1.Series[0] Do
Begin
dec:=series0.Count;
if dec<>0 then
begin
Series0.Delete(0,dec,true);
end;
End;
but with repeat the codes the problem solved :
With Dbchart1.Series[0] Do
Begin
dec:=series0.Count;
label44.Caption := inttostr(dec);
if dec<>0 then
begin
Series0.Delete(0,dec,true);
dec:=series0.Count;
Series0.Delete(0,dec,true);
end;
End;

How do I insert new, unformatted, lines at the top of a TRichEdit

I am using TRichEdit to hold the body of an emailing client. I've given the user simple formatting capabilities (bold, italic, underline, left, centre and right paragraph alignment and bullets. This works well to email formatted text as html using Indy following Remy's code here.
I extract the TRichEdit text as html using
function GetHTML(RichEdit:TRichEdit): string;
var
htmlstrings : Tstringlist;
JvRichEditToHtml1 :TJvRichEditToHtml;
begin
htmlstrings := Tstringlist.create;
JvRichEditToHtml1 := TJvRichEditToHtml.create(nil);
try
JvRichEditToHtml1.ConvertToHtmlStrings(RichEdit,htmlstrings);
result := htmlstrings.Text;
finally
htmlstrings.free ;
JvRichEditToHtml1.free;
end;
end;
Just before I send the email I use code to insert a salutation string as a new top line in the TRichEdit, followed by two blank lines. This is used by the email system to personalise the email and also works well.
The problem is that if the user formats the first lines of their body text when they enter it, for example suppose they make the first few lines a bulleted list, then the salutation line I add under code is also shown bulleted when the email arrives.
How can I use code to insert a line at the top of a TRichEdit with no paragraph or font formatting and yet preserve any formatting that the user might have applied to (what was) the first lines of their manual input?
The code I am using at the moment to insert my salutation string is below but my salutation still gets the formatting style that the user applies. (Originally I only had the three insert lines but added the other code following ideas in a similar question here ). Identifiers in upper case are constants defined elsewhere.
procedure AddRecipientVarableToBody( var Body: TRichEdit);
begin
//remove formatting from the (new) first paragraph
Thebody.Paragraph.Numbering := nsnone;
Thebody.Paragraph.Alignment := taLeftJustify;
//add the three new top lines (two blank plus a recipient)
//done backwards as we insert a new line zero each time
TheBody.lines.Insert(0,EMPTY_STRING); // two blank lines
TheBody.lines.Insert(0,EMPTY_STRING);
TheBody.lines.Insert(0,'To: ' + RECIPIENT_VARIABLE_SALUTATION);
//Remove any formatting from first three lines
TheBody.SelStart:=0;
TheBody.SelLength:= length(TheBody.Lines[0]) + length(TheBody.Lines[1]) + length(TheBody.Lines[2]);
TheBody.SelAttributes.Style := [];
end;
Addendum:
I managed a workaround to get the result I wanted by delaying the salutation insertion until I set up the parameters ready to pass to Indy and appending the entire TRichEdit HTML to a simple text string ie
instead of
Params.Add('html=' + GetHTML(body));
I used
Params.Add('html=' + 'To: ' + RECIPIENT_VARIABLE_SALUTATION + GetHTML(body));
where body is the TRichEdit.
However, I'd still like to know if my prioblem can be solved through the insertion of new lines into the TRichEdit directly.
You can define DefAttributes for your RichEdit. Then you can easily return to use this setup simply by
RE.SelAttributes := RE.DefAttributes;
So, here's a test of your situation. First defining the DefAttributes, e.g. in OnFormCreate():
procedure TForm1.FormCreate(Sender: TObject);
begin
// Initialize to what you want to return to, or use as default
RE.DefAttributes.Charset := ANSI_CHARSET;
RE.DefAttributes.Color := clBlack;
RE.DefAttributes.Height := -16;
RE.DefAttributes.Name := 'Segoe UI';
RE.DefAttributes.Size := 12;
RE.DefAttributes.Style := [];
end;
Note that above doesn't deal with bullets, they are handled separately.
In following code we simulate what a user might have written ...
procedure TForm1.Button1Click(Sender: TObject);
begin
RE.Lines.Add('Final reminder');
RE.Lines.Add('Please, fill the form below, and send it immediately.');
RE.SelStart := 0;
RE.SelLength := Length(RE.Lines[0]);
RE.SelAttributes.Color := clRed;
RE.SelAttributes.Name := 'Algerian';
RE.SelAttributes.Size := 15;
RE.SelStart := Length(RE.Lines[0]);
RE.SelLength := Length(RE.Lines[1]);
RE.SelAttributes := RE.DefAttributes;
end;
... and what special attributes, Bold, Italic, Underline and Strikeout they might have added as well as a bullet for the first line. These are added with buttons in my test form.
Finally how to add the three lines to the beginning and assure an independent formatting.
procedure AltAddRecipientVarableToBody( var RE: TRichEdit);
begin
RE.lines.Insert(0,EMPTY_STRING); // two blank lines
RE.lines.Insert(0,EMPTY_STRING);
RE.lines.Insert(0,'To: ' + RECIPIENT_VARIABLE_SALUTATION);
// Select
RE.SelStart := 0;
RE.SelLength:= length(RE.Lines[0]) + 1
+ length(RE.Lines[1]) + 1
+ length(RE.Lines[2]) + 1;
// Clear attributes
RE.SelAttributes := RE.DefAttributes;
// Clear bullets
RE.Paragraph.Numbering := nsNone;
end;
The addition of 1 char per line is for the new line characters.
Note that, since bullets are properties of paragraphs, they can not be defined in DefAttributes and must be dealt with separately.
And the result, with the three added lines formatted with DefAttributes and the original text maintaining whatever formatting it had.

How to Change "Table Positioning" in the table properties Inside a MS Word Document Using Delphi XE5

I apologize in advance, This is very confusing to explain. Please assist in making it clearer if need be.
I am working with a MS Word document that i generate from code using the following code. The document has 1 table with a bunch of rows and columns that i intend to populate.
wrdDoc.Tables.Add(wrdSelection.Range,9,2);
wrdDoc.tables.Item(1).Rows.Alignment := wdAlignRowLeft;
wrdDoc.Tables.Item(1).Columns.Item(1).SetWidth(155,wdAdjustNone);
wrdDoc.Tables.Item(1).Columns.Item(2).SetWidth(299,wdAdjustNone);
wrdDoc.tables.Item(1).Borders.Item(wdBorderLeft).LineStyle := wdLineStyleSingle;
wrdDoc.tables.Item(1).Borders.Item(wdBorderRight).LineStyle := wdLineStyleSingle;
wrdDoc.tables.Item(1).Borders.Item(wdBorderVertical).LineStyle := wdLineStyleSingle;
wrdDoc.tables.Item(1).Borders.Item(wdBorderTop).LineStyle := wdLineStyleSingle;
wrdDoc.tables.Item(1).Borders.Item(wdBorderBottom).LineStyle := wdLineStyleSingle;
wrdDoc.tables.Item(1).Borders.Item(wdBorderHorizontal).LineStyle := wdLineStyleSingle;
Basically what i am trying to do is change the following values:
Right Click on the table->Table Properties->Table Tab
Text Wrapping = Around
->Positioning->Horizontal:
Position = -0.18"
Relative To = Margin
->Positioning->Vertical:
Position = -0.63"
Relative To = Paragraph
->Positioning->Options:
Move With Text = True
Allow Overlap = True
I have not been able to find any code to assist me. Or even any Code samples that handle changing the text wrapping to around using code in Delphi. So any assistance would be great.
Thank You
The following code does what you asked using D7 and Word2007.
You don't say whether your unit already uses one of the Delphi import units for the MS Word type libraries. You'll need to use one, because that's where the constants like wdTableLeft are defined. I'm using D7 (+Word 2007), so I used the Word2000 import unit that came with D7.
Also my Table and TablesRows are OleVariants which you'll need to add to your code if you don't declare them already.
First thing is that you'll need to add some code above your procedure which creates the table. The reason for this is explained below.
const
CmToPostScriptPoints : Single = 28.3464567;
InchesToCm : Single = 2.54;
function CentimetersToPoints(Centimeters : Single) : Single;
begin
Result := CmToPostScriptPoints * Centimeters;
end;
Then replace the code in your q by the following. Please read the embedded comments carefully because they explain a couple of problems I ran into which took a long time to figure out.
Table := wrdDoc.Tables.Add(wrdSelection.Range, 9, 2);
TableRows := Table.Rows;
TableRows.WrapAroundText := True;
// TableRows.MoveWithText := True;
// Note: If you un-comment the line above it will cause an exception
// Method "MoveWithText" not supported by automation object
// However, even with MoveWithText commented out, the corresponding property
// in Word's table properties will still be ticked by the time the code is finished
TableRows.AllowOverlap := True;
Table.Rows.Alignment := wdAlignRowLeft;
Table.Columns.Item(1).SetWidth(155,wdAdjustNone);
Table.Columns.Item(2).SetWidth(299,wdAdjustNone);
Table.Borders.Item(wdBorderLeft).LineStyle := wdLineStyleSingle;
Table.Borders.Item(wdBorderRight).LineStyle := wdLineStyleSingle;
Table.Borders.Item(wdBorderVertical).LineStyle := wdLineStyleSingle;
Table.Borders.Item(wdBorderTop).LineStyle := wdLineStyleSingle;
Table.Borders.Item(wdBorderBottom).LineStyle := wdLineStyleSingle;
Table.Borders.Item(wdBorderHorizontal).LineStyle := wdLineStyleSingle;
TableRows.RelativeHorizontalPosition := wdRelativeHorizontalPositionMargin;
TableRows.RelativeVerticalPosition := wdRelativeVerticalPositionParagraph;
TableRows.HorizontalPosition := CentimetersToPoints(-0.18 * InchesToCm) ;
// Note : At first, I thought the line above didn't do anything because
// after this routine finishes, the HorizontalPosition in Word
// under TableProperties | Positioning is shown as Left.
//
// However, if you put a breakpoint on the line above,
// and single-step past it, you should see the table shift leftwards
// when the line is executed. The ShowMessage should display - 0.179[...]
ShowMessage(FloatToStr(TableRows.HorizontalPosition / 72)); // 72 PostScript points to an inch
TableRows.VerticalPosition := CentimetersToPoints(-0.63 * InchesToCm);
The reason I've defined a CentimetersToPoints function rather than the Word Application's CentimetersToPoints is that there seems there is a long-standing problem with trying to call CentimetersToPoints from Delphi code - if you're interested, see this SO q and its comments to the answer:
Unspecified error when calling Word CentimetersToPoints via OLE

Is there any way to disable selecting of text in a memo control?

Is there any way to disable selecting of text in a memo control because it's very anoying.
The memo is Read Only.
I think you should rethink. I realise that your control is used in read-only mode, but still, what if the end user wishes to copy a part of the text? Then he needs to be able to select the part in question.
Still, if you are certain that you need to disable every kind of selection, the easiest approach is to use a TRichEdit instead of the TMemo, and do simply
procedure TForm1.RichEdit1SelectionChange(Sender: TObject);
begin
RichEdit1.SelLength := 0;
end;
You could also use the onMouseUp event
procedure TForm1.Memo1MouseUp(Sender: TObject: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
if Memo1.SelLength > 0 then
Memo1.SelLength := 0;
end;
But, that doesn't stop selecting with the keyboard..
or you could also use the onEnter, and just change the focus to another control on your form.
procedure TForm1.Memo1Enter(Sender: TObject);
begin
Edit1.SetFocus;
end;
I played around with TRichEdit and TMemo until I was bored to tears. Yes, you can do a few tricks with event handling on the object, but it still is not the desired effect - and the cursor winds up blinking somewhere. So the best thing I could find was to use TLabel. I'm using Borland C++ Builder 6, and the \n is translated correctly with inline text strings for TLabel. So,
Label1->Caption = "this is a test of the emergency\n"
"broadcast station, this is only\n"
"a test. If this had been an\n"
"actual emergency, blah blah blah...\n";
Works just fine. I haven't tried to read in from a file, but I'm certain that if the stream were exactly as seen it would also work. Since you are going to have to enter or read in the text you want displayed anyway - this should work well instead of using a bunch of TLabels for each line. If you have a concern for word wrapping, you will have to process that portion separately. If it static, then just do it by hand like I did in the example. I sure hope this helps or at least gives an idea...
atomkey -
As i understand you would like to use memo as label actually (and sometimes it really have sense).
When i need to use TcxMemo (memo component from DeveloperExpress) as label i use such simple procedure:
procedure ShowMemoAsLabel(m: TcxMemo);
begin
m.Enabled := False;
m.Properties.ReadOnly := True;
// AH: Unfortunately it doesn't copy some important properties, maybe it will
// be fixed in future versions of DEX, but at moment we do some job ourselves.
m.StyleDisabled := m.Style;
m.StyleDisabled.BorderColor := m.Style.BorderColor;
m.StyleDisabled.BorderStyle := m.Style.BorderStyle;
m.StyleDisabled.Color := m.Style.Color;
m.StyleDisabled.Edges := m.Style.Edges;
m.StyleDisabled.Shadow := m.Style.Shadow;
m.StyleDisabled.TextColor := m.Style.TextColor;
m.StyleDisabled.TextStyle := m.Style.TextStyle;
m.StyleDisabled.TransparentBorder := m.Style.TransparentBorder;
end;

Create an exact copy of TPanel on Delphi5

I have a TPanel pnlMain, where several dynamic TPanels are created (and pnlMain is their Parent) according to user actions, data validations, etc. Every panel contains one colored grid full of strings. Apart from panels, there are some open source arrows components and a picture. Whole bunch of stuff.
Now I want user to be able to print this panel (I asked how to do it on this question), but before printing, user must be presented with a new form, containing copy of pnlMain. On this form user has to do some changes, add few components and then print his customized copy of pnlMain. After printing user will close this form and return to original form with original pnlMain. And – as you can guess – original pnlMain must remain intact.
So is there any clever way to copy whole TPanel and it’s contents? I know I can make it manually iterating through pnlMain.Controls list.
Code based as iterating on child controls, but not bad in anyway ;-)
procedure TForm1.btn1Click(Sender: TObject);
function CloneComponent(AAncestor: TComponent): TComponent;
var
XMemoryStream: TMemoryStream;
XTempName: string;
begin
Result:=nil;
if not Assigned(AAncestor) then
exit;
XMemoryStream:=TMemoryStream.Create;
try
XTempName:=AAncestor.Name;
AAncestor.Name:='clone_' + XTempName;
XMemoryStream.WriteComponent(AAncestor);
AAncestor.Name:=XTempName;
XMemoryStream.Position:=0;
Result:=TComponentClass(AAncestor.ClassType).Create(AAncestor.Owner);
if AAncestor is TControl then TControl(Result).Parent:=TControl(AAncestor).Parent;
XMemoryStream.ReadComponent(Result);
finally
XMemoryStream.Free;
end;
end;
var
aPanel: TPanel;
Ctrl, Ctrl_: TComponent;
i: integer;
begin
//handle the Control (here Panel1) itself first
TComponent(aPanel) := CloneComponent(pnl1);
with aPanel do
begin
Left := 400;
Top := 80;
end;
//now handle the childcontrols
for i:= 0 to pnl1.ControlCount-1 do begin
Ctrl := TComponent(pnl1.Controls[i]);
Ctrl_ := CloneComponent(Ctrl);
TControl(Ctrl_).Parent := aPanel;
TControl(Ctrl_).Left := TControl(Ctrl).Left;
TControl(Ctrl_).top := TControl(Ctrl).top;
end;
end;
code from Delphi3000 article
Too much code... ObjectBinaryToText and ObjectTextToBinary do the job nicely using streaming.
Delphi 7 have a code example, don't know 2009 (or 2006, never bothered to look) still have it.
See D5 help file for those functions (don't have d5 available here).
I'd do it by using RTTI to copy all the properties. You'd still have to iterate over all the controls, but when you need to set up the property values, RTTI can help automate the process. You can get an example towards the bottom of this article, where you'll find a link to some helper code, including a CopyObject routine.

Resources