话框如图13.15所示。 最上面的“List”框是一个组合框,用于列出过去曾经输入过的过滤条件表达式。“ Condition”框是一个多行文本编辑器,用于输入过滤条件表达式。 “Fields”框是一个列表框,用于列出Customer表中的所有字段,因为过滤条件表达式中需要用到字段。因此,程序在处理这个窗口的OnCreate事件的句柄中首先要填充这个列表框。此外,程序还在“List”框中加入了两个过滤条件。 Procedure TfmFilterFrm. FormCreate(Sender: 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; 当用户从“List”框中选择或输入一个过滤表达式,应当首先把下面的“Condition”框清空,然后把用户选择或输入的过滤表达式加到“Condition”框中。 Procedure TfmFilterFrm.ComboBox1Change(Sender: TObject); Begin Memo1.Lines.Clear; Memo1.Lines.Add(ComboBox1.Text); End; 当用户在“Fields”框中双击一个字段,就把该字段加到“Condition”框中。 Procedure TfmFilterFrm.AddFieldName(Sender: TObject); Begin If Memo1.Text <> '''''''' then Memo1.Text := Memo1.Text + '''' ''''; Memo1.Text := Memo1.Text + ListBox1.Items[ListBox1.ItemIndex]; End; 当用户在“Operators”框中双击一个运算符,就把该运算符加到“Condition”框中。 Procedure TfmFilterFrm.ListBox2DblClick(Sender: TObject); Begin If Memo1.Text <> '''''''' thenMemo1.Text := Memo1.Text + '''' ''''+ ListBox2.Items[ListBox2.ItemIndex]; End; 由于用户有可能把过滤条件表达式分成几行写,因此,程序需要把以行为单位的字符串转换为一个字符串列表,因为Filter属性是一个TStrings对象。 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; 程序用两个复选框让用户设置过滤的选项。一个是“Case Sensitive”框,如果选中此框,FilterOptions属性中将包含foCaseInSensitive元素。另一个是“NoPartial Compare”框,如果选中此框,FilterOptions属性中将包含foNoPartialCompare元素。 Procedure TfmFilterFrm.cbCaseSensitiveClick(Sender: TObject); Begin With DM1.CustomerSource.Dataset Do If cbCaseSensitive.checked then FilterOptions := FilterOptions - [foCaseInSensitive]ElseFilterOptions := FilterOptions + [foCaseInsensitive]; End; Procedure TfmFilterFrm.cbNoPartialCompareClick(Sender: TObject); Begin With DM1.CustomerSource.Dataset Do If cbNoPartialCompare.checked then FilterOptions := FilterOptions + [foNoPartialCompare] Else FilterOptions := FilterOptions - [foNoPartialCompare]; End; 当用户输入了过滤条件表达式并且设置了过滤选项,就可以单击“Apply”按钮把过滤条件表达式赋给Filter属性: 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; 如果用户单击“Clear”按钮,就把“Condition”框清空,并把输入的过滤条件表达式加到“List”框中。 Procedure TfmFilterFrm.SBtnClearClick(Sender: TObject); var st: string; Begin Memo1.Lines.Clear; st := ComboBox1.Text; ComboBox1.Text := ''''''''; If ComboBox1.Items.IndexOf(st) = -1 then ComboBox1.Items.Add(st); End; 当用户单击“Close”按钮,就关闭这个窗口。 Procedure TfmFilterFrm.SBtnCloseClick(Sender: TObject); Begin Close; End; 13.9 一个复杂的数据库应用程序 这一节介绍一个复杂的数据库应用程序,项目名称叫Mastapp,它可以在C:\Program Files\Borland\Delphi4\Demos\Db\ Mastapp目录中找到。它的主窗体如图13.18所示。 图13.18 Mastapp的主窗体 这个程序比较复杂,读者一定要对它的程序结构搞清楚。我们先介绍主窗体。我们还是从处理OnCreate事件的句柄开始,因为这是应用程序的起点。 Procedure TMainForm.FormCreate(Sender: TObject); Begin ClientWidth := CloseBtn.Left + CloseBtn.Width + 1; ClientHeight := CloseBtn.Top + CloseBtn.Height; MainPanel.Align := alClient; Left := 0; Top := 0; InitRSRUN; End; 前面两行代码用于设置主窗口的宽度和高度。把Left属性和Top属性都设为0将使主窗口显示在屏幕的左上角。 注意:这个示范程序有一个错误是,从Delphi 3开始已经取消了ReportSmith,因此,这里调用InitRSRUN以及InitRSRUN中调用的UpdateRSConnect都是多余的。当用户使用“File”菜单上的“New Order”命令或单击工具栏上的“NewOrder”按钮,程序将打开“Order Form”窗口,代码如下: Procedure TMainForm.NewOrder(Sender: TObject); Begin EdOrderForm.Enter; End; 当用户使用“File”菜单上的“Print Report”命令,再选择“Customer List”,将调用PrintCustomerReport函数打印客户报表。 Procedure TMainForm.CustomerReport(Sender: TObject); Begin PrintCustomerReport(False); End; 其中,PrintCustomerReport是这样定义的: Procedure TMainForm.PrintCustomerReport(Preview: Boolean); Begin With MastData.CustByLastInvQuery Do Begin Open; If Preview then CustomerByInvoiceReport.Preview Else CustomerByInvoiceReport.Print; Close; End; End; 由于传递给Preview参数的值是False,因此,这里将打印而不是预览报表。当用户使用“File”菜单上的“Print Report”命令,再选择“Order History”,将调用PrintOrderReport函数打印定单报表。 Procedure TMainForm.OrderReport(Sender: TObject); Begin PrintOrderReport(False); End; 其中,PrintOrderReport是这样定义的: Procedure TMainForm.PrintOrderReport(Preview: Boolean); Const FromToHeading = ''''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 then 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(FromToHeading, [DateToStr(FromDate), DateToStr(ToDate)]); If Preview then OrdersByDateReport.Preview Else OrdersByDateReport.Print; Close; End; End; End; PrintOrderReport函数首先弹出一个如图13.19所示的对话框,让用户选择首尾日期。 图13.19 选择首尾日期 当用户选择了首尾日期并单击OK按钮,就预览报表,因为Preview参数是False。当用户使用“File”菜单上的“Print Report”命令,再选择“Invoice”,将调用PrintInvoiceReport函数打印发货单报表。 Procedure TMainForm.InvoiceReport(Sender: TObject); Begin PrintInvoiceReport(False); End; 其中,PrintInvoiceReport是这样定义的: Procedure TMainForm.PrintInvoiceReport(Preview: Boolean); Begin If PickOrderNoDlg.ShowModal = mrOk then If Preview then InvoiceByOrderNoReport.Preview Else InvoiceByOrderNoReport.Print; End; PrintInvoiceReport函数首先将弹出如图13.20所示的对话框,让用户选择定单编号。 图13.20 选择定单编号 当用户使用“File”菜单上的“Printer Setup”命令,将打开“打印设置”对话框。 Procedure TMainForm.PrinterSetupClick(Sender: TObject); Begin PrinterSetup.Execute; End; 当用户使用“View”菜单上的“Orders”命令或者单击工具栏上的“Browse”按钮,程序将打开“Order By Customer”窗口,代码如下: 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首先调用GetDateOrder函数返回日期的格式,然后弹出“OrderBy Customer”窗口。GetDateOrder函数是这样定义的: Function GetDateOrder(const DateFormat: string): TDateOrder; var I: Integer; Begin Result := doMDY; I := 1; While I <= Length(DateFormat) Do Begin Case Chr(Ord(DateFormat[I]) and $DF) of ''''Y'''': Result := doYMD; ''''M'''': Result := doMDY; ''''D'''': Result := doDMY; Else Inc(I); Continue; End; Exit; End; Result := doMDY; End; 当用户使用“View”菜单上的“Parts/Inventory”命令或单击工具栏上的“Parts”按钮,程序将打开“Browse Parts”窗口,代码如下: Procedure TMainForm.BrowseParts(Sender: TObject); Begin BrPartsForm.Show; End; 当用户使用“View”菜单上的“Stay On Top”命令,就使主窗口总是在屏幕的前端。 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; 请读者注意一个编程技巧,即怎样使窗口总是在屏幕前端。 这个程序可以让用户选择用本地数据库还是远程数据库。当用户选择“View”菜单上的“Local Data(Paradox Data)”命令时,就使用本地数据库。当用户选择“View”菜单上的“Remote Data(Local Interbase)”命令时,就使用Interbase数据库。注意:选择后者时,必须保证已安装Interbase服务器并且正在运行,否则会触发异常。 Procedure TMainForm.ViewLocalClick(Sender: TObject); Begin CloseAllWindows; MastData.UseLocalData; ViewLocal.Checked := True; Caption := Application.Title + '''' (Paradox Data)''''; End;
Procedure TMainForm.ViewRemoteClick(Sender: TObject); Begin CloseAllWindows; MastData.UseRemoteData; ViewRemote.Checked := True; Caption := Application.Title + '''' (Local Interbase)''''; End; 其中,UseLocalData和UseRemoteData是在数据模块的单元中定义的。在切换数据库之前必须调用CloseAllWindows关闭所有打开的窗口。CloseAllWindows是这样定义的: 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) then F.Close; End; End; End; 当用户单击工具栏上的“Reports”按钮,就打开“Report Select”窗口,让用户选择要打印或预览哪个报表,代码如下: 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;