ggleUpdateMode(Sender: TObject); Begin FDataSet.CachedUpdates := not FDataSet.CachedUpdates; SetControlStates(FDataSet.CachedUpdates); End; 复选框UseUpdateSQL的OnClick事件是这样处理的: Procedure TCacheDemoForm.UseUpdateSQLClick(Sender: TObject); Begin FDataSet.Close; If UseUpdateSQL.Checked then FDataSet.UpdateObject := CacheData.UpdateSQLElseFDataSet.UpdateObject := nil; FDataSet.Open; End; 当用户单击“Apply Updates”按钮,就向数据库申请更新数据。 Procedure TCacheDemoForm.ApplyUpdatesBtnClick(Sender: TObject); Begin FDataSet.Database.ApplyUpdates([FDataSet]); End; 当用户单击“Cancel Updates”按钮,所有未决的修改将被取消。 Procedure TCacheDemoForm.CancelUpdatesBtnClick(Sender: TObject); Begin FDataSet.CancelUpdates; End; 当用户单击“Revert Record”按钮,对当前记录所作的修改将被取消。 Procedure TCacheDemoForm.RevertRecordBtnClick(Sender: TObject); Begin FDataSet.RevertRecord; End; 在“Show Records”分组框内的几个复选框,它们的OnClick事件是这样处理的: Procedure TCacheDemoForm.UpdateRecordsToShow(Sender: TObject);varUpdRecTypes : TUpdateRecordTypes; Begin UpdRecTypes := []; If UnModifiedCB.Checked then Include(UpdRecTypes, rtUnModified); If ModifiedCB.Checked then Include(UpdRecTypes, rtModified); If InsertedCB.Checked then Include(UpdRecTypes, rtInserted); If DeletedCB.Checked thenInclude(UpdRecTypes, rtDeleted); FDataSet.UpdateRecordTypes := UpdRecTypes; End; UpdateRecordsToShow 函数首先声明了一个TUpdateRecordTypes类型的变量UpdRecTypes,并把它初始化为空的集合。然后依次判断四个复选框是否选中,如选中的话,就把对应的元素包含到这个集合中,作为数据集的UpdateRecordTypes属性。 当用户单击“Re-Execute Query”按钮,就重新执行查询。 Procedure TCacheDemoForm.ReExecuteButtonClick(Sender: TObject); Begin FDataSet.Close; FDataSet.Open; End; 此外,在主窗体上,还有一个菜单命令叫About,此命令将调用ShowAboutDialog打开一个对话框。 ShowAboutDialog是这样定义的: Procedure ShowAboutDialog; Begin With TAboutDialog.Create(Application) Do Try AboutMemo.Lines.LoadFromFile(ExtractFilePath(ParamStr(0))+''''ABOUT.TXT''''); ShowModal; FinallyFree; End; End; 13.3 一个Client/Server示范程序 这一节详细剖析一个Client/Server示范程序,项目名称叫Csdemos,它可以在C:\Program Files\Borland\Delphi4\Demos\Db\Csdemos目录中找到。其主窗体如图13.5所示。 图13.5 Csdemos的主窗体 当用户单击“Show a View in action”按钮时,就打开FrmViewDemo窗口。 Procedure TFrmLauncher.BtnViewsClick(Sender: TObject); Begin FrmViewDemo.ShowModal; End; 当用户单击“Salary Change Trigger Demo”按钮时,就打开FrmTriggerDemo窗口。 Procedure TFrmLauncher.BtnTriggClick(Sender: TObject); Begin FrmTriggerDemo.ShowModal; End; 当用户单击“Query Stored Procedure Demo”按钮时,就打开FrmQueryProc窗口。 Procedure TFrmLauncher.BtnQrySPClick(Sender: TObject); Begin FrmQueryProc.ShowModal; End; 当用户单击“Executable Stored Procedure Demo”按钮时,就打开FrmExecProc窗口。 Procedure TFrmLauncher.BtnExecSPClick(Sender: TObject); Begin FrmExecProc.ShowModal; End; 当用户单击“Transaction Editing Demo”按钮时,就打开FrmTransDemo窗口。 Procedure TFrmLauncher.BtnTransClick(Sender: TObject); Begin FrmTransDemo.ShowModal; End; 下面我们详细介绍这些窗口。FrmViewDemo窗口如图13.6所示。 图13.6 FrmViewDemo窗口 当这个窗口弹出时,首先调用TTable构件的Open函数打开数据集。 Procedure TFrmViewDemo.FormShow(Sender: TObject); Begin VaryingTable.Open; End; 程序用两个快捷按钮来切换表格名称,其中,左边一个按钮对应于EMPLOYEE表。 Procedure TFrmViewDemo.BtnShowEmployeeClick(Sender: TObject); Begin ShowTable(''''EMPLOYEE''''); End; 右边一个按钮对应于PHONE_LIST表。 Procedure TFrmViewDemo.BtnShowPhoneListClick(Sender: TObject); Begin ShowTable(''''PHONE_LIST''''); End; ShowTable是这样定义的: 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; FrmTriggerDemo窗口如图13.7所示: 图13.7 FrmTriggerDemo窗口 当这个窗口弹出时,首先调用两个TTable构件的Open打开数据集。 Procedure TFrmTriggerDemo.FormShow(Sender: TObject); Begin DmEmployee.EmployeeTable.Open; DmEmployee.SalaryHistoryTable.Open; End; 其中,DmEmployee是数据模块的名称。FrmQueryProc窗口如图13.7所示。 图13.7 FrmQueryProc 当这个窗口弹出时,将触发OnShow事件。这个事件是这样处理的: Procedure TFrmQueryProc.FormShow(Sender: TObject); Begin DmEmployee.EmployeeTable.Open; EmployeeSource.Enabled := True; With EmployeeProjectsQuery Do If not Active then Prepare; End; 首先调用EmployeeTable的Open打开数据集,然后把数据源EmployeeSource的Enabled属性设为True,接着调用Prepare准备查询。 为了执行查询,程序处理了数据源EmployeeSource的OnDataChange事件: Procedure TFrmQueryProc.EmployeeDataChange(Sender: TObject; Field: TField); Begin EmployeeProjectsQuery.Close; EmployeeProjectsQuery.Params[0].AsInteger :=DmEmployee.EmployeeTableEmp_No.Value; EmployeeProjectsQuery.Open; WriteMsg(''''Employee '''' + DmEmployee.EmployeeTableEmp_No.AsString +'''' is assigned to '''' + IntToStr(EmployeeProjectsQuery.RecordCount) +'''' project(s).''''); End; 调用WriteMsg的目的是在状态栏上显示一个消息。WriteMsg是这样定义的: Procedure TFrmQueryProc.WriteMsg(StrWrite: String); Begin StatusBar1.SimpleText := StrWrite; End; 最后,当这个窗口暂时隐去时,应当把数据源EmployeeSource的Enabled属性设为False: Procedure TFrmQueryProc.FormHide(Sender: TObject); Begin EmployeeSource.Enabled := False; End; FrmExecProc窗口如图13.8所示。 图13.8 FrmExecProc 当这个窗口弹出时,将触发OnShow事件。这个事件是这样处理的: Procedure TFrmExecProc.FormShow(Sender: TObject); Begin DmEmployee.SalesTable.Open; DmEmployee.CustomerTable.Open; SalesSource.Enabled := True; End; 当用户在栅格中浏览记录时,将触发SalesSource的OnDataChange事件。在处理这个事件的句柄中,要判断ORDER_STATUS字段的值是否是SHIPPED,如果是,就使“Ship Order”按钮有效。 Procedure TFrmExecProc.SalesSourceDataChange(Sender: TObject; Field: TField); Begin If DmEmployee.SalesTable[''''ORDER_STATUS''''] <> NULL then BtnShipOrder.Enabled :=AnsiCompareText(DmEmployee.SalesTable[''''ORDER_STATUS''''],''''SHIPPED'''')<>0; End; 当用户单击“Ship Order”按钮,就执行存储过程,存储过程的参数取自PO_NUMBER字段。 Procedure TFrmExecProc.BtnShipOrderClick(Sender: TObject); Begin With DmEmployee Do Begin ShipOrderProc.Params[0].AsString := SalesTable[''''PO_NUMBER'''']; ShipOrderProc.ExecProc; SalesTable.Refresh; End; End; FrmTransDemo窗口如图13.9所示。 这个窗口演示了怎样处理事务。首先,要调用EmployeeDatabase(TDatabase构件)的StartTransaction开始一次新的事务。此后,对数据库的所有修改都暂时保留在缓存中,直到程序调用Commit或Rollback。 Procedure TFrmTransDemo.FormShow(Sender: TObject); Begin DmEmployee.EmployeeDatabase.StartTransaction; DmEmployee.EmployeeTable.Open; End; 当用户单击“Commit Edits”按钮,就要向服务器提交数据。首先要访问TDatabase构件的InTransaction属性,看看当前是否正在处理事务。如果是的话,还要弹出一个对话框,让用户确认是否要提交数据。程序代码如下: Procedure TFrmTransDemo.BtnCommitEditsClick(Sender: TObject); Begin If DmEmployee.EmployeeDatabase.InTransaction and(MessageDlg(''''Are you sure you want to commit your changes?'''',mtConfirmation, [mbYes, mbNo], 0) = mrYes) then Begin DmEmployee.EmployeeDatabase.Commit; DmEmployee.EmployeeDatabase.StartTransaction; DmEmployee.EmployeeTable.Refresh; End Else MessageDlg(''''Can抰 Commit Changes:No Transaction Active'''',mtError, [mbOk], 0); End; 如果用户回答Yes的话,调用Commit向服务器提交数据。当用户单击“Undo Edits”按钮,调用Rollback取消所有的修改。 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.EmployeeDatabase.StartTransaction; DmEmployee.EmployeeTable.Refresh; End Else MessageDlg(''''Can抰 Undo Edits: No Transaction Active'''', mtError, [mbOk], 0); End; 在窗口即将隐去的时候,也要调用Commit向服务器提交数据,因为用户可能没有单击“Commit Edits”按钮。 Procedure TFrmTransDemo.FormHide(Sender: TObject); Begin DmEmployee.EmployeeDatabase.Commit; End; 13.4 一个TDBCtrlGrid构件的示范程序 这一节详细剖析一个TDBCtrlGrid构件的示范程序,项目名称叫Ctrlgrid,它可以在C:\ Program Files\Borland\Delphi4\Demos\Db\Ctrlgrid目录中找到。它的主窗体如图13.10所示。 我们先介绍数据模块,因为几个关键的构件在数据模块上,如图13.11所示 可以看出,DM1上有三个TTable构件和三个TDataSource构件,这三个TTable构件分别访问Master表、Industry表和Holdings表。 主窗体上有两个栅格,一个是用TDBGrid构件建立的栅格,另一个是用TDBCtrlGrid构件建立的栅格,这两个栅格都用同一个TDBNavigator构件来导航。 这个程序运用了这样一个编程技巧,当用户把输入焦点移到TDBGrid构件建立的栅格中时,导航器就为TDBGrid构件建立的栅格导航;当用户把输入焦点移到TDBCtrlGrid构件建立的栅格中时,导航器就为TDBCtrlGrid构件建立的栅格导航。程序代码如下: Procedure TFmCtrlGrid.DBGrid1Enter(Sender: TObject); Begin DBNavigator1.DataSource := DM1.DSMaster; End;
Procedure TFmCtrlGrid.DBCtrlGrid1Enter(Sender: TObject); Begin DBNavigator1.DataSource := DM1.DSHoldings; End; 当主窗体弹出时,将触发OnShow事件。程序是这样处理OnShow事件的: Procedure TFmCtrlGrid.FormShow(Sender: TObject); Begin DM1.CalculateTotals(Sender, nil); End; 其中,CalculateTotals用于计算几个数值,这些数值将显示在“InvestmentValue”框内。CalculateTotals是在数据模块DM1的单元中定义的: Procedure TDM1.CalculateTotals(Sender: TObject; Field: TField); var flTotalCost, flTotalShares, flTotalValue, flDifference: Real; strFormatSpec: string; Begin{显示股票交易的次数} FmCtrlGrid.lPurchase.Caption := IntToStr( tblHoldings.RecordCount ); {如果股票交易次数为0,就把“Investment Value”框内的数值清掉} If tblHoldings.recordCount = 0 then Begin FmCtrlGrid.lTotalCost.Caption := ''''''''; FmCtrlGrid.lTotalShares.Caption := ''''''''; FmCtrlGrid.lDifference.Caption := ''''''''; End Else Begin { 把光标设为沙漏状,因为计算数值的时间可能较长 } Screen.Cursor := crHourglass; { 把数值初始化为0.0 } flTotalCost := 0.0; flTotalShares := 0.0; { 计算购买所持股票的金额 } tblHoldings.DisableControls; tblHoldings.First; While not tblHoldings.eof Do Begin flTotalC上一页 [1] [2] [3] [4] 下一页 |