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;