Multi-level database development fourteen: Patter several MIDAS demonstration procedures

xiaoxiao2021-03-06  89

Chapter 14 Analysis Several Midas Demo Procedure Midas is a referusion of Multi-Tier Distributed Application Services Suite, a key technique for Delphi 4. For beginners, Midas has considerable difficulty, so this chapter analyzes several MIDAS demonstration procedures to help readers understand and master MIDAS technology.

Unlike the general database application, only the project can be opened, compiled and running, compiling and running the "thin" client when the application server is running.

14.1 An example of an Activeform

Delphi 4 can bring the distributed database structure to the Internet / Intranet, which embeds the "thin" client as an ActiveForm into the web page, and then executes locally.

This section analyzes an ActiveForm's demonstration program, and the project name is EMPEDITX, which can be found in the C: / Program Files / Borland / Delphi4 / Demos / Midas / ActiveFM directory. Its main form is shown in Figure 14.1.

Before opening this project, you must compile, run the Server project in the C: / ProgramFiles / Borland / Delphi4 / Demos / Midas / Empedit directory, which is an application server, as shown in Figure 14.2.

Here is to explain, on the application server, introduce the data set with a TQUERY component, and its SQL statement is as follows:

SELECT * from Employee

On this ActiveForm, there is a TDCOMCONNECTION component for connecting the application server in a DCOM. Its ServerName property is set to serv.empserver, and its ServerGUID is set to {53BC6562-5B3E-11D0-9FFC-00A0248E4B9A}.

ActiveForm is introduced from the application server from the application server with the TclientDataSet component, and its RemoteServer property is set to the name of the MidasConnection, which is set to Empquery, which is the TQuery component on the application server, by it provides an iProvider interface.

There are several data controls on ActiveForms, which are used to obtain data through a TDataSource component. In addition, there is a TDBNAVigator component on the ActiveForm for browsing the data set.

Since the demonstration program to be introduced this section is an ActiveForm, most of its code is related to the type library, we only put some of the "拎" of the MIDAS technology.

When the user clicks the "Get Employees" button on ActiveForm, the data is retrieved from the application server. Each retrieved number of records depends on the PacketRecords attribute of the TclientDataSet component.

Procedure Tempeditform.QueryButtonClick (Sender: TOBJECT);

Begin

Employees.Close;

{Employees is the name of the TclientDataSet component} E

MPLOYEES.OPEN;

END;

When the user clicks the "Update Employees" button on ActiveForm, write the user's modification of the data to the data set.

Procedure Tempeditform.UpdateButtonClick (Sender: TOBJECT);

Begin

Employees.Applyupdates (-1);

END;

Cancel the user's modification of the data when the user clicks on the "undo Last Change" button on ActiveForm.

Procedure Tempeditform.undobuttonClick (Sender: TOBJECT);

Begin

Employees.undolastChange (TRUE);

END;

In order to test this ActiveForm, you first need to post it onto the web server for download. To do this, use the "Web Deployment Options" command on the "Project" menu to set the option for the web publishing, mainly to specify the URL on the ActiveForm on the web server. Then publish the ActiveForm on the web server using the "WebDeploy" command on the Project menu.

14.2 Demonstration program for dynamically transmitting SQL statements

This section analyzes an exemplary program that dynamically transmits the SQL statement, which can be found in the C: / Program Files / Borland / Delphi4 / DEMOS / MIDAS / Adhoc directory.

This program is divided into two parts: application servers and client programs. When the client calls DataRequest request data via the iProvider interface, pass the SQL statement entered to the application server, so that the TQuery component on the application server can query the database according to the user's requirements, which is the basic idea of ​​this demonstration program.

Firstly, the application server is first, and the data module is seen, as shown in Figure 14.3.

Figure 14.3 Data module

There are such components on the data module:

A TSESSION component, its sessionName property is set to session1_2.

A TDATABASE component, its sessionname property is set to session1_2, and defines a dedicated alias called Adhoc.

A TQUERY component, its DatabaseName property is set to Adhoc, and its sessionName property is also set to session1_2, and its SQL property is empty because the SQL statement is transmitted dynamically by the client program.

A TPROVIDER component, its DataSet property is set to the name of the TQUERY component.

Now we temporarily see the data module, then look at the main form of the application server, as shown in Figure 14.4.

Figure 14.4 Main Form for Application Server

Two counts are displayed on the main form, one is the number of customers currently connected to the application server, and the other is the number of queries that have already been executed (queries).

What to use to determine the current customer, this is related to the instance of the data module. We can return to the unit of the data module to see its initialization code:

INITIALIZATION

TcomponentFactory.create (COMSERVER, TADHOCQUERYDEMO,

Class_adhocQueryDemo, CIMULTIINSTANCE

End.

It can be seen that the instance of this data module is set to CIMULTIINSTANCE, indicating that a new instance of the data module will be created whenever a client is connected to the application server. Therefore, the number of instances of data modules is the current number of customers. How do I have the count number of data modules? Very simple, just handle the oncreate event of the data module.

Procedure TadhocqueryDemo.adhocqueryDemOCreate (Sender: TOBJECT);

Begin

Mainform.UpdateClientCount (1);

END;

When a customer exits the connection, an instance of a data module will be deleted, and the ONDESTROY event of the data module is triggered:

Procedure TadhocqueryDemo.adhocqueryDemodeStroy (Sender: TOBJECT);

Begin

Mainform.UpdateClientCount (-1);

Where the UpdateClientCount function is defined in the unit of the main form:

Procedure TMAINFORM.UPDATECLIENTCOUNT (INCR: Integer);

Begin

Fclientcount: = fclientcount inCr;

Clientcount.caption: = INTOSTR (fclientcount);

END;

Please read by pay attention to the role of the INCR parameter. How do I have the number of queries that have been implemented? It is very simple, as long as the number of TQuery components is activated. Therefore, the program handles the AfterOpen event of the TQuery component. Procedure TadhocqueryDemo.adhocQueryAfteropen (DataSet: TDataSet);

Begin

Mainform.incquerycount;

END;

INCQUERYCOUNT is defined in the unit of the main form:

Procedure tMainform.incqurycount;

Begin

Inc (FQUERYCOUNT);

Querycount.caption: = INTTOSTR (FQueryCount);

END;

You must compile and run items for the application server before opening the customer's project. Ok, now we open the customer's project, and its main form is shown in Figure 14.5.

This client is connected to the application server with a TDCOMCONNECTION component, and its ServerName property is set to serv.adhocquerydemo. The client program introduces a data set from the application server with the TclientDataSet component, and its RemoteServer property is set to the name of the TDCOMConnection component, which is set to AdhocQuery, which is the iProvider interface output by the application server.

There is a grid on the client program for displaying data, and the grid and the data set are connected via the TDataSource component. In addition, there is a multi-line text editor on the client program to enable the user to enter the SQL statement. There is a combo box to select the database you want to access. We still start with the handle to handle the oncreate event.

Procedure TFORM1.FormCreate (Sender: TOBJECT);

VAR i: integer; dbnames: olevariant;

Begin

Remoteserver.Connected: = true;

DBNAMES: = RemoteServer.AppServer.getDatabaseNames;

IF VarisArray (DBNAMES) THEN

For i: = 0 to VararrayHighBound (dbnames, 1) DO

DatabaseName.Items.Add (dbnames [i]);

DatabaseNameClick (Self);

END;

First, set the connect attribute of the TDCOMConnection component to True and the application server will be connected. The AppServer property of the TDCOMConnection component will return the interface of the data module on the application server, and the remote data module can be called by this interface, such as GetDatabaseNames. GetDatabaseNames is defined in the data module unit of the application server:

Function TadhocqueryDemo.getDatabaseNames: olevariant;

VAR i: integer;

DBNAMES: TSTRINGS;

Begin

DBNAMES: = TSTRINGLIST.CREATE;

Trysession1.GetDatabaseNames (DBNAMES);

Result: = VararrayCreate ([0, DBNAMES.COUNT - 1], Varolestr);

For i: = 0 to dbnames.count - 1 doreSult [i]: = dbnames [i];

FinallyDbnames.free;

END;

END;

The role of the getDatabaseNames function is to return an array that consists of all the unspecified alias and BDE session object alias. Now let's go back to the client program, after calling the GetDatabaseNames function of the data module, retrieve the retrieved alias to the combo box in the upper right corner of the form, then call the DatabaseNameClick function.

Procedure TFORM1.DATABASENAMECLICK (Sender: TOBJECT);

Var Password: String;

Begin

If DatabaseName.Text <> '' THEN

Begin

ClientData.Close;

Try

RemoteServer.AppServer.SetDatabaseName (DatabaseName.Text, '');

Except

ON E: Exception Doif E.MESSAGE = 'Password Required' Then

Begin

If INPUTQUERY (E.MESSAGE, 'Enter Password', Password) THEN

RemoteServer.AppServer.SetDatabaseName (DatabaseName.Text, Password);

End

Else

Raise;

END;

END;

END;

The purpose of calling DatabaseNameClick is to connect the application server to another database, which requires the interface of the data module through the App Server property, and then calls the setDatabaseName of the data module unit. SetDatabaseName is defined in the data module unit of the application server:

Procedure TadhocqueryDemo.SetDatabaseName (const dbname, password: wideString);

Begin

Try

Database1.close;

Database1.aliasname: = dbname;

IF Password <> '' Then

Database1.params.values ​​['password']: = password;

Database1.open;

Except

{If the database opens fail, it is probably because the database needs a password}

ON E: EdbEngineError Doif (Password = ') Then Raise Exception.create (' Password Required ') ELSE

Raise;

END;

END;

The role of SetDatabaseName is to modify the AliasName property of the TDatabase component, then connect the new database. If it fails, it triggers an exception. During the DatabaseNameClick process of the client program, if an exception occurs, you will pop up a input box, let the user enter the password, then call the setDatabaseName of the data module again.

When the user entered the SQL statement in the "Query" box, click the "Run Query" button to execute this query. The problem is that only the application server can execute the query, how do the client passed the SQL statement to the application server? This is the key to this demonstration process. Procedure TFORM1.RunbuttonClick (Sender: TOBJECT);

Begin

ClientData.Close;

ClientData.Provider.DataRequest (Sql.Lines.Text);

ClientData.Open;

END;

It turns out that the client program calls DataRequest via the iProvider interface to pass the SQL statement entered to the application server. The client program calls DataRequest via the iProvider interface will trigger the onDataRequest event on the application server side, let's take a look at how the application server handles the OndataRequest event.

Function TadhocqueryDemo.adhocProviderDataRequest (Sender: Tobject; Input: Olevariant): Olevariant;

Begin

Adhocquuery.sql.text: = input;

END;

At this point, a dynamically transmitted SQL statement is completed, and readers should carefully ponder the programming skills. In fact, call DataRequest via the iProvider interface can pass any information.

14.4 A Demonstration Procedure for a TCLientDataSet Function

This section describes a demonstration program that demonstrates the TclientDataSet function. The project name is Alchtest, which can be found in the C: / Program Files / Borland / Delphi4 / Demos / Midas / Alchtest directory, the main form is shown in Figure 14.6.

The overall idea of ​​this program is that uses a multi-page control to make the user modify the attribute of the TclientDataSet or call it, and then demonstrate the modified effect in the TAB control below.

The program first made some initialization work in handling the handle of the oncreate event.

Procedure TdbClientTest.formCreate (Sender: TOBJECT);

VAR i: integer;

Begin

Database1.close;

FmaxerRors: = -1;

FPACKETRECS: = -1;

SetCurrentDirectory (Pchar (ExtractFilePath)))))))))

For i: = 0 to statusbar.panels.count - 1 DO

Statusbar.Panels [i] .text: = '';

Application.onidle: = ShowheapStatus;

Application.onhint: = onhint

StreamSettings (false);

SetEventsVisible (VIEWEVENTS.CHECKED);

END;

Among them, specifying ShowHeapStatus as a handle of the onIdle event for processing the application, specifying the handle of OnHint as the onHINT event of the application. Showheapstatus is defined in this:

Procedure TDBClientTest.showheapStatus (Sender: Tobject; Var Done: Boolean);

Begin

CAPTION: = Format ('Client Dataset Test Form - (Blocks =% D Bytes =% D)', [AllocMemcount, AllocMemsize]);

END; SHOWHEAPSTATUS's role is to display the state of the stack at the title bar of the main window in the application free, where allocMemcount is the currently allocated memory block, and AllocMemSize is the currently allocated memory length.

Onhint is defined in this:

Procedure TdbClientTest.OnHint (Sender: TOBJECT);

Begin

STATUSMSG: = Application.hint;

END;

StatusMSG is a custom property that expresss prompt information to be displayed on the status bar.

The StreamSettings function is also called in the handle that processes the OnCreate event. StreamSettings is very useful. When the form is closed, call streamSettings to save the status of some controls on the form to a configuration file. When the form is popped up, call the streamSettings to read the configuration file to initialize the control on the form.

Procedure TdbClientTest.StreamSettings (Write: Boolean);

Procedure Writestr (const Optname, value: string);

Begin

Fconfig.WritString ('settings', optName, value);

END;

Procedure WriteBool (Const Optname: String; Value: Boolean);

Begin

Fconfig.writeBool ('settings', optName, value);

END;

Function ReadStr (const option): String;

Begin

Result: = fconfig.readstring ('settings', Optname, '');

END;

Function ReadBool (const Optname: String): Boolean;

Begin

Result: = fconfig.readBool ('settings', Optname, False);

END;

Function FindPage (const pagename: string): ttabsheet;

VAR i: integer;

Begin

For i: = limited - 1 Downto 0 DO

Begin

Result: = aaselector.pages [i];

IF result.caption = PageName dam

END;

Result: = proviDERPAGE;

END;

Procedure ProcessComponents (Components: array of tcomponent);

VARI: Integer;

Begin

IF WRITE THEN

Begin

For i: = low (components) to high (components) do

IF Components [I] IS TCUSTOMEDIT THEN

With TEDIT (Components [i]) Do Writestr (Name, Text)

Else IF Components [I] IS TCOMBOBOX THEN

With tdbcombobox (Components [i]) Do Writestr (Name, Text)

Else IF Components [I] is Tcheckbox Then

With Tcheckbox (Components [i]) Do WriteBool (Name, Checked) Else IF Components [i] is Tong Then

With Taction (Components [i]) Do WriteBool (Name, Checked)

Else if Components [i] is tpagecontrol.

WITH TPAGECONTROL (Components [i]) DowritStr (Name, ActivePage.caption);

END;

Else

Begin

For i: = low (components) to high (components) do

IF Components [I] IS TCUSTOMEDIT THEN

WITH TEDIT (Components [i]) Do Text: = ReadStr (NAME)

Else IF Components [I] IS TCOMBOBOX THEN

With Tcombobox (Components [i]) Do Text: = ReadStr (Name)

Else IF Components [I] is Tcheckbox Then

With Tcheckbox (Components [i]) Do Checked: = ReadBool (Name)

Else if Components [I] is TACTION THEN

WITH TACTION (Components [i]) Do Checked: = ReadBool (Name)

Else if Components [i] is tpagecontrol.

WITH TPAGECONTROL (Components [i]) DoctivePage: = FINDPAGE (ReadStr (Name));

END;

END;

Begin

GetConfigfile;

IF not write and (readstr ('areaselector') = ') THEN EXIT;

ProcessComponents ([AreaSelector, DatabaseName, MasterTableName, DetailTableName, MasterSQL, DetailSQL, poCascadedDeletes, poCascadedUpdates, poDelayedDetails, poDelayedBlobs, poIncludeFieldProps, poReadOnly, DisableProvider, ObjectView, SparseArrays, MixedData, FetchOnDemand, DisableProvider, ResolveToDataSet, DataRows, CreateDataSetDesc, EnableBCD, RequestLiveQuery, ViewEvents , DISPLAYDETAILS, INCLUDENESTEDOBJECT]);

END;

STREAMSETTINGS uses a Write parameter to distinguish it is to read or write. Several processes and functions are nested in StreamSettings, where Writestr, WriteBool, ReadStr, ReadBool are used to save strings and Boolean information in the configuration file, and the FindPage function search and return a specific object, and ProcessComponents It is used to access information related to the specific components.

The getConfigFile function is used to create an instance of a TiniFile object (if there is not yet created).

Function TDBClientTest.getConfigfile: tinifile;

Begin

IF fconfig = nil dam

Fconfig: = tinifile.create (ChangefileExt (paramstr (0), '.ini'); result: = fconfig;

END;

Please read the reader to pay attention to how streamSettings calls the ProcessComponents function. ProcessComponents needs to pass an array, the elements in the array are the names of some controls on the form.

Let's turn to the "Provider" page to see how to specify the database and establish the master / detail relationship, as shown in Figure 14.7.

Figure 14.7 "provider" page

The "Database" box is used to specify the database to be accessed. When the user pulls this box, the OONDROPDOWN event will be triggered. If the "Database" box is still empty, call the TSession's getDatabaseNames function to fill all the defined BDE alias and dedicated alias into the "Database" box.

Procedure TdbClientTest.databaseNamedropdown (Sender: TOBJECT);

Begin

If DatabaseName.Items.count = 0 THEN

Session.getDatabaseNames (DatabaseName.Items);

END;

When the user selects an alias in the "Database" box, the ONCLICK event will be triggered. At this point, you call the CheckDatabase to connect to another database. Since the database has changed, the content within the "Master / DetailTables" box should be clear.

Procedure TdbClientTest.DatabaseNameClick (Sender: TOBJECT);

Begin

IF (DatabaseName.Text <> ') and not databasename.droppedDown then

Begin

CheckDatabase (TRUE);

MASTERTABLENAME.ITEMS.CLEAR;

MASTERTABLENAME.TEXT: = '';

DetailTableName.Text: = '';

ClientData.Close;

END;

END;

Users can also type a database alias directly in the "Database" box, then press Enter to trigger the ONKEYPRESS event.

Procedure TDBClientTest.DatabaseNameKeyPress (Sender: Tobject; Var Key: char);

Begin

If key = # 13 THEN

Begin

If DatabaseName.droppedDown Then

DatabaseName.DroppedDown: = false;

DatabaseNameClick (Sender); key: = # 0;

END;

END;

Ok, let us see how CheckDatabase is defined:

Procedure TDBClientTest.checkDatabase (Closefirst: Boolean);

Var spassword, susename: String;

Begin

If not closefirst and database1.connected and (database1.aliasname = DatabaseName.Text) THEN EXIT;

Database1.close;

Database1.aliasname: = DatabaseName.Text;

Session.getaliasparams (Database1.Params); if Database1.Params.indexOfName ('PATH') = -1 Then

Begin

Spassword: = configfile.readstring ('passwords', Database1.aliasName, '');

IF spassword = '' THEN

Begin

SUSERNAME: = Database1.Params.Values ​​['user name'];

IF not logindialog ('DatabaseName.Text', SUSERNAME, SPASSWORD).

Database1.params.values ​​['user name']: = susename

END;

Database1.params.values ​​['password']: = spassword;

END;

If enablebcd.checked the database1.params.add ('enable bcd = true ";

Database1.open;

IF database1.issqlbased and (spassword <> '). Thenfigfile.writestring (' Passwords', Database1.aliasName, Spassword);

END;

CheckDatabase is used to connect a user specified database. If the current connection is the database specified by the user, CheckDatabase does not do anything. If not, first call the Close of the TDATABASE component to disconnect the connection with the database, and then set the AliasName property of the TDATABASE component to the alias selection, and call the GetAliasParams of the BDE session to remove the parameters of this alias.

Note that for the local database, only one path parameter, and for the SQL database, there are several parameters, so there is no PATH parameter to distinguish the local database and SQL database. If it is a SQL database, set the user name and password parameter to give the username and password. If the "enablebcd" command on the "Settings" menu is selected, an Enable BCD parameter is added and the value is set to True. Then call the Open to reconnect the database.

This program also allows customers to select the master table and Detail table in the "master / detail" relationship, which is selected in the "Master / Detail Tables" box, where one of the combo box is used to select the master table, one of the following combination Box is used to select the Detail table. When the user selects a table in the combo box, the ONCLICK event will be triggered.

Procedure TdbClientTest.mastertableNameClick (Sender: TOBJECT);

Begin

With sender as tcombobox do

IF not DroppedDown and (mastertable.tablename <> text). ..Execute;

END;

When the user pulls a combo box in the "Master / Detail Tables" box, the OONDROPDOWN event will be triggered. At this point, you will fill in the name of all the tables in the current database to the combo box for the user selection. Procedure TdbClientTest.MasterTableNameDropdown (Sender: TOBJECT);

Begin

CheckDatabase (false);

With sender as tcombobox do

IF (items.count <1) and (Database1.AliasName <> ') THEN

Session.gettablenames (Database1.DatabaseName, '', True, False, Items);

END;

The user can also type a table's name directly within a combination in the "master / Detail Tables" box, then press ENTER to trigger the ONKEYPRESS event.

Procedure TdbClientTest.MasterTableNameKeyPress (Sender: Tobject; Var Key: char);

Begin

If key = # 13 THEN

Begin

With sender as tcombobox do

IF DroppedDown the DroppedDown: = false;

OpenTable.execute;

Key: = # 0;

END;

END;

Note: The above is in the case where the combo box is selected as an example. In fact, the operation of the Detail table is selected is exactly the same, the code is as follows.

Procedure TdbClientTest.detailTableNameClick (Sender: TOBJECT);

Begin

With sender as tcombobox do

IF not DroppedDown and (detailtable.tablename <> text) THEN

OpenTable.execute;

END;

In the above event handles, OpenTable is a list of action, which is a newly added function of Delphi 4. Double-click the TactionList component on the form, open a editor as shown in Figure 14.8.

Figure 14.8 Action List Editor

In this editor, find this action, then you can find that the code that performs this action is the OpenTableExecute function in the Object Observer.

Procedure TDBClientTest.OpenTableExecute (Sender: TOBJECT);

Begin

ClearEventlog.execute;

If MASTERTABLENAME.TEXT <> '' Ten OpenDataSet (MASTERTABLE);

END;

OpenDataSet is defined in this:

Procedure tdbclientTest.Opendataset (Source: TDBDataSet);

Begin

Screen.cursor: = CRHOURGLASS;

Try

ClientData.Data: = NULL;

Source.close;

IF not disableprovider.checked kil

Begin

BDEPROVIDER.DataSet: = Source;

SetProviderOptions;

ClientData.ProviderName: = bdeprovider.name;

ActiveDataSet: = ClientData; END

Else

ActiveDataSet: = Source;

Mastergrid.setfocus;

Statusmsg: = 'Dataset Opened';

FinallyScreen.cursor: = crdefault;

END;

StreamSettings (TRUE);

END;

OpenDataSet decides whether to use the TPROVIDER component through a checkbox called DisableProvider. If you do not select the "Disable Provider" check box, you represent the use of the TPROVIDER component, at which point the TProvider component is set to MASTERTABLE, then call SetProviderOptions to set the option to set the TPROVIDER component, then set the TclInderName property of the TclInderDataSet component Specify this TPROVIDER. The component, finally set the ActiveDataSet variable to this TclientDataSet component. If the user selects the "Disable Provider" check box, indicates that the TPROVIDER component is not used, and then the ActiveDataSet is set directly to MASTABLE.

SetProviderOptions is defined in this:

Procedure tdbclientTest.SetProviderOptions;

Var OPTS: TPROVIDEROPTIONS;

Begin

OPTS: = []; if podelayeddetails.checked the

Include (OPTS, PofetchDetails);

If Podelayedblobs.Checked Then Include (OPTS, PofetchBlobsondemand);

If PocaScadeddeletes.checked Ten Include (OPTS, POCASCADELES);

If PocaScadedupdates.checked THEN INCLUDE (OPTS, POCASCADEUPDATES);

IF poreadonly.checked kilod (OPTS, Provider.poreadOn ";

IF poincludefieldprops.checked kilod (OPTS, POINCFIELDPROPS);

BDEPROVIDER.OPTIONS: = OPTS;

END;

SetProviderOptions actually sets whether to set the Options property of the TPROVIDER component based on some subcommands of the "Provider Options" command on the "Settings" menu. This program also allows users to enter SQL statements in the "Master / Detail Queries" box. When the user enters the SQL statement and presses the Enter key, the ONKEYPRESS event will be triggered.

Procedure TdbClientTest.Master: Tobject; Var Key: char);

Begin

If key = # 13 THEN

Begin

OpenQuery.execute;

Key: = # 0;

END;

END;

Among them, OpenQuery is also an action, executing it is the OpenQueryExecute function. OpenQueryExecute is defined in this:

Procedure TDBClientTest.openQueryexecute (Sender: TOBJECT);

Begin

IF Uppercase (Copy (MasterSql.Text, 1, 6)) = 'SELECT' THENOPENDATASET (MasterQuery)

Else

Begin

CheckDatabase (false);

MasterQuery.RequestLive: = true;

MasterQuery.sql.text: = MASTERSQL.TEXT;

MASTERQUERY.EXECSQL;

Statusmsg: = format ('% d rows were affected ", [masterQuery.rowsaffected]);

END;

Events.items.

Begin

Update;

Try

Events.clear;

Finally

Events.Items.Endupdate;

END;

END;

OpenQueryExecute first determines whether the user entered SQL statement is SELECT. If so, call the OpenDataSet to perform the SELECT statement. If not, call the execSQL to execute the SQL statement.

When the user flies to the "fields" page, the ONSHOW event of the Fieldspage (TtabSheet object) is triggered, and the fields and field definition object names in the data set are displayed in two multi-line text editors, as shown in Figure 14.9 .

Figure 14.9 "FIELDS" page

Procedure TdbClientTest.fieldspageShow (Sender: TOBJECT);

Procedure WriteFullNames (Fields: Tfields);

VAR i: integer;

Begin

For i: = 0 to Fields.count - 1 DO

With Fields [i] DO

Begin

FieldList.Lines.Add (Format ('% d)% s', [FieldNo, Fullname]);

IF fields [i] .dattype in [ftadt, ftarray] THEN

WriteFullNames (Tobjectfield (Fields [i]). Fields);

END;

END;

Procedure WriteLists (DataSet: TDataSet);

VAR i: integer;

Begin

FieldList.clear;

For i: = 0 to dataset.fieldlist.count - 1 do

With dataset.fieldlist do

FieldList.Lines.Add (Format ('% D)% s', [Fields [i] .fieldno, Strings [i]]);

FieldDeflist.clear;

Dataset.fielddefs.updated: = false;

DataSet.fieldDeflist.Update;

For i: = 0 to dataset.fielddeflist.count - 1 do

With dataset.fielddeflist do

FieldDeflist.Lines.Add (Format ('% D)% s', [FieldDefs [i] .fieldno, Strings [i]]);

END;

Var DataSet: TDataSet;

Begin

Dataset: = dbnavigator1.datasource.datan;

IF assigned (dataset) and dataset.active the

Begin

WriteLists (Dataset)

End

Else

Begin

CheckDatabase (false);

MASTERTABLE.TABLENAME: = MASTERTABLENAME.TEXT; WRITELISTS (MASTERTABLE);

END;

END;

The first thing to explain is that WriteFullNames is nestled in FieldspageShow, in fact, WriteFullNames is completely redundant. FieldspageShow first gets the current data set. If the current data set is turned on, call the WriteLists to display the list of field objects and field definition objects. If the current data set is not open, the list of field objects and field definition objects in MASTERTABLE is displayed. When the user flies to the "indexes" page, the ONSHOW event of IndexPage will be triggered. At this time, the index in the current data set is column, and the user can create a new index or delete an index. "Indexes" page is shown in Figure 14.10.

Figure 14.10 "INDEXES" page

Procedure TdbClientTest.indexpageShow (Sender: TOBJECT);

Begin

IF not assigned (activeDataSet) or not activeDataSet.Active Then

OpenTable.execute;

RefreshindexNames (0);

END;

IndexpageShow first checks if there is a dataset. If not, open the dataset of the OpenTable code, then call the RefreshIndexNames function listing all index names.

Procedure tdbclientTest.refresh IndexNames (NewItemIndex: Integer);

VAR i: integer;

Indexdefs: TINDEXDEFS;

Begin

Indexlist.clear;

If ActiveDataSet = MASTERTABLE THEN

Indexdefs: = MASTERTABLE.INDEXDEFS

Else

INDEXDEFS: = ClientData.indexdefs;

Indexdefs.update;

For i: = 0 to indexdefs.count - 1 do

IF indexdefs [i] .name = '' Then indexlist.Items.add ('

')

Else

IndexList.Items.Add (Indexdefs [i] .name);

IF indexlist.items.count> 0 THEN

Begin

IF newItemIndex

Indexlist.ItemIndex: = newItemIndex

ElseIndexList.itemindex: = 0;

ShowIndexparams;

END;

END;

RefreshIndexNames calls ShowIndexParams to retrieve indexes, with these options to initialize several edit boxes and check boxes on the "Indexes" page.

Procedure tdbclientTest.showindexparams; varindexdef: TINDEXDEF;

Begin

If ActiveDataSet = MASTERTABLE THEN

INDEXDEF: = Mastertable.indexdefs [indexlist.itemindex]

Else

Indexdef: = ClientData.Indexdefs [indexlist.itemindex];

idxCaseInsensitive.Checked: = ixCaseInsensitive in IndexDef.Options; idxDescending.Checked: = ixDescending in IndexDef.Options; idxUnique.Checked: = ixUnique in IndexDef.Options; idxPrimary.Checked: = ixPrimary in IndexDef.Options; IndexFields.Text: = IndexDef .Fields; descfields.text: = indexdef.descfields;

Caseinsfields.text: = indexdef.caseinsfields;

END;

If the user selects another index in the list box, you should refresh these options accordingly. Procedure TdbClientTest.indexlistClick (Sender: TOBJECT);

Begin

If ActiveDataSet = MASTERTABLE THEN

MASTERTABLE.INDEXNAME: = MASTERTABLE.INDEXDEFS [INDEXLIST.ItemIndex] .name

Else

ClientData.indexName: = ClientData.indexdefs [indexlist.itemindex] .name

ShowIndexparams;

END;

If you want to create a new index, the user must set an index option in advance, then click the "CreateIndex" button.

Procedure TDBClientTest.createIndexclick (Sender: TOBJECT);

Var indexname: string; options: tindexoptions

Begin

IndexName: = Format ('Index% D', [IndexList.Items.count 1]);

IF INPUTQUERY ('Create Index', 'Enter IndexName:', IndexName) THEN

Begin

Options: = [];

If idxcaseinsensitive.checked kilod (options, ixcaseinsensitive);

If idxdescending.checked dam, ixdescending;

If idxunique.checked kiln ket (options, ixunique);

If idxprimary.checked kilodes (options, ixprimary);

If ActiveDataSet = MASTERTABLE THEN

Begin

MASTERTABLE.CLOSE;

MASTERTABLE.AddIndex (IndexName, Indexfields.Text, Options, Descfields.Text);

MASTERTABLE.OPEN

End

Else

ClientData.AddIndex (IndexName, Indexfields.Text, Options, Descfields.Text, Caseinsfields.Text);

Statusmsg: = 'index created';

Refresh IndexNames (indexlist.items.count);

END;

END;

CreateIndexClick first pops up a input box, allows the user to enter an index name, and then set the options attribute of the index according to the options for the user. Before calling AddIndex, you should first distinguish between the current data set is MASTERTABLE or ClientData, why do you distinguish MASTERTABLE and CLIENTDATA? Because for a general data set component, the data set must be turned off before creating an index, and for the TClientDataSet component, you don't have to close the data set first.

Users can also select an index first, then click the "Delete Index" button to delete this index.

Procedure TdbClientTest.deleteIndexclick (Sender: TOBJECT);

Begin

If indexlist.itemindex> -1 then

If ActiveDataSet = MASTERTABLE THEN

Begin

MASTERTABLE.CLOSE;

MASTERTABLE.DELETEINDEX (MASTERTABLE.INDEXDEFS [INDEXLIST.ItemIndex] .name);

MASTERTABLE.OPEN

End

Else

ClientData.deleteIndex (ClientData.indexdefs [indexlist.itemindex] .name);

END;

Like calling addindex, first distinguishing the current data set before calling deleteIndex, is MASTERTABLE or ClientData. When the user turned to the Filters page, the filtering condition can be set, as shown in Figure 14.11.

Figure 14.11 "Filters" page

When the "Filters" page is just open, the ONSHOW event will be triggered so that the "Filter" box can be initialized. This uses a programming skill, first remove a field from the grid below, and then determine whether the data type of this field is ftstring, ftmemo, or ftfixedchar, if yes, the filter condition expression operator is followed. The value should be enclosed with quotation marks.

Procedure TDBClientTest.FilterpageShow (Sender: TOBJECT);

Var Field: Tfield; LocValue, Quotechar: String

Begin

IF (Filter.Text = '') And assigned (activeDataSet) and activeDataSet.Active the

Begin

Field: = MASTERGRID.SELECTEDFIELD; if Field = NIL THEN EXIT;

WITH ACTIVEDATASET DOTRYDISABLECONTROLS;

Moveby (3);

Locvalue: = Field.Value;

First;

Finally

EnableControls;

END;

If Field.DataType in [ftstring, ftmemo, ftfixedchar] THEN

Quotechar: = '' ''

Else quotechar: = '';

Filter.Text: = format ('% s =% s% s% 1: s', [field.ffullname, quotechar, locvalue]);

END;

END;

The user can type a new filter condition in the "Filter" box, and the user inputs the filter condition expression to the current data set in the current data set by pressing the Enter or remove the input focus. When the user turned to the "Findkey" page, you can enter a key value and then search for a specific record in the data set, as shown in Figure 14.12. Figure 14.12 "FindKey" page

When the user clicks the "Find Key" or "Find Nearest" button, starts searching for a specific record.

Procedure TDBClientTest.FindKeyClick (Sender: TOBJECT);

Begin

If ActiveDataSet = ClientData Then

WITH ClientData DO

Begin

SetKey; Indexfields [0] .sstring: = FindValue.Text;

KeyExClusive: = self.keyexclusive.checked; if FindPartial.checked the keyfieldcount: = 0;

If sender = self.findnearest the Gotonearest Else

IF not gotokey the statusmsg: = 'not found';

End

Else

if ActiveDataSet = MASTERTABLE THEN

With masteable do

Begin

SetKey;

Indexfields [0] .sstring: = FindValue.Text;

KeyExClusive: = self.keyexclusive.checked;

If FINDPARTIAL.CHECKED THEN Keyfieldcount: = 0;

If sender = self.findnearest the GotoneareAreSt

Else

IF gotoKey TenStatusmsg: = 'Record Found'

Else Statusmsg: = 'NOT FOUND';

END;

END;

First, to distinguish whether the current data set is ClientData or MASTERTABLE, calling SetKey to enter the DSSetKey state, assign the user input to the first field in the index. Then, according to the Sender parameter, it is determined that the user presses the "Find Key" button or the "Find Nearest" button. If it is the latter, call Gotonearest if it is the former, call GotoKey, and finally displays the relevant information according to the return value of GotoKey.

When the user turned to the "Locate" page, the LocatePage (TTABSHEET object) will trigger the LocatePage (TTABSHEET object), and the program selects the fields selected in the raster as a key field. "Locate" page is shown in Figure 14.13.

Figure 14.13 "Locate" page

Procedure TDBClientTest.locatePageShow (Sender: TOBJECT);

Var field: tfield;

Begin

IF (ActiveDataSet <> nil) and activeDataSet.Active the

Beginfield: = Mastergrid.selectedfield;

If Locatefield.Items.count = 0 THEN

LocatefieldDropdown (Locatefield);

IF (locatefield.text = ') or (locatefield.Items.indexof (field.fieldname) <1 )11Locatefield.Text: = Field.fieldName;

With activeDataSet do

Try

DisableControls;

Moveby (3);

LocateEdit.Text: = Field.Value;

First;

Finally

EnableControls;

END;

END;

END;

Users can also select a key field in the "Field" box. When the user pulls the "Field" box, trigger the onDropdown event so that the fields in the current data set can be displayed in the "field" box.

Procedure TdbClientTest.locatefieldDropdown (Sender: TOBJECT);

Begin

ActiveDataSet.GetfieldNames (Locatefield.Items);

END;

When the user selects a key field and enter the key value, you can click the Locate record.

Procedure TDBClientTest.locateButtonClick (Sender: Tobject); VarOptions: TlocateOptions; LocateValue: Variant;

Begin

Options: = [];

If LOCCASEINSENSITIVE.CHECKED THEN INCLUDE (OPTIONS, LOCASEINSENSITIVE);

If LocpartialKey.checked THEN INCLUDE (OPTIONS, LOPARTIALKEY);

If Locatenull.checked Then LocateValue: = NULL

Else

LocateValue: = locateedit.text;

IF ActiveDataSet.locate (Locatefield.Text, LocateValue, Options) THEN

Statusmsg: = 'Record Found'

Else

Statusmsg: = 'NOT FOUND';

END;

The previous few lines of code mainly set the option, whereile the "Null Value" check box is selected, set the key value to NULL. Then call the Locate function positioning record of the current data set, and displays the corresponding information based on the return value of the Locate function.

14.6 a login demonstration program

This section analyzes a login demonstration program that can be found in the C: / Program Files / Borland / Delphi4 / Demos / Midas / Login directory.

This program is divided into two parts: application servers and client programs. There is a list box on the main form of the application server, which is used to record the username you have logged in to the application server, as shown in Figure 14.16.

The data module on the application server is shown in Figure 14.17.

There is only one TTable component on the data module, and its DatabaseName property is set to DBDemos, and the TableName property is set to Country. There is no TPROVIDER component on the data module, which provides an IProvider interface by the TTable component.

The instance of this data module is set to CIMULTIINSTANCE, which means that a new instance of the data module will be created whenever a client is connected to the application server. When the customer is no longer connected to the application server, instance of the data module is deleted. Therefore, this program uses the oncreate event of the data module to make some initialization work, using the ONDESTROY event of the data module from the list box to delete a username.

Procedure Tlogindemo.logindemoCreate (Sender: TOBJECT);

Begin

Floggedin: = false;

END;

Why do you want to set the FLOGGEDIN variable to false? The reason will be explained later.

Procedure Tlogindemo.logindemodestroy (Sender: TOBJECT);

Begin

With form1.listbox1.items do delete (Indexof (FuserName);

END;

Compile and run this application server. Open the customer's project, its main form is shown in Figure 14.18.

The TDCOMCONNECTION component on the form is used to connect the application server, and its ServerName property is set to Server.Logindemo, and its LoginPrompt property is set to true. The RemoteServer property of the TclientDataSet component on the form specifies the TDCOMCONNECTION component, and its ProviderName property is set to Country.

In addition, there is a grid on the form to display data in the data set, and an "open" button is used to open the data set.

Since the LoginPrompt property of the TDCOMConnection component is set to TRUE, a "Remote Login" dialog box will pop up when the client tries to connect to the application server, requiring the user to enter the username and password. After logging in, I trigger the ONLOGIN event. In handle the handle of this event, the client obtains the interface of the data module via the appserver property to invoke the login of the data module.

Procedure TFORM1.DCOMCONNECTION1LOGIN (Sender: Tobject; UserName, Password: String);

Begin

DCOMCONNECTION1.APPServer.login (username, password);

END;

Login is defined in the data module unit of the application server.

Procedure Tlogindemo.login (const username, password: wideString);

Begin

Form1.ListBox1.Items.Add (username);

Floggedin: = true;

FUSERNAME: = Username;

END;

Login adds the username to the list box, and set the FLoggedin variable to true, indicating that the user is logged in. When the user clicks the "Open" button, call the Open of the TclientDataSet component to open the data set.

Procedure TFORM1.BUTTON1CLICK (Sender: TOBJECT);

Begin

ClientDataSet1.Open;

END;

14.7 Demonstration Procedure Demonstrate Master / Detail Relationship

This section analyzes a demonstration program that demonstrates Master / Detail relationships, which can be found in the C: / ProgramFiles / Borland / Delphi4 / Demos / Midas / MSTRDTL directory.

This program is divided into two parts: application servers and client programs. The application server has a form, however, this form is actually redundant. If you don't want to display, you can open the project file of the application server, join this:

Application.showmainform: = false;

The data module of the application server is shown in Figure 14.19.

There are several components on the data module of the application server:

TDATABASE components named Database, its AliasName property is set to IBLOCAL and define an app-specific alian name called ProjectDB. Its Params property provides username and password. The TTable component named Project, which is set to Projectdb, and its TableName property is set to Project (Note: INTERBASE Server must be run.

The TQuery component named Employee, which is set to Projectdb, its SQL statement is as follows: select * from Employee_Project E Where E.Proj_ID =: Proj_ID

The TQUERY component named EMPPROJ, which is set to Projectdb, its SQL statement is as follows: select EMP_NO, FULL_NAME FROM EMPLOYEE

The TQUERY component named UpdateQuery, its DatabaseName property is set to ProjectDB, and its SQL statement is currently empty.

The TPROVIDER component named ProjectProvider, which is set to Project.

The TDataSource component called ProjectSource, which is set to Project. Compile and run the application server. You can now open the program of the client, and its data module is shown in Figure 14.20.

Figure 14.20 Data Module

There are such components on the data module of the client program:

The TDCOMCONNECTION component named DCOMCONNECTION, its ServerName property is set to serv.projectddata.

The TclientDataSet component called Project, its RemoteServer property is set to DCOMCONNECTION It is set to ProjectProvider. And established a permanent field object called Projectempproj, which is TDataSetField. The TDataSource component corresponding to Project is called ProjectSource.

TclientDataSet components named EMP_PROJ, its RemoteServer attribute, and proviDERNAME properties are empty, but its DataSetField property is set to the field object of Projectempproj, which constitutes the master / detail relationship. The TDataSource component corresponding to EMP_PROJ is called EMPPROJSOURCE.

The TClientDataSet component named Employee, which specifies the TDCOMCONNECTION component, but its ProviderName property is set to EMPLOYEE. The TDataSource component corresponding to Employee is called Employeesource.

Let's see the main form of the client program, as shown in Figure 14.21.

On the left, a grid only displays the Proj_Name field in the Project data set, the project name, "Product" box Displays the Product field in the Project data set, "Description" box shows the proj_desc field in the Project data set, and uses a TDBNAVIATOR component to provide the Project Data Set navigation .

The raster in the lower right corner shows the value of the field called Employeename, which is a lookup field. Its lookupDataSet property is set to EMPLOYEE, and its lookupKeyField property is set to EMP_NO, its lookupResultfield property is set to full_name. When the user browses the record of the Project dataset with a navigator, the raster in the lower right corner looks for records that match the EMP_NO field from the Employee data set, and displays the full_name fields. Since the raster in the lower right corner only establishes a permanent column object, the width of this column can be set to the grid itself, which is performed in the handle of the oncreate event of the form.

Procedure TclientForm.FormCreate (Sender: TOBJECT);

Begin

Membergrid.columns [0] .width: = membergrid.clientwidth - getSystemMetrics (SM_CXVScroll);

END;

Due to more than one employee in a project, in order to be eye-catching, you can bold the person in charge, which requires processing the grid's OnDrawColumnCell event.

Procedure tclientform.membergriddrawcolumncell (Sender: Tobject; Const Rect: TRECT; Datacol: Integer; Column: Tcolumn; State: TgriddrawState;

Begin

IF dm.projectteam_leader.value = DM.EMP_Projemp_no.ient dam.style: = [fsbold];

Membergrid.defaultDrawColumnCell (Rect, Datacol, Column, State);

END;

How to judge the person in charge? In the Project data set, there is a Team_leader field that stores the employee number of the project leader. In the EMP_PROJ data set, there is an EMP_NO, which is also stored is also an employee number, and if the two are equal, the employee is the project person in charge. When the user clicks the "Add" button, you can add a record in the grid, which adds an employee in the project.

Procedure TclientForm.Addbtnclick (Sender: TOBJECT);

Begin

Membergrid.setfocus;

DM.EMP_PROJ.APPpend;

Membergrid.editormode: = true;

END;

Since the grid has established a permanent column object in advance, the field of the column object specifies a lookup field, so the user can select a value from a combo box.

When the user clicks on the "Delete" button, delete the current record, an employee.

Procedure TclientForm.deletebtnclick (Sender: TOBJECT);

Begin

DM.EMP_PROJ.DELETE;

END;

When the user selects one of the employees first, then click the "Leader" button to set the employee as the project leader.

Procedure TclientForm.leaderbtnclick (Sender: TOBJECT);

VAR NEWLEADER: Integer;

Begin

NEWLEADER: = DM.EMP_Projemp_no.view;

IF not (dm.project.state in dseditmodes) Then DM.Project.editation; dm.projectteam_leader.value: = newLerader;

MEMBERGRID.REFRESH;

END;

After adding, deleting, or modifying the record, the user should click the "Apply Update" button to update the database.

Procedure tclientform.applyupdatesbtnclick (sender: TOBJECT);

Begin

DM.Applyupdates;

END;

In the unit of the data module, ApplyUpdates is defined in this:

Procedure tdm.applyupdates;

Begin

If Project.Applyupdates (0) = 0 THEN Project.refresh;

END;

It can be seen that Applyupdates of the data module also call Applyupdates of the TclientDataSet component, and set the maxErrorS parameter to 0, so that as long as the application server finds an error record, the update stops.

When the user attempts to add a new project in the grid on the left, the ONNewRecord event of the TclientDataSet component is triggered. Since this grid only shows the proj_name field, the user cannot enter the value of the Proj_ID field, so the program introduces a input box in the handle that handles the ONNewRecord event, allows the user to enter the value of the Proj_id field. If the user entered by the user exceeds the length allowed by this field, it triggers an exception.

If the user does not enter any characters, it also triggers an exception.

Procedure TDM.ProjectNewrecord (DataSet: TDataSet);

VA RVALUE: STRING;

Begin

IF INPUTQUERY ('Project ID ",' Enter Project ID: ', Value) THEN

Begin

If Length> ProjectProj_id.size Then

Raise Exception.createfmt ('Project ID CAN Only BE% D Characters', [ProjectProj_id.size]); if Length (Value) = 0 THEN

Raise Exception.create ('Project ID is Required');

End

Else

Sysutils.abort;

ProjectProj_id.value: = value;

END;

Since a master / Detail relationship is present between the Project dataset and the Employee dataset, when a record of the Project dataset is deleted, the records associated with the Employee data set should first be removed. This application server implements this with the BeforeUpDateRecord event of the TPROVIDER component.

Procedure tprojectdata.projectProviderbeforeupdateRecord; Sourceds: tclter; deltads: tclientDataSet; Updatekind: tupdatekind; var applied: boolean;

Const deleteQuery = 'delete from Employee_Project Where proj_id =: projid';

Begin

IF (updatekind = ukdelete) and (sources = project) thenbegin

UpdateQuery.sql.text: = deleteQuery;

UpdateQuery.Params [0] .sstring: = DELTADS.FIELDBYNAME ('Proj_ID'). Asstring;

UpdateQuery.execsql;

END;

END;

14.9 Demonstration Procedure for Dynamic Setting Inquiry Parameters

This section analyzes an exemplary program that dynamically sets the query parameter, which can be found in the C: / ProgramFiles / Borland / Delphi4 / Demos / Midas / SetParam directory.

This program is divided into two parts: application servers and client programs. When the client is set to the TQUERY component on the application server via the Params property of the TclientDataSet component, these parameters are automatically passed to the TQuery component on the application server, which can query the database according to the user's requirements, which is the basic idea of ​​this demonstration program.

Let's analyze the application server, first look at its data module, as shown in Figure 14.24. Figure 14.24 Only one TQuery component on the data module data module, its DatabaseName property is set to DBDemos, its SQL statement is as follows:

SELECT * home "=: start_date and event_date <=: end_date order by Event_date

It can be seen that there are two parameters in this SQL statement, one is: start_date, the other: End_date.

Now we temporarily regardless of the data module, then look at the main form of the application server, as shown in Figure 14.25.

Figure 14.25 Main Form for Application Server

Two counts are displayed on the main form, one is the number of customers currently connected to the application server, and the other is the number of queries that have already been executed (queries). What to use to determine the current customer, this is related to the instance of the data module. We can return to the unit of the data module to see its initialization code:

INITIALIZATION

TcomponentFactory.create (COMSERVER, TSETPARAMDEMO,

Class_setParamDemo, CIMULTIINSTANCE

End.

It can be seen that the instance of this data module is set to CIMULTIINSTANCE, indicating that a new instance of the data module will be created whenever a client is connected to the application server. Therefore, the number of instances of data modules is the current number of customers. How do I have the count number of data modules? Very simple, just handle the oncreate event of the data module.

Procedure TsetParamDemo.SetParamDemoCreate (Sender: TOBJECT);

Begin

Mainform.UpdateClientCount (1);

END;

When a customer exits the connection, an instance of a data module will be deleted, and the ONDESTROY event of the data module is triggered:

Procedure TsetParamDemo.SetParamDemoCreate (Sender: TOBJECT);

Begin

Mainform.UpdateClientCount (1);

END;

Where updateClientCount is defined in the unit of the main form:

Procedure TMAINFORM.UPDATECLIENTCOUNT (INCR: Integer);

Begin

Fclientcount: = fclientcount inCr;

Clientcount.caption: = INTOSTR (fclientcount);

END;

Note the role of the INCR parameter. How do I have the number of queries that have been implemented? It is also very simple, as long as the number of TQUERY components is activated. Therefore, the program handles the AfterOpen event of the TQuery component.

Procedure TsetParamDemo.Eventsafteropen (DataSet: TDataSet);

Begin

Mainform.incquerycount;

END;

INCQUERYCOUNT is defined in the unit of the main form:

Procedure tMainform.incqurycount;

Begin

Inc (FQUERYCOUNT);

Querycount.caption: = INTTOSTR (FQueryCount);

END;

Compile and run this application server. Open the customer's project, its main form is shown in Figure 14.26.

There is a TDCOMConnection component on the form for connecting the application server, with a TclientDataSet component called Events for introducing a data set.

"Starting Date" box is used to enter the value of the start_date parameter,

"Ending Date" box is used to enter the value of the End_Date parameter. The middle grid is used to display the result of the query. The "Description" box is used to display the value of the Event_Description field. The "photo" box is used to display the value of the Event_Photo field.

The client program initializes the "Starting Date" box and "endingDate" box in the handle of the oncreate event of the form.

Procedure TFORM1.FormCreate (Sender: TOBJECT);

Begin

Startdate.text: = DATETOSTR (Encodedate (96, 6, 19));

Enddate.text: = DATETOSTR (Encodedate (96, 6, 21));

END;

Users can re-enter other dates in these two boxes and click the "Show Events" button.

Procedure TFORM1.SHOWEVENTSCLICK (Sender: TOBJECT);

Begin

Events.close;

Events.Params.Parambyname ('start_date'). Asdatetime: = strtodatetime (startdate.text); Events.Params.Parambyname ('end_date'). Asdatetime: = stratodatetime (enddate.text);

Events.open;

END;

First, to call the TclientDataSet component, then set the value of the start_date parameter and the end_date parameter, finally, call the Open of the TclientDataSet component to open the dataset, this time, these two parameters are automatically passed to the application server. TQuery component.

转载请注明原文地址:https://www.9cbs.com/read-95930.html

New Post(0)