How to use Word in TOleContainer in TForm properly, layout-wise?
Subform is a correct way to do it. We used this approach in a production environment and it worked. We hosted our "sub" form in a panel. However, we modified TOleContainer and TOleForm with a flag whether to use the parent form, or the topmost form:
procedure TOurOleContainer.InitObject;
...
begin
if FDrawInTopForm then
DocForm := GetParentForm(Self)
else
DocForm := TCustomForm(Parent);
...
Where FDrawInTopForm is a property we introduced. We also modified:
function GetVCLFrameForm(Form: TCustomForm; DrawInTopForm: Boolean): IVCLFrameForm;
begin
if Form.OleFormObject = nil then TOleForm.Create(Form, DrawInTopForm);
Result := Form.OleFormObject as IVCLFrameForm;
end;
Unfortunately, due to agreements with the customer, I cannot post the complete solution here.
SOUser
Updated on June 28, 2022Comments
-
SOUser almost 2 years
I wonder what is the suggested way to embed and control MS Word in a TForm, layout-wise? Currently, I (1) put two TPanel on TForm. The
alBottom
TPanel has one TButton, and thealClient
TPanel has aalNone
TOleContainer. (2) set up the layout in TMainForm.FormCreate event handler.The problem is MS Word likes to take up all the space of its parent form. Only the fourth way as shown below seems to give acceptable layout. Based on trial-and-error, it seems necessary to use a sub-form instead of TPanel to host TOleContainer. (Also, Windows.SetParent seems necessary.) I wonder whether a sub-form is the correct way to go?
PS: Delphi XE, Word 2010, Windows 7
PS: web pages related to "hosting external applications":
How to shell to another app and have it appear in a delphi form
PS: web pages related to "Form in Panel (sub-form)":
how to make a transparent form inside Panel?
Delphi - OleContainer - PowerPoint - AutoPlay
sample code
unit uMainForm; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, OleCtnrs, ExtCtrls, StdCtrls; type TMainForm = class(TForm) PanelOle: TPanel; PanelBtn: TPanel; OleContainer1: TOleContainer; Button1: TButton; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end; var MainForm: TMainForm; implementation {$R *.dfm} procedure TMainForm.FormCreate(Sender: TObject); var OleForm: TForm; begin //// //// 1 //// // OleContainer1.Parent := PanelOle; // OleContainer1.Align := alClient; // //// //// 2 //// // Windows.SetParent(OleContainer1.Handle, PanelOle.Handle); // OleContainer1.Align := alClient; // //// //// 3 //// // OleForm := TForm.Create(Self); // OleForm.Parent := PanelOle; // OleForm.Align := alClient; // OleForm.Visible := True; // OleContainer1.Parent := OleForm; // OleContainer1.Align := alClient; // //// //// 4 Works! //// // OleForm := TForm.Create(Self); // Windows.SetParent(OleForm.Handle, PanelOle.Handle); // OleForm.Align := alClient; // OleForm.Visible := True; // OleContainer1.Parent := OleForm; // OleContainer1.Align := alClient; // //// //// 5 //// // OleForm := TForm.Create(Self); // OleForm.Parent := PanelOle; // OleForm.Align := alClient; // OleForm.Visible := True; // Windows.SetParent(OleContainer1.Handle,OleForm.Handle); // OleContainer1.Align := alClient; // //// //// 6 //// // OleForm := TForm.Create(Self); // Windows.SetParent(OleForm.Handle, PanelOle.Handle); // OleForm.Align := alClient; // OleForm.Visible := True; // Windows.SetParent(OleContainer1.Handle,OleForm.Handle); // OleContainer1.Align := alClient; end; procedure TMainForm.Button1Click(Sender: TObject); var // Declare the item to be a generic OleVariant to force late binding Ds: OleVariant; D: OleVariant; begin OleContainer1.CreateObjectFromFile('sample.docx', False); OleContainer1.Run; OleContainer1.AutoActivate := aaManual; OleContainer1.DoVerb(ovShow); // not in FormCreate, in or after FormShow Ds := OleContainer1.OleObject.Application.Documents; Caption := IntToStr(Ds.Count); end; end.