How to align paragraph using Delphi MSWord automation? - delphi

I want to align a text to center and I have no idea on how to achieve it.
Here is my code:
try
MsWord := GetActiveOleObject('Word.Application');
except
try
MsWord := CreateOleObject('Word.Application');
MsWord.Visible := True;
except
Exception.Create('Error');
end;
end;
MSWord.Documents.Add;
MSWord.Selection.Font.Size := 22;
MSWord.Selection.Font.Bold := true;
MSWord.Selection.TypeText(#13#10);
MSWord.Selection.TypeText('I want this to be center-aligned');
...
MSWord.ActiveDocument.SaveAs('C:\doc2.doc');
Please help.
Thanks

This works for me:
procedure TForm1.Button1Click(Sender: TObject);
var
MSWord : OleVariant;
begin
try
MsWord := GetActiveOleObject('Word.Application');
except
try
MsWord := CreateOleObject('Word.Application');
MsWord.Visible := True;
except
Exception.Create('Error');
end;
end;
MSWord.Documents.Add;
MSWord.Selection.Font.Size := 22;
MSWord.Selection.Font.Bold := true;
MSWord.Selection.TypeText(#13#10);
MSWord.Selection.TypeText('I want this to be center-aligned');
MSWord.Selection.ParagraphFormat.Alignment := wdAlignParagraphCenter;
MSWord.ActiveDocument.SaveAs('C:\doc2.doc');
end;
Btw, the way to find the answer yourself is to go into Word, start recording a macro, perform the action, stop recording then edit the macro to see what code Word generates. Converting that to Delphi is usually fairly trivial if you're using late binding (accessing Word from Delphi via an OleVariant) but can be a bit long winded if you're using early binding, because early binding requires all parameters to be specified, whereas late binding lets you leave most of them out.

Related

Reading Word-file (*.dot) from program resources

Have a set of Word-templates (files *.dot) and a little program, which create new files base on that templates. It's works fine, but the goal is to make all in one exe-file.
I see the solution is to move templates files into program resources. But I don't know, how then I will read them from resources. Tell me, please, how to do this.
Maybe you can advise me another solution.
Now, my code is:
procedure TfmMain.CreateDocument0;
var
TempleateFileName: string;
WordApp, Document: OleVariant;
procedure FillBookmark(BookmarkName, bText: string);
var
Range: OleVariant;
begin
if Document.Bookmarks.Exists(BookmarkName) then
begin
Range := Document.Bookmarks.Item(BookmarkName).Range;
Range.Text := bText;
end;
end;
begin
TempleateFileName := ExtractFilePath(Application.ExeName)+'Templates\0.dot';
try
WordApp := GetActiveOleObject('Word.Application');
except
try
WordApp := CreateOleObject('Word.Application');
except
on E: Exception do
begin
MessageBox(Self.Handle, PChar(E.Message), PChar(fmMain.Caption), MB_OK+MB_ICONERROR);
Exit;
end;
end;
end;
try
Document := WordApp.Documents.Add(TempleateFileName, False);
FillBookmark('ObjectType', edt0ObjectType.Text);
...
WordApp.Visible := True;
WordApp.Activate;
finally
WordApp := Unassigned;
end;
end;
That is, I should change this line:
Document := WordApp.Documents.Add(TempleateFileName, False);
Read not from file, but from program resource.
Word cannot open documents from memory. Not only does it not have such a feature, you must also bear in mind that Word executes in a separate process. It cannot see the memory in your process, even if it were able to open documents from memory.
If you do put the documents into linked resources then you will need to extract them to file before asking Word to open them.

TDirectoryWatch not firing first time

I have a small application that is used to process some files made in another program.
I use an older component by Angus Johnson called TDirectoryWatch
On my FormCreate I have the following code
DirectoryWatch := TDirectoryWatch.Create(self);
DirectoryWatch.OnChange := FileAction;
DirectoryWatch.Directory := Folders.Path(dirInput);
DirectoryWatch.Active := True;
If the program is started and there is put a new file in the directory everything fires and runs OK.
But if there is a file in the directory when the program is started nothing happens even if I make a call to FileAction(nil);
FileAction is the name of the procedure that handles the files
I have a call to FileAction from a popupmenu and that handles the files in the directory
So my question is: how to make sure that existing files are handled at program start?
Or is there a better way to handle this problem.
Added code for FileAction
procedure TfrmMain.FileAction(Sender: TObject);
var
MailFile: string;
MailInfo: TMailInfo;
ListAttachments: TstringList;
i: integer;
MailBody: string;
begin
for MailFile in TDirectory.GetFiles(Folders.Path(dirInput), CheckType) do
begin
if FileExists(MailFile) then
begin
MailInfo := TMailInfo.Create(MailFile);
try
if FileProcessing = False then
begin
Logfile.Event('Behandler fil: ' + MailFile);
FileProcessing := True;
MailBody := '';
Settings.Load;
MailInfo.Load;
Settings.Mail.Signature := '';
Settings.Mail.Subject := MailInfo.Subject;
ListAttachments := TStringList.Create;
ListAttachments.Clear;
for i := 1 to MaxEntries do
begin
if (MailInfo.Attachment[i] <> '') and (FileExists(MailInfo.Attachment[i])) then
ListAttachments.Add(MailInfo.Attachment[i]);
end;
for i := 1 to MaxEntries do
begin
MailBody := MailBody + MailInfo.MailBody[i];
end;
try
if MailBody <> '' then
begin
if MailInfo.SenderBcc then
Mailing.Send(MailInfo.SenderMail, MailInfo.Recipient, MailInfo.SenderMail, MailInfo.Subject, MailBody, ListAttachments, True)
else
Mailing.Send(MailInfo.SenderMail, MailInfo.Recipient, MailInfo.Subject, MailBody, ListAttachments, True);
end;
finally
ListAttachments.Free;
end;
FileProcessing := False;
DeleteFile(MailFile);
end;
finally
MailInfo.Free;
end;
end;
end;
end;
The component doesn't notify about changes when your program starts up because at the time your program starts, there haven't been any changes yet.
Your policy appears to be that at the time your program starts up, all existing files are to be considered "new" or "newly changed," so your approach of manually calling the change-notification handler is correct.
The only thing the component does when it detects a change is to call the change-notification handler. If you explicitly call that function, and yet you still observe that "nothing happens," then there are more deep-seated problems in your program that you need to debug; it's not an issue with the component or with the basic approach described here.

Programmatically adding columns to a TdxDBGrid (Expressquantumgrid by Devexpress)

With a customer I'm stuck developing for this very old version (2.1) of ExpressQuantumGrid by DevExpress. In Delphi 4. I can't find any documentation about it.
Basically I just need to create a bunch of TdxDBGridMaskColumn and "insert" them into the grid (TdxDBGrid) at runtime. From the code completion pop-up I can't figure out how.
Thanks!
We have an old app that uses Delphi 5 and DevExpress v3, the code might not be identical but should get you started.
A function that can create a column of any type (TdxDBDateColumn for example):
function CreateColumn(const aField: string; aColClass: TdxDBTreeListColumnClass): TdxDBTreeListColumn;
var
begin
Result := dxGrid.CreateColumn(aColClass);
Result.Name := dxGrid.Name + aField;
TdxDBGridColumn(Result).DisableFilter := True;
TdxDBGridColumn(Result).DisableGrouping := True;
TdxDBGridColumn(Result).Alignment := taRightJustify;
TdxDBGridColumn(Result).FieldName := aField;
TdxDBGridColumn(Result).Caption := aField;
TdxDBGridColumn(Result).Width := 70;
end;
Then you can call this function like so:
NewColumn := CreateColumn('Username', TdxDBGridColumn);

Adding a checkbox to cxGridDBColumn (DateEdit)

I using Delphi BDS 2006 and have a DevExpress cxGridDBColumn with properties set to DateEdit and was wondering whether it is possible to add a checkbox to the displayed date time picker popup?
I am not sure that I understand what you wish to achieve. Anyway, it is impossible without creating a custom cxEditor which supports this look&feel and desired functionality.
Here is a quick hack which should help you implement this feature. However, you should handle the checkBox yourself. I have done this for the standalone editor, however, the same approach will work with the inplace editor:
procedure TForm1.cxDateEdit1PropertiesPopup(Sender: TObject);
var
AEdit: TcxDateEdit;
ACalendar: TcxPopupCalendar;
ACheckBox: TcxCheckBox;
begin
AEdit := TcxDateEdit(Sender);
if AEdit.Tag <> 1 then
begin
AEdit.Tag := 1;
ACalendar := TcxPopupCalendar(AEdit.Properties.PopupControl);
ACheckBox := TcxCheckBox.Create(Self);
ACheckBox.Parent := ACalendar.Parent;
ACheckBox.Align := alBottom;
ACheckBox.Transparent := True;
ACalendar.Parent.Height := ACalendar.Parent.Height + ACheckBox.Height;
end;
end;

StringBuilder.Split in Delphi?

Anyone know of a good Split procedure that uses StringBuilder in Delphi?
You might be better off using TStringlist.DelimitedText (or any other non-abstract TStrings sub-class). It's more of the traditional Delphi way of achieving what string.Split does in .Net (assuming I remember correctly).
e.g. To split on a pipe | character
var
SL : TStrings;
i : integer;
begin
SL := TStringList.Create;
try
SL.Delimiter := '|';
SL.StrictDelimiter := True;
SL.DelimitedText := S;
for i := SL.Count - 1 do
begin
// do whatever with sl[i];
end;
finally
SL.Free;
end;
end;
You may need to handle the QuoteChar property as well
You can also Look at my answer to this question for a general purpose utility functions GetStringPart and NumStringParts that allow you to perform split type operations.

Resources