Multi-level database development thirteen: Patter several database applications

xiaoxiao2021-03-06  100

Chapter 13 Patients Database Programming Technology of Delphi 4 in front of several database applications. In order to enable the reader to thoroughly understand the programming technology and flexibly use, we take the Delphi 4's demonstration procedures to analyze, these demonstration procedures have a very technical. To illustrate, we may ignore some details that are unrelated to topics when analyzing procedures.

13.1 Model Procedure for a Backstage Inquiry

This section analyzes a background query to the demonstration program, the project name is BKQuery, which can be found in the C: / Program Files / Borland / Delphi4 / DEMOS / DB / BKQUERY directory. Its main form is shown in Figure 13.1.

Figure 13.1 BKQuery's main form

Let's start from the handle of the oncreate event of the process of processing the form, because it is the starting point of the application. Procedure Tadhocform. Form: TOBJECT

Procedure CreateInitialini;

Const

VeryinefficientName = 'Ib:

Very inefficient query ';

VeryinefficientQuery = 'SELECT EMP_NO, AVG (SALARY) AS SALARY / N' 'From Employee, Employee, Employee / N' '

Group by EMP_NO ';

Amountduename = 'DB: Amount Due by Customer';

Amountduebycustomer = 'Select Company, Sum (itemstotal) - SUM (AmountPAID) AS AMOUNTDUE / N' '

From customer, ORDERS / N ' '

WHERE CUSTOMER.CUSTNO = Orders.custno / N ' ' Group by Company ';

Begin

With savedqueries do

Begin

WritestRing (VeryinefficientName, 'Query', Veryinefficient Query);

Writestring (VeryinefficientName, 'Alias', 'Iblocal');

WriteString (VeryinefficientName, 'Name', 'sysdba');

SavedQuerycombo.items.add (VeryinefficIntname);

Writestring (Amountduename, 'Query', AmountduebyCustomer);

Writestring (Amountduename, 'Alias'); "DBDEMOS');

WriteString (Amountduename, 'Name', '');

SavedQuerycombo.items.add (Amountduename);

END;

END;

Begin

Session.GetAliasNames (aliascombo.items);

SavedQueries: = TiniFile.create ('bkquery.ini');

SavedQueries.Readsections (SavedQueryCombo.items);

If SavedQuerycombo.items.count <= 0 THEN CREATEINIALINI;

SavedQuerycombo.itemindex: = 0; queryname: = savedQuerycombo.items [0];

Unmodify; readquery;

END;

Formcreate mainly did this a few things: First, it calls the TSession's GetAliasNames function to put all defined BDE alias into a string list, actually fill the "Database Alias" box in Figure 13.1. Next, a TINIFILE type object instance is created and the file name is bkquery.ini. If this file does not exist now, you need to call CreateInitialIni to create a file. As for how to write .ini files, this is not the subject of this chapter to discuss. Finally, call ReadQuery to read the relevant parameters saved in the file.

The READQUERY function is such a definition:

Procedure Tadhocform.Readquery;

Begin

IF not checkmodified kiln

With savedqueries do

Begin

QueryName: = savedQuerycombo.items [savedQuerycombo.itemindex];

QueryEdit.Text: = InisTRTOStr (ReadString (QueryName, 'Query', '');

Aliascombo.text: = readstring (queryname, 'alias',');

NameEdit.Text: = ReadString (queryname, 'name', '');

END;

Unmodify;

If Showing Thenif NameEdit.Text <> 'Ten Passwordedit.Setfocus Else

QueryEdit.Setfocus;

END;

When the user clicks on the "Execute" button, the program calls Background Query in the background. Procedure Tadhocform.executebtnclick (Sender: TOBJECT);

Begin

BackgroundQuery (queryname, aliascombo.text, nameEdit.text, queryedit.text);

Bringtofront;

END;

BackgroundQuery is defined in another unit called ResitFRM, which will focus on this process. When the user clicks on the "New" button, the program reinitializes some of the windows on the form.

Procedure Tadhocform.newbtnclick (Sender: TOBJECT);

Function UNIQUENAME: STRING;

VAR

I: integer;

Begin

I: = 1;

Repeat

Result: = Format ('query% d', [i]);

Until

SavedQuerycombo.items.indexof (Result) <0;

END;

Begin

Aliascombo.text: = 'dbdemos';

NameEdit.Text: = '';

Passwordedit.text: = '';

QueryEdit.Text: = '; queryedit.setfocus;

QueryName: = UNIQUENAME;

SavedQueryCombo.Index: = -1; unnamed: = true;

END;

When the user clicks the "Save" button, the program calls the SaveQuery function to save the current parameters to the .ini file.

Procedure Tadhocform.Savebtnclick (Sender: TOBJECT);

Begin

SaveQuery;

END;

SaveQuery is defined in this:

Procedure tadhocform.savequry;

Begin

IF unnamed the SaveQueryas

Else

With savedqueries do

Begin

WriteString (QueryName, 'Query', STRTOINISTR (QueryEdit.Text));

WriteString (queryname, 'alias', aliascombo.text);

WriteString (QueryName, 'Name', NameEdit.text); unmodify;

END;

END;

When the user clicks on the "Save AS" button, the program call SaveQueryAS function saves the relevant parameters in another name.

Procedure Tadhocform.SAVEASBTNCLICK (Sender: TOBJECT);

Begin

SaveQueryas;

END;

SaveQueryas is defined in this:

Procedure tadhocform.savequeryas;

Begin

IF getnewname (queryname) THEN

Begin

Unnamed: = false;

SaveQuery;

With SavedQueryCombo, Items DO

Begin

IF indexof (queryname) <0 Then Add (queryname);

ItemIndex: = indexof (queryname);

END;

END;

END;

Among them, getnewname is defined in a unit called SaveQas, which will open the dialog shown in Figure 13.2 to allow the user to enter a file name. Figure 13.2 Specify another file name In addition, the program has also handled the onchange event of the SavedQueryCombo box:

Procedure Tadhocform.SavedQueryCombochange (Sender: TOBJECT);

Begin

Readquery;

END;

The so-called background query is actually the use of multi-threaded programming technology to make the query in a special thread. To this end, first declare a thread object as a base class as a base class:

TypetQuerythread = Class (TTHREAD) PrivateQueryform: tQueryform;

MessageText: String;

PROCEDURE CONNECTQUERY;

Procedure displaymessage;

ProtectedProcedure Execute;

OVERRIDE;

Publicconstructor Create (AQueryform: tQueryform);

END;

Let's take a look at how thread objects are created:

Constructor Tquerythread.create (AQueryform: tQueryform);

Begin

Queryform: = aqueryform;

FreeOnterminate: = true;

Inherited Create (False);

END;

When the user clicks the "Execute" button, the program calls the BackgroundQuery function to execute the query in the background. BackgroundQuery is defined in this: Procedure BackgroundQuery (const queryname, alias, user, password, querytext: string);

VAR

Queryform: tQueryform;

Begin

Queryform: = tQueryform.create (Application);

With queryform, Database DO

Begin

Caption: = queryname;

Querylabel.caption: = querytext;

SHOW;

AliasName: = alias;

PARAMS.VALUES ['User']: = USER;

Params.values ​​['Password']: = password;

Query.sql.text: = querytext;

END;

TQuerythread.create (queryform);

END;

BackgroundQuery mainly made three things, one is dynamically created and displaying a form (tQueryform) because you want to display the query results in this form. The second is to assign the passing parameters to the SQL attribute of the AliasName, Params, and TQuery components of the TDADABASE component, respectively. The third is an example of creating a thread object. Since the freeOnterminate attribute of the thread object is set to True, it is not necessary to delete thread objects specifically.

Ok, let's take a look at the most critical code of this program, that is, the EXECUTE function of thread objects:

Procedure tquerythread.execute;

Varuniquenumber: integer;

Begin

Try

With queryform do

Begin

UNIQUENUMBER: = Getuniquenumber;

Session.SessionName: = Format ('% s% x', [session.name, uniqueenumber]);

Database.SessionName: = session.SessionName;

Database.DatabaseName: = Format ('% s% x', [Database.name, Uniqueenumber]);

Query.SessionName: = Database.SessionName;

Query.DatabaseName: = Database.databaseName;

Query.open;

Synchronize (ConnectQuery); MessageText: = 'Query OpenNed';

Synchronize (DisplayMessage);

END;

Except

ON E: Exception DO

Begin

MessageText: = format ('% s:% s.', [E.CLASSNAME, E.MESSAGE]);

Synchronize (DisplayMessage);

END;

END;

END;

Since this is a multi-threaded database application, there is a need to explicitly use the TSESSION component, and to ensure that the BDE session period for each thread is unique. Therefore, the program first calls getUniquenumber to get a unique serial number. Similarly, there are similar problems for the TDATABASE component.

Execute allows the main thread to execute ConnectQuery, DisplayMessage by Synchronize, because ConnectQuery, DISPLAYMESSAGE needs to be deal with VCL and must be used in Synchronize. 13.2 Demonstration program for a cache update

This section detailedly analyzes a caching update model program, the project name is Cache, which can be found in the C: / Program Files / Borland / Delphi4 / Demos / DB / Cacheup directory. Its main form is shown in Figure 13.3.

Figure 13.3 Cache main form

There is a "cached updates" check box on the main form, if this check box is selected, indicating using the cache update technology. Otherwise, it means that the cache update technology is not used. When the user modifies the data, the data is directly written to the data set.

There is also a "Update SQL" check box on the main form, if this check box is selected, indicating the use of the TUPDATESQL component to make a cache update.

When the user clicks the "Apply Updates" button, apply to the database to update the data.

When the user clicks the "Cancel Updates" button, all unresolved modifications will be canceled.

When the user clicks on the "Revert Record" button, the modification of the current record will be canceled.

There are several check boxes in the "Show Records" packet box, which are used to select which records you want to display in the grid, including unmodified records, modified records, insert records, and delete records.

Re-execute the query when the user clicks on the "RE-EXECUTE Query" button. In addition, this exemplary program also uses a calculation field to express the current update status.

Let's take a look at how to achieve the above functions. Before introducing the program code, we must introduce the data module Cachedata, because several key components are placed on this data module, as shown in Figure 13.4.

Figure 13.4 Data Module

There are four components on the data module, namely: a TDataSource component, which is called cacheds, a TDATABASE component named cachedb, a TQuery component named cacheQuery, a TupdateSQL component name UpdateSQL.

The TQUERY component's oncfields event is handled:

Procedure tcachedata.cacheQuerycalcfields (DataSet: tdatan);

ConstupdateStatusstr: array [tupdatestatus] of string = ('unmodified', 'modified', 'INSERTED');

Begin

If cachequery.cachedupdates the

CacheQueryUpdateStatus.Value: = updatestatusStr [cacheQuery.Updatestatus];

END;

The above code is used to assign a value to the calculation field cacheQueryUpdateStatus to display the current update status. The onupdateError event of the TQUERY component is processed:

Procedure tcachedata.updateerrorhandler (DataSet: TDataSet; E: eDatabaseerror;

Updatekind: tupdatekind;

VAR UpdateAction: tupdateAction;

Begin

UpdateAction: = UpdateerrorM.HandleError (Dataset, E, Updatek);

END;

Now let's go back to the main form, starting from the handle of the oncreate event of the hosting the main form. Procedure tcachedemoform. Form: TOBJECT

Begin

FDataSet: = cachedata.cacheds.dataset as tdbdata

FDataSet.cachedupdates: = cachedupdates.checked;

SetControlstates (fdataSet.cacheDupdates);

FDataSet.Open;

END;

The first row code removes the current data set from the DataSet property of the TDataSource component. The second line code is based on the check box cachedupdates to determine the cachedupdates property of the data set, and then call the SETCONTROLSTATES function setting the status of the control on the form, final call. Open executes the query. SetControlStates is defined in this:

Procedure TcacheDemoform.SetControlStates (Enabled: Boolean);

Begin

ApplyUpdateSbtn.enabled: = True;

Cancelupdatesbtn.enable;

RevertRecordbtn.Nabled: = true;

UNMODIFIEDCB.ENABED: = TRUE;

Modifiedcb.enabled: = true;

INSERTEDCB.ENABLED: = TRUE;

Delededcb.enabled: = true;

UseUpdateSql.enabled: = true;

END;

Below is an event to process some controls. The first is the ONCLICK event of check box cachedupdates:

Procedure tcachedemoform.toGGleUpdatemode (Sender: TOBJECT);

Begin

FDataSet.cachedupdates: = not fdatanet.cachedupdates;

SetControlstates (fdataSet.cacheDupdates);

END;

Check box UseUpdateSQL's onclick event is processed:

Procedure tcachedemoform.useUpdatesqlclick (sender: TOBJECT);

Begin

FDataSet.Close;

IF useupdatesql.checked then

FDataSet.UpdateObject: = Cachedata.UpdateSqlelsefDataSet.UpdateObject: = NIL;

FDataSet.Open;

END;

When the user clicks the "Apply Updates" button, apply to the database to update the data.

Procedure Tcachedemoform.ApplyUpdateSbtnclick (Sender: TOBJECT);

Begin

FDataSet.Database.Applyupdates ([FDataSet]);

END;

When the user clicks the "Cancel Updates" button, all unresolved modifications will be canceled.

Procedure tcachedemoform.cancelupdatesbtnclick (sender: TOBJECT);

Begin

FDataSet.cancelupdates;

END;

When the user clicks on the "Revert Record" button, the modification of the current record will be canceled.

Procedure TcacheDemoform.revertRecordbtnclick (Sender: TOBJECT);

Beginfdataset.revertRecord;

END;

Several check boxes in the "Show Records" packet box, their OnClick event is processed:

Procedure tcachedemoform.UpdateRecordstoshow (Sender: TOBJECT); VARUPDRECTYPES: TUPDATERECORDTYPES;

Begin

UPDRECTYPES: = [];

IF unmodifiedcb.checked the

INCLUDE (UPDRECTYPES, RTUNMODIFIED);

If MODIFIEDCB.CHECKED THEN INCLUDE (UPDRECTYPES, RTMODIFIED);

IF insertedcb.checked kiln incl inde (UpdRectypes, Rtinserted);

If deletedcb.checked kilud (UpdRectypes, RTDelete);

FDataSet.UpdateRecordtypes: = UpdRectypes;

END;

The UpdateRecordstoshow function first declares a TupdateRecordtypes type variable UPDRECTYPES, and initializes it into an empty collection. Then determine if the four check boxes are selected, if selected, include the corresponding elements into this collection, as the UpdateRecordtypes property of the data set.

Re-execute the query when the user clicks on the "RE-EXECUTE Query" button.

Procedure tcachedemoform.reexecutebuttonclick (sender: TOBJECT);

Begin

FDataSet.Close;

FDataSet.Open;

END;

In addition, on the main form, there is a menu command called About, this command will call SHOWABOUTDIALOG to open a dialog.

SHOWABOUTDIALOG is defined in this:

Procedure showaboutdialog;

Begin

With TaboutDialog.create (Application) DO

Try

AboutMemo.lines.LoadFromFile (extractfilepath) 'about.txt';

ShowModal;

Finallyfree;

END;

END;

13.3 A Client / Server Demonstration Procedure

This section analyzes a Client / Server demonstration program, the project name is CSDemos, which can be found in the C: / Program Files / Borland / Delphi4 / Demos / DB / CSDemos directory. Its main form is shown in Figure 13.5.

Figure 13.5 Main form of CSDemos

When the user clicks on the "Show a View In Action" button, open the FRMViewDemo window.

Procedure tfrmlauncher.btnviewsclick (sender: TOBJECT);

Begin

FRMViewDemo.showModal;

END;

When the user clicks on the "SALARY CHANGE TRIGGER DEMO button, open the FRMTRIGGERDEMO window.

Procedure tfrmlauncher.btntriggclick (sender: TOBJECT);

Begin

FRMTRIGGERDEMO.SHOWMODAL;

END;

When the user clicks on the Query Stored Procedure Demo button, open the FRMQueryProc window.

Procedure tfrmlauncher.btnqryspclick (sender: TOBJECT); Begin

FRMQUERYPROC.SHOWMODAL;

END;

When the user clicks on the "Executable Stored Procedure" button, open the FRMEXECPROC window.

Procedure tfrmlauncher.btnexecspclick (sender: TOBJECT);

Begin

Frmexecproc.showmodal;

END;

When the user clicks on the "Transaction Editing" button, open the FRMTRANSDEMO window.

Procedure tfrmlauncher.btntransclick (sender: TOBJECT);

Begin

FRMTRANSDEMO.SHOWMODAL;

END;

Let's introduce these windows in detail. The FRMViewDemo window is shown in Figure 13.6.

Figure 13.6 FRMVIEWDEMO Window

When this window is popped up, first call the OPEN function of the TTable component to open the data set.

Procedure tfrmviewdemo.formshow (sender: TOBJECT);

Begin

Varyingtable.open;

END;

The program uses two shortcuts to switch the table name, where one button is corresponding to the EMPLOYEE table.

Procedure TfrmViewDemo.BtnshowemPloyeeclick (Sender: TOBJECT);

Begin

ShowTable ('EMPLOYEE');

END;

On the right, a button corresponds to the Phone_List table.

Procedure TfrmViewDemo.BtnshowPhoneListClick (Sender: TOBJECT);

Begin

ShowTable ('Phone_List');

END;

ShowTable is defined in this:

Procedure tfrmviewdeMo.showTable (atable: string);

Begin

Screen.cursor: = CRHOURGLASS;

VaryingTable.disableControls;

VaryingTable.Active: = false;

VaryingTable.tablename: = atable;

Varyingtable.open;

VaryingTable.enableControls;

Screen.cursor: = CRDEFAULT;

END;

The FRMTRIGERDEMO window is shown in Figure 13.7:

Figure 13.7 FRMTRIGGERDEMO window

When this window is popped up, first call the Open of the two TTable components to open the data set.

Procedure tfrmtriggerDemo.formshow (sender: TOBJECT);

Begin

DMemPloyee.Employeetable.open;

DMemPloyee.salaryhistoryTable.Open;

END;

Where DMemPloyee is the name of the data module. The FRMQueryProc window is shown in Figure 13.7.

Figure 13.7 FRMQUERYPROC

The ONSHOW event will be triggered when this window pops up. This event is handled in this way:

Procedure TfrmQueryProc.FormShow (Sender: TOBJECT);

Begin

DMemPloyee.Employeetable.open;

Employeesource.enabled: = TRUE;

With EmployeeprojectsQuery Do

IF not active.

First call the Employeetable Open Open the dataset, then set the Enabled property of the data source Employeesource to True, then call the Prepare ready to query.

In order to perform a query, the program handles the Ondata Accenge event of the data source Employeesource:

Procedure TfrmQueryProc.employeedatachange (Sender: TObject; Field: Tfield);

Begin

Employeeprojectsquery.close;

EmployeeprojectsQuery.Params [0] .asinteger: = DMemPloyee.employEetableemp_no.view;

Employeeprojectsquery.open;

Writemsg ('Employee' DMemPloyee.employeetableEmp_No.emPloyEetableEmp_no.Asstring 'Is Assigned to' INTOSTR (Employeeprojectsquery.Recordcount) 'Project (s).');

END;

The purpose of calling WRITEMSG is to display a message on the status bar. WriteMsg is defined in this:

Procedure TfrmQueryProc.writeMsg (strwrite: string);

Begin

Statusbar1.simpletext: = strwrite;

END;

Finally, when this window is temporarily hidden, the Enabled property of the data source Employeesource should be set to FALSE:

Procedure TfrmQueryProc.FormHide (Sender: TOBJECT);

Begin

Employeesource.Nabled: = false;

END;

The FRMEXECPROC window is shown in Figure 13.8.

Figure 13.8 FRMEXECPROC

The ONSHOW event will be triggered when this window pops up. This event is handled in this way:

Procedure TFRMEXECPROC.FORMSHOW (Sender: TOBJECT);

Begin

DMemPloyee.salesTable.Open;

DMemPloyee.customertable.open;

SalesSource.Nabled: = true;

END;

When the user browses the record in the grid, the ONDATACHANGE event of SalesSource will be triggered. In handling this event's handle, it is necessary to determine if the value of the ORDER_STATUS field is shipped, if yes, make the "ship order" button valid.

Procedure TFRMEXECPROC.SALESSOURCEDATACHANGE (Sender: TFIELD);

Begin

If DMEMPLOYEE.SAASTABLE ['Order_Status'] <> null then

BtnshiPorder.enabled: = ansicomparetext (DMemPloyee.salestable ['Order_Status'], 'Shipped') <> 0;

END;

When the user clicks on the "Ship Order" button, the stored procedure is executed, the parameters of the stored procedure are taken from the PO_NUMBER field.

Procedure TFRMEXECPROC.BTNSHIPORDERCLICK (Sender: TOBJECT);

Begin

With dmemployee dobegin

ShiporderProc.Params [0] .sstring: = SalesTable ['PO_NUMBER'];

ShiporderProc.execproc;

SalesTable.Refresh;

END;

END;

The FRMTransdemo window is shown in Figure 13.9.

This window demonstrates how to handle transactions. First, you want to call the STARTTRANSACTION of the Employeedatabase (TDatabase member) to start a new transaction. Thereafter, all modifications to the database are temporarily kept in the cache until the program is called COMMIT or ROLLBACK.

Procedure tfrmtransdemo.formshow (sender: TOBJECT);

Begin

DMEMPLOYEE.EMPLOYEDATABASE.STARTTRANSACTION;

DMemPloyee.Employeetable.open;

END;

When the user clicks the "Commit Edits" button, the data is submitted to the server. First access the IntraSection property of the TDATABASE component to see if the current is being processed. If so, a dialog is also popped up so that the user confirms whether to submit the data. The program code is as follows:

Procedure TfrmTransDemo.BtncommiteditsClick (Sender: TOBJECT);

Begin

If DMEMPLOYEE.EMPLOYEDATABASE.INTRANSACTION AND (MESSAGEDLG ('Are you have you want to commit you changes?', MTConfirmation, [mbyes, mbno], 0) = mryes) THEN

Begin

DMemPloyee.employeedatabase.commit;

DMEMPLOYEE.EMPLOYEDATABASE.STARTTRANSACTION;

DMemPloyee.employeetable.refresh;

End

Else

Messagedlg ('CAN 抰 Commit Changes: No Transaction Active ", mTerror, [Mbok], 0);

END;

If the user answers YES, call the CommIT to submit the data to the server. When the user clicks the "undo edits" button, call the Rollback to cancel all modifications.

Procedure TfRmTransDemo.BtnundoEditsClick (Sender: Tobject);

Begin

If DmEmployee.EmployeeDatabase.InTransaction and (MessageDlg ( 'Are you sure you want to undo all changes made during the' 'current transaction?', MtConfirmation, [mbYes, mbNo], 0) = mrYes) then

Begin

DMemPloyee.employeedatabase.rollback;

DMEMPLOYEE.EMPLOYEDATABASE.STARTTRANSACTION;

DMemPloyee.employeetable.refresh;

End

Else

Messagedlg ('CAN 抰 undo edits: no transaction active ", mtror, ​​[mbok], 0);

END;

When the window is about to be hidden, you should also call the commits to submit data to the server because the user may not click the "Commit Edits" button. Procedure tfrmtransdemo.FormHide (Sender: TOBJECT);

Begin

DMemPloyee.employeedatabase.commit;

END;

13.4 Demonstration Procedure for a TDBCTRLGRID component

This section analyzes a TDBCTRLGRID component, the project name is Ctrlgrid, which can be found in the C: / Program Files / Borland / Delphi4 / Demos / DB / CtrlGrid directory. Its main form is shown in Figure 13.10.

Let's introduce the data module first, because several key components are on the data module, as shown in Figure 13.11

It can be seen that there are three TTable components and three TDataSource components on DM1, which accesses the master table, Industry table, and Holdings tables, respectively.

There are two grids on the main form, one is the raster established with the TDBGRID component, the other is the raster established with the TDBCTRLGRID component, which uses the same TDBNAVIGATOR component to navigate.

This program uses such a programming skill. When the user moves the input focus to the grid established by the TDBGRID component, the navigator is established for the TDBGRID component; when the user moves the input focus to the grid established by the TDBCTRLGRID component In time, the navigator is established for the TDBCTRLGRID component. The program code is as follows:

Procedure tfmctrlgrid.dbgrid1enter (sender: TOBJECT);

Begin

DBNAVIGATOR1.DATASOURCE: = DM1.DSMaster;

END;

Procedure tfmctrlgrid.dbctrlgrid1enter (Sender: TOBJECT);

Begin

DBNAVIGATOR1.DATASOURCE: = DM1.DSHOLDINGS;

END;

When the main form is popped up, the ONSHOW event will be triggered. The program is to handle the Onse event:

Procedure tfmctrlgrid.formshow (sender: TOBJECT);

Begin

DM1.CalculateTotals (Sender, NIL);

END;

Among them, CalculateTotals is used to calculate several values, which will be displayed in the "InvestmentValue" box. CalculateTotals is defined in the unit of data module DM1:

Procedure Tdm1.calculateTotals (Sender: TField);

VAR

FLTOTALCOST, FLTOTALSHARES, FLTOTALUE, FLDIFMERENCE: REAL

Strformatspec: string;

Begin {Number of time display stock transactions

Fmctrlgrid.lpurchase.caption: = INTTOSTR (TBLHOLDINGS.Recordcount);

{If the number of stock transactions is 0, the value in the "Investment Value" box is clear.

If TBLHOLDINGS.Recordcount = 0 THEN

Begin

Fmctrlgrid.ltotalcost.caption: = '';

Fmctrlgrid.ltotalshares.caption: = '';

Fmctrlgrid.ldiference.caption: = ';

End

Elsebegin

{Set the cursor as an hourglass, because the time calculated value may be longer}

Screen.cursor: = CRHOURGLASS;

{Initialize the value to 0.0}

FLTOTALCOST: = 0.0;

FLTOTALSHARES: = 0.0;

{Calculating the amount of shares holding the stock}

TBLHOLDINGS.DISABLECONTROLS;

TBLHOLDINGS.FIRST;

While not tblholdings.eof do

Begin

Fltotalcost: = flotalcost tblholdingspur_cost.asfloat; flotalshares: = flotalshares tblholdinsssssssss.Asfloat;

TBLHOLDINGS.NEXT;

END;

TBLHOLDINGS.FIRST;

TBLHOLDINGS.ENABLECONTROLS; {calculate the market value of the stock}

FLTOTALVALUE: = flotalshares * tblmastercur_price.Asfloat;

FLDIFCERENCE: = flotalvalue - fltotalcost;

Strformatspec: = tblmastercur_price.displayFormat;

{Display above data}

Fmctrlgrid.ltotalcost.caption: = formatfloat (Strformatspec, flotalcost);

Fmctrlgrid.ltotalshars.caption: = formatfloat (strformatspec, fltotalvalue);

Fmctrlgrid.ldifference.caption: = formatfloat (strformatspec, fldifference);

{If you make, you will display green. If it is a loss, it will be displayed in red}

IF fldifference> 0 Then fmctrlgrid.ldifference.font.color: = CLGREEN

Else fmctrlgrid.ldifference.font.color: = CLRED;

Fmctrlgrid.ldifference.update;

{Recover the cursor}

Screen.cursor: = CRDEFAULT;

END;

END;

In addition, when the user selects the "About" command, the Abut box will open. The program code is as follows:

Procedure tfmctrlgrid.about1click (sender: TOBJECT);

Begin

With tfmaboutbox.create (nil) do

Try

ShowModal;

Finally

FREE;

END;

END;

When the data set of the HOLDINGS table is turned on, you will dynamically specify the handle of CalculateTotals as the handle of the OONDATAANGE event for DSMaster.

Procedure TDM1.TBLHOLDINGSAFTEROPEN (DataSet: TDataSet);

Begind

Smaster.ondataachange: = CALCULATALS;

END;

In addition, this program also demonstrates the use of bookmarks.

Procedure TDM1.TBLHOLDILDINGSAFTERPOST (DataSet: TDataSet);

VAR

BMCurrent: TBOOKMARK;

Begin

With TBLHOLDINGS DO

Begin

Bmcurrent: = getBookmark;

Try

CalculateTotals (NIL, NIL); gotobookmark (BMCurrent);

Finally;

FreeBookmark (BMCurrent);

END;

END;

END;

13.5 A demonstration program captures database error

This section analyzes a demonstration program that captures database errors, and the project name is DBERRORS, which can be found in the C: / Program Files / Borland / Delphi4 / Demos / DB / DBERRORS directory. Its main form is shown in Figure 13.11.

This program demonstrates how to capture the database error. Delphi 4 captures errors with OnPOSTERROR, ONEDITELETEEEEEEEError event, which is generated on the user's operation, such as modify, delete, and insert records.

First start from its data module. Its data module is called DM, as shown in Figure 13.12.

Figure 13.12 Data Module

It can be seen that there are three TTable components and three TDataSorce components on the data module, which accesses the Customer table, the Orders table, and the Items table, respectively.

It should be noted that these three tables are not parallel relationships, but a couple of master / detail relationships. For example, the MASTERSOURCE attribute of the Orders table specifies that the itemsource attribute must be specified as Customersource, and the MASTERSOURCE attribute of the Items table must be specified as OrdersSource. Therefore, these TTABLE components and Creation Order are important, and they cannot be mistaken.

The main form of this program is simple, there are three grids (TDBGRID components), display the data of the Customer table, the Orders table, and the Items table, respectively.

This program uses the same TDBNAVigator component to navigate through these three grids. Therefore, this program uses a small programming skill to dynamically switch the DataSource properties of the TDBNAVigator component. The program code is as follows:

Procedure tfmain.gridordersenter (Sender: TOBJECT);

Begin

DBNAVIGATOR1.DATASOURCE: = DM.ORDERSSOURCE;

END;

Procedure tfmain.gridcustomersenter (Sender: TOBJECT);

Begin

DBNAVIGATOR1.DATASOURCE: = DM.CUSTOMERSOURCE;

END;

Procedure tfmmain.gridItemSenter (Sender: TOBJECT);

Begin

DBNAVIGATOR1.DATASOURCE: = DM.Itemssource;

END;

If the user modifies, inserts, or deletes records in the Customer table, when the user is moved to the input focus to other grids, the user should call the user to write the user to the database.

Procedure tfmmain.gridcustomersexit (Sender: TOBJECT);

Begin

If DM.CUSTOMER.STATE IN [DSEDIT, DSINSERT] THEN DM.CUSTOMER.POST;

END;

In addition, an Abut box will appear when the user selects the "About" command. code show as below:

Procedure tfmmain.about1click (sender: TOBJECT);

VAR FMABOUTBOX: TFMaboutBox;

Begin

FMaboutBox: = tfmaboutbox.create (Self);

Try

Fmaboutbox.showmodal;

Finally

Fmaboutbox.free; end;

END;

The following focuses on how to capture errors. Any code to capture the wrong mistake is implemented in the unit of the data module, which is also one of the benefits of using the data module. When the program calls POST or the user clicks on the POST button on the navigator, the user is written to the database, if an error (may be because there is a repetitive customer number), the ONPOSTERROR event will be triggered. Let's take a look at how the Customer Table handles the onposterror event:

Procedure TDM.CUSTOMERPOSTERROR (DataSet: TDataSet; E: EDATABASEERROR; VAR Action: TData);

Begin

IF (e is edbengineerror) THEN

IF (e as edbengineerror). ErrorS [0]. Herrorcode = ekeyviol dam

Begin

Messagedlg ('Unable to Post: Duplicate Customer ID.', MTWARNING, [Mbok], 0);

Abort;

END;

END;

Where EDBEngineError is an exception class that handles BDE errors, you can access its Errors array to get the current error code. If the error code is ekeyviol, a dialog is displayed to tell the user that you cannot write the data to the database because there are duplicate customer numbers. Then call Abort to abandon this operation.

There is also an error while deleting a record in the Customer table, because the deleted customers also have records in the OrderS table and the Items table, which triggerates the OndleteError event. Let's take a look at how the Customer Table handles the OndleteError event:

Procedure Tdm.customerdeleteError (Dataset: TDataSet; E: edatabaseError; var Action: tdata);

Begin

IF (e is edbengineerror) THEN

IF (e as edbengineerror). ErrorS [0]. Errorcode = edetailsexist kil

Begin

Messagedlg ('to Delete this Record, First Delete Related Orders and items.', MTWARNING, [MBOK], 0);

Abort;

END;

END;

The reader may find that the way to handle the OndleteError event is similar to the way the ONPOSTERROR event is similar. First, the error code is EDETAILSEXIST, if yes, the deleted client also has records in the Orderse table and the items table, showing a dialog box. Tell the user: To delete this record, first delete the relevant records in the ORDERS table and the items table. Then call Abort to abandon this operation.

Since the CustNo field is a key field of the Customer table, when the user modifies the value of the CustNo field but not before POST, in order to prevent chaos from the raster of the OrderS table and the Items table, it is best to call the DisableControls function temporarily disabled Data, etc. Call the POST or the user after clicking the POST button on the navigator, then call the EnableControls function.

Procedure TDM.CUSTOMERCUSTNOCHANGE (Sender: tfield);

Begin

ORDERS.DISABLECONTROLS;

Items.disableControls;

END;

When the program calls POST or the user clicks on the POST button on the navigator, the AfterPost event will be triggered. The program is the AFTERPOST event of the Customer table: procedure tdm.customerafterpost (DataSet: tdatan);

Begin

DM.ORDERS.REFRESH;

DM.Items.Refresh;

DM.ORDERS.ENABLECONTROLS;

DM.Items.enableControls;

END;

For Items tables, how to process the ONPOSTERROR event is approximately the same as the Customer table processes the ONPOSTERROR event:

Procedure TDM.Itemsposterror (Dataset: TDataSet; E: edatabaseError; var Action: tdata);

Begin

IF (e as edbengineerror). ErrorS [0] .errorcode = EFOREIGNKEY THEN

Begin

Messagedlg ('Part Number Is Invalid', MtWarning, [Mbok], 0);

Abort;

END;

END;

The ORDERS table is to handle the onposterror event:

Procedure TDM.OrDersposterror (DataSet: TDataSet; E: edatabaseError; var Action: tdata);

VAR IDBIERROR: Integer;

Begin

IF (e is edbengineerror) THEN

Begin

IDBIERROR: = (e as edbengineerror). ErrorS [0]. ErrorCode;

Case idbierror of

EREquidFieldMissing:

{EMPNO field must have a value}

Begin

Messagedlg ('Please provide an Employee ID', MtWarning, [Mbok], 0);

Abort;

END;

EKEYVIOL:

{For the ORDERS table, the key field is ORDERNO}

Begin

Messagedlg ('unable to post. Duplicate order number', mtwarning, [mbok], 0);

Abort;

END;

END;

END;

END;

Since the ITEMS table depends on the ORDERS table, it is also wrong when the record in the ORDERS table is deleted. Therefore, the program handles the ORDELETEERROR event of the OrderS table. However, unlike the OndleteError event of the Customer Table, here is used to make the user choose whether to delete this "problem" record, if the user answers Yes, delete all the records of the items table, and then put The Action parameter is set to DareTry, indicating that after exiting this event handle, will re-try the record. If the user answers NO, call Abort to discard the operation.

Procedure TDM.OrDersdeleterror (Dataset: TDataSet; E: edatabaseError; var Action: tdata);

Begin

IF e is edbengineerror dam

IF (e as edbengineerror). ErrorS [0]. Errorcode = edetailsexist kil

Begin

IF Messagedlg ('delete this order and limited items?', MTConfirmation, [mbyes, mbno], 0) = mryester dam

Begin

While Items.Recordcount> 0 do

Items.Delete; Action: = DareTry;

End

Else

Abort;

END;

END;

13.6 A demonstration program for filtering data sets

This section analyzes a demonstration program that is filtered by the data set, the project name is Filter, which can be found in the C: / Program Files / Borland / Delphi4 / Demos / DB / Filter directory. Its main form is shown in Figure 13.13.

This demonstration program demonstrates how to dynamically set filter conditions by modifying the Filter property, how to change the filtering criteria in the handle of the ONFILTERRecord event, how to get parameters from another data set from another data set, and how to switch one grid data set.

We still start from the data module because several critical components are placed on the data module. The data module of this program is called DM1, as shown in Figure 13.14.

There is a TTable component called Customer on the data module to access the Customer table. There is a TQUERY component called Sqlcustomer, accesses the Customer table through the SQL statement, and its SQL statement is as follows:

SELECT * "Customer.db"

There is a TDataSource component on the data module called Customersource, which can be set to Customer or a SQLCustomer.

There is also a TQuery component on the data module called Sqlorders, used to query the OrderS table, the SQL statement is as follows:

Select * from Orders Where Custno =: Custno

The DataSource attribute of SQLORDERS is set to Customersource, indicating that the CustNO parameter is taken from the Customer table CustNo field. There are two grids on the main form, and this grid called dbgrid1, below this grid called DBGRID2.

The DataSource property of DBGRID1 is set to Customersource, and the Customersource's DataSet property can be set to Customer, or it can be set to SQLCustomer, which is switched by two radio buttons in the "DataSet" box.

Procedure tfmcustview.rgdatasetclick (sender: TOBJECT);

VAR

STRING;

Begin

With DM1, Customersource DO

Begin

If DataSet.filtered The St: = Dataset.filter;

Case rgdataset.itemindex of

0: if DataSet <> sqlcustomer the dataset: = SQLCUSTOMER;

1: if Customersource.DataSet <> Customer The DataSet: = Customer;

END;

IF st <> '' Then BegindataSet.Filter: = ST;

DataSet.filtered: = true;

END;

END;

END;

When the user clicks the "Filter Customers" button, open a window to allow the user to set the filter condition. About this window is later. Procedure tfmcustview.speedButton1Click (Sender: TOBJECT);

Begin

FMFilterfrm.show;

END;

DBGRID2 shows the data of the Orders table. The user can select whether to filter the data set through a checkbox, which is actually modifying the Filtered property of SqlORDERS.

Procedure TFMCustView.cbfilterRordersClick (Sender: TOBJECT);

Begin

DM1.SQLORDERDERS.FILTERED: = CBFilterOrDERS.CHECKED;

IF cbfilterorders.checked then

Edit1Change (NIL);

END;

If this check box is selected, call Edit1Change to assign the value input in the "Amount PAID" box to a common variable in the DM1 unit called Ordersfilteramount, what is the role of this variable, and later introduces the DM1 unit . Calling Refresh will trigger SQLORDERS's ONFILTERRECORD event. If the user typed non-digital characters in the "AmountPAID" box before calling Refresh, calling Refresh will trigger the EconvertError exception, so the program is protected by the TRY 匛 XCEPT structure.

Procedure tfmcustview.edit1change (sender: TOBJECT);

Begin

IF (cbfilterORDERS.CHECKED) and (edit1.text <> ') THEN

Try

DM1.OrDERSFILTERAMOUNT: = STRTOFLOAT (FMCustView.edit1.text);

DM1.SQLORDERS.REFRESH;

Excepton EconvertError Doraise Exception.create ('Threshold Amount Must Be a Number')

End

END;

The previous introduction of such programming skills, when a navigator is navigating a few data sets, should handle the Raster's OneNTER event to dynamically switch the DataSource property of the TDBNAVigator component.

Procedure tfmcustview.dbgrid1enter (sender: TOBJECT);

Begin

DBNAVIGATOR1.DATASOURCE: = dbgrid1.datasource;

END;

Procedure TFMCustView.dbgrid2enter (Sender: TOBJECT);

Begin

DBNAVIGATOR1.DATASOURCE: = DBGRID2.DATASOURCE;

END;

In addition, when the user selects the "About" command, the About box will appear. code show as below:

Procedure TFMCustView.about1click (Sender: TOBJECT);

Begin

With tfmaboutbox.create (nil) do

Try

ShowModal;

Finally

FREE;

END;

END;

This program also demonstrates how to handle ONFILTERRECORD events:

Procedure TDM1.SQLORDERSFILTERRECORD (DataSet: TDataSet; VAR Accept: Boolean);

Begin

Accept: = SqlordersamountPaid.Value> = Ordersfilteramount; End;

Readers pay attention, because ORDERSFILTERAMOUNT is a variable, this means that the user can dynamically change the filter condition as long as the value of this variable can make the filter condition. When the user clicks on the Filter Customers button, open a dialog to set the filter criteria. This dialog is shown in Figure 13.15.

The top "List" box is a combo box for listing the filtering conditions expressions that have been entered in the past. The "Condition" box is a multi-line text editor for entering filter conditional expression.

The "fields" box is a list box that lists all fields in the Customer table because the fields are required in the filter conditional expression. Therefore, the program first populates this list box in the handle of the oncreate event in which this window is handled. In addition, the program is also added to the "List" box to join two filter conditions.

Procedure TfmfilterFRM. Form: TOBJECT

VAR

I: integer;

Begin

For i: = 0 to dm1.customersource.DataSet.fieldcount - 1 DO

Listbox1.items.add (dm1.customer.fields [i] .fieldname);

ComboBox1.Items.add ('lastinvoicedate> =' '' datetostr (Encodedate (1994, 09, 30)) '' ');

ComboBox1.Items.add ('country =' US '' and lastinvoicedate> '' ' DateTostr (Encodedate (1994, 06, 30)) ' '');

END;

When the user selects or enters a filter expression from the "List" box, first empty the following "Condition" box, then select or entered filter expressions to the "Condition" box.

Procedure Tfmfilterfrm.comBobox1change (Sender: TOBJECT);

Begin

Memo1.Lines.clear;

Memo1.Lines.Add (ComboBoX1.Text);

END;

When the user doubles a field in the "Fields" box, add this field to the "CONDition" box.

Procedure TFMFilterfrm.addfieldName (Sender: TOBJECT);

Begin

IF memo1.text <> '' THEN

Memo1.Text: = MEMO1.TEXT '';

Memo1.text: = MEMO1.TEXT ListBox1.items [listbox1.itemindex];

END;

When the user doubles an operator in the "Operators" box, add the operator to the "Condition" box.

Procedure TFMFilterfrm.ListBox2dblclick (Sender: TOBJECT);

Begin

If Memo1.Text <> '' TenMemo1.Text: = MEMO1.TEXT '' ListBox2.Items [listbox2.itemindex];

END;

Since the user is likely to divide the filter condition expression into a few lines, the program needs to convert a string of strings in the behavior unit to a string list because the Filter property is a TStrings object. Procedure TFMFilterfrm.Memo1Change (Sender: TOBJECT);

VAR i: integer;

Begin

ComboBox1.Text: = MEMO1.LINES [0];

For i: = 1 to memo1.lines.count - 1 DO

ComboBox1.Text: = ComboBox1.text '' memo1.lines [i];

END;

The program uses two check box to allow the user to set the filtering option. One is a "case sensitive" box, if this box is selected, the FILterOptions property will contain the FocaseInSensitive element. The other is the "NOPArtial Compare" box, if this box is selected, the FonopArtialCompare element will be included in the FilterOptions property.

Procedure TFMFilterfrm.cbcasesensitiveClick (Sender: TOBJECT);

Begin

With dm1.customersource.dataset do

IF cbcasensensitive.checked then

FilterOptions: = filterOptions - [FocaseInSensitive] elsefilterOptions: = filterOptions [FocaseInSensitive];

END;

Procedure TFMFilterfrm.cbnopartialCompareClick (Sender: TOBJECT);

Begin

With dm1.customersource.dataset do

If cbnopartialcompare.checked kil

FilterOptions: = filteroptions [fonopartiaalth]

Else

FilterOptions: = filteroptions - [fonopartialCompare];

END;

When the user enters the filter condition expression and sets the filter option, you can click the "Apply" button to assign the filter condition expression to the Filter property:

Procedure Tfmfilterfrm.ApplyFilter (Sender: TOBJECT);

Begin

With dm1.customersource.dataset do

Begin

IF ComboBox1.text <> 'Then

Begin

Filter: = ComboBoX1.Text;

Filtered: = true;

FMCustView.caption: = 'Customers - Filtered';

End

Else

Begin

Filter: = '';

Filtered: = false;

FMCustView.caption: = 'Customers - Unfiltered'

END;

END;

END;

If the user clicks the "Clear" button, the "condition" box is empty and the input filter condition expression is added to the "List" box.

Procedure TFMFilterfrm.sbtnclearClick (Sender: TOBJECT);

Var st: string;

Begin

Memo1.Lines.clear;

St: = ComboBox1.text; ComboBox1.text: = '';

If ComboBox1.Items.indexOf (st) = -1 Ten ComboBox1.Items.Add (ST);

END;

When the user clicks on the "Close" button, turn off this window.

Procedure tfmfilterfrm.sbtncloseclick (sender: TOBJECT);

Begin

CLOSE;

END;

13.9 A complex database application

This section describes a complex database application that is called MastApp, which can be found in the C: / Program Files / Borland / Delphi4 / Demos / DB / MastApp directory. Its main form is shown in Figure 13.18.

Figure 13.18 Master Form for MastApp

This program is more complicated, and the reader must be clear about its program structure. Let's introduce the main form. We still start from the handle of the handling oncreate event, because this is the starting point of the application.

Procedure TMAINFORM.FORMCREATE (Sender: TOBJECT);

Begin

ClientWidth: = Closebtn.Left Closebtn.width 1;

Clientheight: = Closebtn.top Closebtn.Height;

Mainpanel.align: = alclient;

LEFT: = 0;

TOP: = 0;

INTRSRUN;

END;

The front two lines of code is used to set the width and height of the main window. Setting the LEFT attribute and TOP attribute to 0 will display the main window to the top left corner of the screen.

Note: This exemplary program has an error that ReportSmith has been canceled from Delphi 3, so the UpdatersConnect called initrsRun and the initrsConnect in the initrsRun is redundant. When the user uses the "New Order" command on the "File" menu or click the "Neworder" button on the toolbar, the program will open the "Order Form" window, the code is as follows:

Procedure TMAINFORM.NEWORDER (Sender: TOBJECT);

Begin

EdorderForm.Enter;

END;

When the user uses the "Print Report" command on the File menu, select "Customer List" to print the PrintCustomerReport function to print the customer report.

Procedure TMAINFORM.CUSTOMERREPORT (Sender: TOBJECT);

Begin

PrintCustomerReport (False);

END;

Among them, PrintCustomerReport is defined in this:

Procedure TMAINFORM.PRINTCUSTOMERREPORT (Preview: Boolean);

Begin

With mastdata.custbylastinvquery do

Begin

Open;

IF Preview Ten CustomerbyInvoiceReport.preview

Else

CustomerbyInvoiceReport.print;

CLOSE;

END;

END;

Since the value passed to the Preview parameter is False, it will be printed instead of preview reports. When the user uses the "Print Report" command on the File menu, select "Order History" and call the printorderReport function Print order report.

Procedure Tmainform.OrderReport (Sender: TOBJECT); BEGIN

PrintOrderReport (false);

END;

Among them, PrintOrderReport is defined in this:

Procedure TMAINFORM.PRINTORDERREPORT (Preview: Boolean);

Const windtoheading = 'from' '% s'' to ''% s' ';

Begin

With querycustdlg do

Begin

Msglab.caption: = 'print all Orders Ranging:';

If fromdate = 0 Then fromDate: = Encodedate (95, 01, 01);

IF Todate = 0 damhen Todate: = now;

If ShowModal = MROK THEN

With mastdata.ordersbyDateQuery DO

Begin

CLOSE;

Params.Parambyname ('fromdate'). Asdate: = fromdate;

Params.Parambyname ('Todate'). AsDate: = Todate;

Open;

ORDERSBYDATEREPORT.FROMTOHEADING.CAPTION: = Format (frekehead), DateTostr (Todate), DateTostr (Today)]);

IF Preview Then

ORDERSBYDATEREPORT.PREVIEW

Else ORDERSBYDATEREPORT.PRINT;

CLOSE;

END;

END;

END;

The PrintOrDerReport function first pops up a dialog shown in Figure 13.19 to allow the user to select the first date.

Figure 13.19 Select the first date

When the user selects the first date and click the OK button, preview the report because the preview parameter is false. When the user uses the "Print Report" command on the "File" menu, select "Invoice" and call the PrintInvoiceReport function to print the delivery single report.

Procedure TMAINFORM.INVOICEREPORT (Sender: TOBJECT);

Begin

PrintInvoiceReport (false);

END;

Among them, PrintInvoiceReport is defined in this:

Procedure TMAINFORM.PRINTINVOICEREPORT (Preview: Boolean);

Begin

IF pickordernodlg.showmodal = mrok dam

IF Preview Then

InvoicebyOrdernoreport.preview

Else

InvoiceByOrdernoreport.print;

END;

The PrintInvoiceReport function first pops up the dialog shown in Figure 13.20, allowing the user to select the order number.

Figure 13.20 Select the order number

When the user uses the "Printer Setup" command on the "File" menu, the Print Settings dialog opens.

Procedure TMAINFORM.PRINTERSETUPCLICK (Sender: TOBJECT);

Begin

Printersetup.execute;

END;

When the user uses the "order" command on the "View" menu or click the "Browse" button on the toolbar, the program will open the "Order By Customer" window, the code is as follows: Procedure TMAINFORM.BROWSECUSTORD (Sender: TOBJECT);

Begin

Case getDateOrder (shortdateformat) of

Doymd: shortdateFormat: = 'yy / mm / dd';

Domdy: shortdateFormat: = 'mm / dd / yy';

DODMY: ShortdateFormat: = 'DD / MM / YY';

END;

Brcustordform.show;

END;

BrowSecustord first calls the getDateOrder function to return the date of the date and pop up the "Orderby Customer" window. The GetDateOrder function is defined in this:

Function getDateOrder (const dateformat: string): TDATEORDER;

VAR i: integer;

Begin

Result: = Domdy;

I: = 1;

While i <= length (dateformat) do

Begin

Case Chr (DateFormat [i]) and $ df) of

'Y': result: = DOYMD;

'M': result: = Domdy;

'D': result: = DODMY;

Else INC (i);

CONTINUE;

END;

EXIT;

END;

Result: = Domdy;

END;

When the user uses the "Parts / Inventory" command on the View menu or click the "Parts" button on the toolbar, the program will open the "Browse Parts" window, the code is as follows:

Procedure TMAINFORM.BROWSEPARTS (Sender: TOBJECT);

Begin

Brpartsform.show;

END;

When the user uses the "Stay on TOP" command on the View menu, the main window is always on the front of the screen.

Procedure TMAINFORM.TOGGLESTAYONTOP (Sender: TOBJECT);

Begin

With sender as tmenuitem do

Begin

Checked: = not checked;

IF CHECKED THEN Mainform.FormStyle: = fsstayontop

Else Mainform.FormStyle: = fsnormal

END;

END;

Please read the reader to pay attention to a programming skill, how to make the window always on the front end of the screen.

This program allows users to choose a local database or a remote database. When the user selects the Local Data (PARADOX DATA "command on the" VIEW "menu, use the local database. When the user selects the "Remote Data" command on the "View" menu, use the InterBase database. Note: When you select the latter, you must ensure that the Interbase server is installed and is running, otherwise an exception is triggered.

Procedure TMAINFORM.VIEWLOCALCLICK (Sender: TOBJECT);

Begin

CloseallWindows;

Mastdata.uselocaldata;

Viewlocal.checked: = true;

CAPTION: = Application.Title '(Paradox Data)';

Procedure TMAINFORM.VIEWREMOTECLICK (Sender: TOBJECT);

Begin

CloseallWindows;

Mastdata.useremotedata;

ViewRemote.checked: = true;

CAPTION: = Application.Title '(local interbase)';

END;

Where used, UserData and UseRemoteData are defined in the unit of the data module. You must call CloseAllWindows to close all open windows before switching the database. CloseallWindows is defined in this:

Procedure Tmainform.CloseallWindows;

VAR i: integer;

F: tform;

Begin

For i: = 0 to Application.comPonentcount - 1 DO

Begin

If Application.components [I] is TFORM THEN

Begin

F: = tform (Application.Components [i]);

IF (f <> self) and (f.visible).

END;

END;

END;

When the user clicks the "Reports" button on the toolbar, open the "Report SELECT" window so that users choose which report to print or preview, the code is as follows:

Procedure TMAINFORM.REPORTBTNCLICK (Sender: TOBJECT);

Begin

With Pickrpt Do

If ShowModal = MROK THEN

Case reporttype.ItemIndex of

0: PrintCustomerReport (Preview);

1: PrintORDERREPORT (Preview);

2: PrintInvoiceReport (Preview);

END;

END;

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

New Post(0)