Articles   Members Online:
-Article/Tip Search
-News Group Search over 21 Million news group articles.
-Delphi/Pascal
-CBuilder/C++
-C#Builder/C#
-JBuilder/Java
-Kylix
Member Area
-Home
-Account Center
-Top 10 NEW!!
-Submit Article/Tip
-Forums Upgraded!!
-My Articles
-Edit Information
-Login/Logout
-Become a Member
-Why sign up!
-Newsletter
-Chat Online!
-Indexes NEW!!
Employment
-Build your resume
-Find a job
-Post a job
-Resume Search
Contacts
-Contacts
-Feedbacks
-Link to us
-Privacy/Disclaimer
Embarcadero
Visit Embarcadero
Embarcadero Community
JEDI
Links
How to use a TPanel as a host for child windows (MDI simulation) Turn on/off line numbers in source code. Switch to Orginial background IDE or DSP color Comment or reply to this aritlce/tip for discussion. Bookmark this article to my favorite article(s). Print this article
28-Oct-02
Category
Others
Language
Delphi 2.x
Views
88
User Rating
No Votes
# Votes
0
Replies
0
Publisher:
DSP, Administrator
Reference URL:
DKB
			Author: Jonas Bilinkevicius

I was wondering if someone can offer assistance with this application. Basically 
the application is for configuring our system. At present it is a MDI where child 
windows are various functions (security, report options, etc.). The number of 
functions are growing, currently around 15, which means an increase in different 
child forms and, overall, a growing exe. I would like the child forms to be 
standalone programs or dlls which can appear in the control program as child 
windows and also execute by themselves. Only one child form is displayed at a time 
and always maximised within the parent window. I did see some code about that 
provided for a dll as a child form, but this would not help as a standalone 
execution.

Answer:

This is an interesting problem. As it happens it is possible in Win32 to make 
another processes window appear like a child window in ones own windows. It does 
not work quite as well as a true child in your own process but takes care about 
moving the pseudo-child with your menu app.

The general design is this: the main/menu app has a form with menu, perhaps tool 
and status bars, and a client-aligned panel that will serve as the host for the 
child windows. It reads the available child apps from INI file or registry key and 
builds a menu or selection list from this info. On user request it launches the 
appropriate child app and passes the panels window handle on the commandline. The 
child app checks the command line, if there are no parameters it rans as designed, 
if there is a parameter it reads it, removes its border and bordericon, parents 
itself to the passed window handle and sizes itself to its client area. It also 
sends a message with *its* window handle to the panels parent (the main app form) 
to register itself. The main app can close the child with this handle and also 
resize it when the user resizes the main app.

Main app: has a menu with two entries (OpenMenu, CloseMenu), a toolbar with two 
buttons attached to the same events as the two menus, a statusbar, a client-aliged 
panel.

1   unit MenuApp;
2   
3   interface
4   
5   uses
6     Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
7     Menus, ExtCtrls, ComCtrls, ToolWin;
8   
9   const
10    UM_CHILDREGISTER = WM_USER + 111;
11    UM_CHILDUNREGISTER = WM_USER + 112;
12  
13  type
14    TUmChildRegister = packed record
15      msg: Cardinal;
16      childwnd: HWND;
17      unused: Integer;
18      result: Integer;
19    end;
20    TUmChildUnregister = TUmChildregister;
21  
22    TForm1 = class(TForm)
23      MainMenu1: TMainMenu;
24      OpenMenu: TMenuItem;
25      StatusBar1: TStatusBar;
26      ToolBar1: TToolBar;
27      ToolButton1: TToolButton;
28      CloseMenu: TMenuItem;
29      ToolButton2: TToolButton;
30      Panel1: TPanel;
31      procedure OpenMenuClick(Sender: TObject);
32      procedure CloseMenuClick(Sender: TObject);
33      procedure Panel1Resize(Sender: TObject);
34      procedure FormClose(Sender: TObject; var Action: TCloseAction);
35    private
36      { Private declarations }
37      FChildAppHandle: HWND;
38      procedure UMChildRegister(var msg: TUmChildRegister);
39        message UM_CHILDREGISTER;
40      procedure UMChildUnRegister(var msg: TUmChildUnRegister);
41        message UM_CHILDUNREGISTER;
42    public
43      { Public declarations }
44    end;
45  
46  var
47    Form1: TForm1;
48  
49  implementation
50  
51  uses
52    shellapi;
53  
54  {$R *.DFM}
55  
56  procedure TForm1.OpenMenuClick(Sender: TObject);
57  var
58    path, param: string;
59  begin
60    if FChildAppHandle = 0 then
61    begin
62      path := ExtractFilePath(Application.Exename) + 'childAppProj.exe';
63      param := '$' + IntTohex(panel1.handle, 8);
64      ShellExecute(handle, 'open', pchar(path), pchar(param), nil, SW_SHOWNORMAL);
65    end
66    else
67      ShowMessage('Child already loaded');
68  end;
69  
70  procedure TForm1.CloseMenuClick(Sender: TObject);
71  begin
72    if FChildAppHandle <> 0 then
73      SendMessage(FchildApphandle, WM_CLOSE, 0, 0);
74  end;
75  
76  procedure TForm1.Panel1Resize(Sender: TObject);
77  begin
78    if FChildAppHandle <> 0 then
79      MoveWindow(FchildAppHandle, 0, 0, Panel1.ClientWidth, Panel1.ClientHeight, 
80  true);
81  end;
82  
83  procedure TForm1.UMChildRegister(var msg: TUmChildRegister);
84  begin
85    FChildAppHandle := msg.childwnd;
86  end;
87  
88  procedure TForm1.UMChildUnRegister(var msg: TUmChildUnRegister);
89  begin
90    if FChildAppHandle = msg.childwnd then
91      FChildAppHandle := 0;
92  end;
93  
94  procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
95  begin
96    if FChildAppHandle <> 0 then
97      SendMessage(FchildApphandle, WM_CLOSE, 0, 0);
98  end;
99  
100 end.
101 
102 //Child app has a couple of edits, two buttons, a memo.
103 
104 unit ChildApp;
105 
106 interface
107 
108 uses
109   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
110   StdCtrls, AppEvnts;
111 
112 type
113   TForm2 = class(TForm)
114     Edit1: TEdit;
115     Edit2: TEdit;
116     Edit3: TEdit;
117     Button1: TButton;
118     Memo1: TMemo;
119     Button2: TButton;
120     ApplicationEvents1: TApplicationEvents;
121     procedure Button1Click(Sender: TObject);
122     procedure ApplicationEvents1Activate(Sender: TObject);
123     procedure FormClose(Sender: TObject; var Action: TCloseAction);
124     procedure FormResize(Sender: TObject);
125   private
126     { Private declarations }
127     FMenuAppWnd: HWND;
128     FParentPanelWnd: HWND;
129   public
130     { Public declarations }
131     constructor Create(aOwner: TComponent); override;
132     procedure CreateWnd; override;
133     procedure DestroyWnd; override;
134   end;
135 
136 var
137   Form2: TForm2;
138 
139 implementation
140 
141 {$R *.DFM}
142 
143 const
144   UM_CHILDREGISTER = WM_USER + 111;
145   UM_CHILDUNREGISTER = WM_USER + 112;
146 
147 procedure TForm2.Button1Click(Sender: TObject);
148 begin
149   close;
150 end;
151 
152 procedure TForm2.ApplicationEvents1Activate(Sender: TObject);
153 begin
154   if FMenuAppWnd <> 0 then
155     SendMessage(FMenuAppWnd, WM_NCACTIVATE, 1, 0);
156   memo1.lines.add('Activated');
157 end;
158 
159 constructor TForm2.Create(aOwner: TComponent);
160 begin
161   if ParamCount > 0 then
162   begin
163     FParentPanelWnd := StrToInt(ParamStr(1));
164     FMenuAppWnd := Windows.GetParent(FParentPanelWnd);
165   end;
166   inherited;
167   if FParentPanelWnd <> 0 then
168   begin
169     Borderstyle := bsNone;
170     BorderIcons := [];
171     {remove taskbar button for the child app}
172     SetWindowLong(Application.Handle, GWL_EXSTYLE,
173       GetWindowLong(Application.Handle, GWL_EXSTYLE)
174       and not WS_EX_APPWINDOW or WS_EX_TOOLWINDOW);
175   end;
176 end;
177 
178 procedure TForm2.CreateWnd;
179 var
180   r: Trect;
181 begin
182   inherited;
183   if FMenuAppWnd <> 0 then
184   begin
185     SendMessage(FMenuAppWnd, UM_CHILDREGISTER, handle, 0);
186     Windows.SetPArent(handle, FParentPanelWnd);
187     Windows.GetClientRect(FParentPanelWnd, r);
188     SetBounds(r.left, r.top, r.right - r.left, r.bottom - r.top);
189   end;
190 end;
191 
192 procedure TForm2.DestroyWnd;
193 begin
194   if FMenuAppWnd <> 0 then
195     SendMessage(FMenuAppWnd, UM_CHILDUNREGISTER, handle, 0);
196   inherited;
197 end;
198 
199 procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
200 begin
201   {Closing the main form does not fire DestroyWnd for some reason}
202   if FMenuAppWnd <> 0 then
203     SendMessage(FMenuAppWnd, UM_CHILDUNREGISTER, handle, 0);
204 end;
205 
206 procedure TForm2.FormResize(Sender: TObject);
207 begin
208   memo1.width := clientwidth - memo1.Left - 10;
209   memo1.height := clientheight - memo1.Top - 10;
210 end;
211 
212 end.


One problem I noted is that sometimes the main applications caption will loose the active look when switching between main and child despite the action taken in the childs Application.OnActivate handler.

			
Vote: How useful do you find this Article/Tip?
Bad Excellent
1 2 3 4 5 6 7 8 9 10

 

Advertisement
Share this page
Advertisement
Download from Google

Copyright © Mendozi Enterprises LLC