Almost all official C Builder programs have the slave form in addition to the main window, sometimes the dialog, sometimes no mode window. VCL makes it easy to create and display the slave form. But not all programs are suitable for useless form, some programs need to display different content in one main window. This article discusses how to "resigniate" in the main form, which looks from the main form, and the user does not know that a slave form is being displayed. Figure A shows a main form, and its client area is a slave from the form.
Figure A client area contains the main form of the slave form
Understand sub-/ parent
The basic idea of such programs is to let all the slave forms as a sub-form of the primary form, which is very common in other frameworks, such as OWL or MFC, but is not common in the VCL program. VCL does not allow simply specifying properties to make a form belong to another form, to do this to pay some small labor. You have to tell the Microsoft Windows Subject to the Subject of the main form, which generally tends to be a window in C Builder programming, and the component is a child object. It is actually seen from Windows, and the forms and components are window. Can put any window
(Forms and Components) Specify the child objects of another window, as long as you temporarily jump out of the VCL circle.
Better "mouse clip"
One benefit of attaching a form is a main form is that you can design a subordinate form like any other slave form, that is, you create a new form, add components on it and write this form. Code. This makes it easy to design your sub-form and set all the code of all opinion forms in one place.
Program design example
First give a background of some programs, the program is called PARENTING, with a main form, the top of the main form and the bottom of the Tool Bar and Status Bar, except for the main window, There are two sub-forms, a TTableForm, displays animal.dbf data table with a raster, an Animal Table is a table of the database samples of the C Builder. Another child form TCHARTFORM displays the animal table with TCHART. (If you purchase C Builder is a standard version without database components) You can select the display form or the graphic form by clicking the Menu item or the tool button, when you make a choice, the active form is destroyed and the form is selected. Display, the subscription is below the toolbar of the main form, and the client area above the status bar is displayed, and the client is always filled with the main form size.
Heavy duty CreateParams ()
As mentioned earlier, in order to let the main form control the slave form, you need to set the main window to the "parent" from the form, which can be done by overloading the CreateParams () method. CREATEPARAMS () calls when VCL creates a window contact with the form, the declaration of createparams () is as follows:
Void __fastcall createparams (tcreateparams & params);
The unique parameters of CreateParams () are references to a TcreateParams structure. TCREATEPARAMS is defined below in the VCL:
Struct TCREATEPARAMS
{
Char * CAPTION;
Int style;
Int exstyle;
INT X;
Int Y;
Int width;
INT height;
HWND WNDPARENT;
Void * param;
Tagwndclassa windowclass;
Char WinclassName [64];
}
This structure contains all the information required for Windows to create a window (if you have used API for Windows programming, you must realize the map of TcreateParams to the Windows CreateStruct structure). When you overload CreateParams (), first call the baseparams () method of the base class, then modify the individual member variables of the TcreateParams structure. A heavy-duty CreateParams () method looks roughly as follows: void __fastcall tchartform :: CreateParams (TcreateParams & params)
{
TFORM :: CreateParams (params);
Params.Style = WS_CHILD | WS_CLIPSIBLINGS;
Params.wndparent = mainform-> handle;
Params.x = 0;
Params.y = 0;
Params.Width = mainform-> clientRect.right;
Params.height = mainform-> clientRect.bottom
}
The key to the program is to set the Style and WndParent members of the TCREATEPARAMS structure, Style Set WS_CHILD and WS_CLIPSIBLINGS window, and ws_child specifies the sub-window for another window. Depending on the definition, a child window is not a title stick, the title bar when designing, in Windows, creates a window, is removed. WS_CLIPSIBLINGS guarantees that the different sub-windows of the main window do not interfere when forming the form. Obviously, a sub-window must have a parent object that specifies the parent object by specifying the parent window handle to the TcreateParams structure WNDParent member, as indicated by the previous code, the WndParent member is set to the Handle property of the main form. Given that the specified parent object property is relatively straightforward, I don't go deep into this topic.
Set the properties of the subform
In addition to the code in the CreateParams () method, you have to set the properties of some subforms. Most attributes can retain the default, but the AutoScroll property should be false. Of course, the premise is that your form is designed to be rolled Form style. Since the size and location of the sub-window is set in createparams (), the position property can be set to Podefault. Caption and Bordericon properties will be ignored, so there is no need to specify. Make sure BorderStyle is set to Bssizeable, and BorderWidth is set to 0, and if this two attribute is set to other values, the child form is not coordinated with the main window.
Other components of the form
Many times, in addition to the slave form, the main form also contains other components, such as toolbar and status bars. When setting the X, Y, Width and Height members of the TcreateParams structure, consider the toolbar and status bar, The subsidiary should be coordinated with the top of the toolbar and the bottom of the strip. Therefore, the code for setting the member of the TCREATEPARAMS structure should be:
Params.x = 0;
Params.y = mainform-> Toolbar-> Height 1;
Params.Width = mainform-> clientRect.right;
Params.height = (mainform-> statusbar-> TOP-1) -Params.y;
Note Y is set to the bottom of the tool bar. 1, the sub-form width is set to the main form client area width, and the height is calculated according to the top of the subform and the status bar, substantially bound to the bottom of the tool strip and the bottom of the state bar. Main Factory Customer Area. These are all requirements that enable the slave family "home" in the main form, you may have the features that want to be implemented in the child form, I will leave these characteristics to the back. Set the main form
The main form is also available to control the subsidiary of its "receivable". First, you need to remove the child form from the automatically created form list and create them again. If you do not remove it from the list, they will be automatically displayed when your application starts. You also need a variable to track the current active subform, declare the variables in the PUBLIC area of the main form, tform * ActiveChild; ActiveChild is public because the sub-form is to access this variable. I will immediately demonstrate how to use this variable. Now let's write the code that shows the child form, first look at the following line, then I will explain.
Void __fastcall tMainform :: Chart1click (TOBJECT * SENDER)
{
IF (ActiveChild)
Delete activeChild;
TCHARTFORM * form = new tchartform (this);
ActiveChild = form;
FORM-> show ();
Chart1-> checked = true;
Table1-> checked = false;
}
This method is the onclick handling handle of the menu item of the main form, guess, this is displaying the TchartForm subform. First check if the ActiveChild variable is not 0, and if there is an activation mutual form ActiveChild will not 0. If ActiveChild is not 0, the pointer associated with this variable is deleted to destroy the active subform, otherwise the procedure will be stacked one by one. Then create an instance of a TCHARTFORM class, returning the New operation to the pointer to assign an ActiveChild variable, so ActiveChild always contains a pointer to the current subform. Finally, the SOW () method displays a child form. The last two lines of code ensure that the menu item representative form or graphic display shows a selected mark. In order to complete the discussion of the ActiveChild variable, I have to take you back to the sub-unit unit for a while. Each sub-form contains an event handle of an onClose event:
Void __fastcall tchartform :: formclose (TOBJECT * SENDER,
Tclosection & Action)
{
Mainform-> ActiveChild = 0;
Mainform-> chart1-> checked = false;
Action = CAFREE;
}
Note When the form is destroyed, the ActiveChild of the main form is set to 0 and is placed in unchecked menu item associated with the subsidiary. The Action parameter is set to CAFREE to notify the VCL to release the memory associated with this form. You may be confused with what the FormClose handle contains the last two lines above. The answer is that each subform has a Close button to close the form. If you turn off the form with a Close button, you need to release the memory and Uncheck menu items.
Extra characteristics
There is at least one feature that has not been discussed, that is, if the child form is larger than the main form, to re-adjust the main form size to accommodate the child form. These statements are placed in the CreateParams () method of the child form. I have shown a simple createParams () example, but did not put it in a statement that adjusts the main form size. List B has a complete createParams () method, and the only difference from previous demonstrations is to include the following statement:
IF (Width> Mainform-> ClientWidth)
Mainform-> clientwidth = width; if (height> (mainform-> statusbar-> Top-mainform-> toolbar-> height))
Mainform-> ClientHeight = Height
Mainform-> Toolbar-> HEIGHT
Mainform-> statusbar-> height;
These statements check whether the width of the child is greater than the clientWidth property of the main form, if yes, the clientwidth of the main form is placed as the width of the subform. The remaining several lines are the same thing, but it is only targeted that the customer area of the main form is height. The result of these statements is that the main form is always adjusted to a subsidy that can be fully contained. The example program also considers the main form of the main form. If the main window is changed, the subsidiary size must vary to make a client area filled with the main form. The following statement demonstrates the ONRESize event handle of the main form:
Void __fastcall tMainform :: FormResize (TOBJECT * SENDER)
{
IF (ActiveChild)
{
ActiveChild-> width = clientRect.right;
ActiveChild-> Height = (mainform-> statusbar-> TOP-1) -
ActiveChild-> Top;
}
}
These statements are quite straightforward, no need to explain one by one. Note First, the ActiveChild variable ensures non-0 (ie, pointing to a sub-form), it is clear if there is no activation any child form, nothing in OnResize. The remaining statements are variants of statements in CreateParams (), just simply calculate new sizes of the child form and set the corresponding Width and Height properties.
Conclusion
List A contains the code of the example of the master's main form. List B shows the source code of the TChartForm unit. The header file did not give the statement of the TTableForm cell because there is no meaningful statement, because similar to the Chatform unit. You can download an example program at www.reisdorph.com. The sub-form "home" provides a clear alternative to the MDI in the main form, which is also an alternative to programs that can only display data to the user in the form of a modeless form, using a child form to allow you to use The form designer designs your from the window and places the code of the operator form in a place.
List A: mainu.cpp
#include
#pragma HDRSTOP
#include "mainu.h"
#include "chartu.h"
#include "tableu.h"
#pragma resource "* .dfm"
TMAINFORM * MainForm;
__fastcall Tmainform :: TMAINFORM (Tcomponent * Owner)
: TFORM (OWNER)
{
// Clear 0 to prevent the random number
ActiveChild = 0;
// Open data sheet
Table-> Active = true;
}
Void __fastcall tMainform :: Table1Click (Tobject * Sender)
{
IF (Table1-> Checked) Return;
IF (ActiveChild) {
Delete activeChild;
ActiveChild = 0;
}
TTableForm * form = new TTableForm (this);
// Assign DBGRID :: DataSource attribute to the data source
FORM-> dbgrid-> DataSource = Datasource; // Track Active Subform
Active = form;
FORM-> show ();
Table1-> checked = true;
Chart1-> checked = false;
}
Void __fastcall tMainform :: Chart1click (TOBJECT * SENDER)
{
IF (chart1-> checked) return;
IF (ActiveChild) {
Delete activeChild;
ActiveChild = 0;
}
TCHARTFORM * form = new tchartform (this);
Active = form;
FORM-> show ();
Chart1-> checked = true;
Table1-> checked = false;
}
Void __fastcall tMainform :: FormResize (TOBJECT * SENDER)
{
IF (ActiveChild) {
ActiveChild-> width = clientRect.right;
ActiveChild-> Height = (mainform-> statusbar-> TOP-1) -
ActiveChild-> Top;
}
}
List B: chartu.cpp
#include
#pragma HDRSTOP
#include "chartu.h"
#include "mainu.h"
#pragma resource "* .dfm"
TChartform * chartform;
__fastcall tchartform :: tchartform (tComponent * Owner)
: TFORM (OWNER)
{
}
Void __fastcall tchartform :: CreateParams (TcreateParams & params)
{
// Call the base class CreateParams method
TFORM :: CreateParams (params);
// Sub window type
Params.Style = WS_CHILD | WS_CLIPSIBLINGS;
// Set the parent as a main form
Params.wndparent = mainform-> handle;
Params.x = 0;
IF (Width> Mainform-> ClientWidth)
Mainform-> clientwidth = width;
IF (Height> (mainform-> statusbar-> Top-mainform-> toolbar-> height))
Mainform-> ClientHeight = Height
Mainform-> Toolbar-> HEIGHT
Mainform-> statusbar-> height;
Params.y = mainform-> Toolbar-> Height 1;
Params.Width = mainform-> clientRect.right;
Params.height = (mainform-> statusbar-> TOP-1) -Params.y;
}
Void __fastcall tchartform :: formclose (TOBJECT * SENDER,
Tclosection & Action)
{
Mainform-> ActiveChild = 0;
MAINFORM-> Chart1-> checked = false; action = CAFREE
}
Void __fastcall tchartform :: ClosebTnclick (Tobject * Sender)
{
CLOSE ();
}