在做一个查询时,我用到了面向对象的一些知识,现在总结一下
程序中需要查询功能,查询要灵活,界面统一。这样许多的查询窗体的界面都是一样的,要是一个窗体一个窗体的做,而且界面是一样的,就是功能不同,很累的,我就想该怎么做省事呢?想到了
Delphi
的窗体继承的特性,对,我可以先做一个模板,然后让别的窗体继承这个窗体,不就达到界面的统一了,而且继承的窗体也可以在原窗体的基础上再添加控件,好就这么做了
我先做了一个窗体
如图
功能很简单,
[
查找
] [导出到 Excel] [打印] [关闭]
然后别的窗体来继承这个窗体,一个继承的窗体如下
没有什么变动,再看看别
的
也就是功能不一样,界面是一样的
这样就省了不少的力气,好,开始做查询的功能吧
根据不同的选择,要生成不同的
Sql
语句进行查询
……..
查询的功能完成,可以查询了
这个查询很麻烦的,要是在第二个窗体中也这很写,第三个窗体中再写,代码有好多的重复的,怎么办呢?刚学了学面向对象,能不能用面向对象来解决呢?看了看继承窗体的代码
TFocDeliverySearchForm = class(TFocSearchModelForm) ---à 从模板窗体继承
DBGridEh1: TDBGridEh;
Panel1: TPanel;
spbtFinder: TSpeedButton;
procedure FormCreate(Sender: TObject);
procedure btSearchClick(Sender: TObject);
procedure SpeedButton1Click(Sender: TObject);
procedure SpeedButton2Click(Sender: TObject);
procedure DBGridEh1DblClick(Sender: TObject);
procedure btExcelClick(Sender: TObject);
procedure btPrintClick(Sender: TObject);
procedure ComboFieldChange(Sender: TObject);
protected
function createSqlStr():string;override;
{ Private declarations }
public
Qj_Name,Qj_NameID:string;
end;
这不是从
TFocSearchModelForm
这个类继承来的吗?根据面向对象的特点,我可以把这些生成
Sql
语句的代码放到父类里,然后子类不就可以用了吗?但还有一个问题是查询的表是不同的,那该怎么做呢?
终于解决了,在父类中做一个虚拟方法,这个虚拟方法中我写主要的判断语句,也就是判断
Edit
里的内容,还有选择的是按什么查询。这个方法在每个继承的窗体中是一样的,继承的特性就是所的继承的控件的命名也是一样的。
好,代码如下:
Protected //
一定要用
protected
这个修饰符,这样在派生类中才可以看到这里定义的
sField,dField,iField:string; // 字符串字段,日期字段,数字字段
dValue,dValueDate1,dValueDate2:string; // 日期值
iValue,iValue1,iValue2:string; // 数字值
sValue:string; // 字符值
sOp:string; // 字符串的操作
dOp:string; // 日期的操作
iOp:string; // 数字的操作
theSqlStr :string;
QuerySear:TQuery;
ds:TDataSource;
function CreateSqlStr():string;virtual; // 虚方法
procedure receiptPerson(sender:tobject); // 收款人
procedure customerName(sender:tobject); // 客户名称
procedure stockName(sender:tobject); // 材料名称
……..
……..
function TFocSearchModelForm.CreateSqlStr:string;
var
sqlStr:string; // sql
begin
//
字符
sOp := self.ComboFunction.Text;
if self.edLookupText.Text <> '' then
begin
if sOP = '起始内容' then
sValue := ' like '''+self.edLookupText.Text+'%'''+sValue;
if sOp = '包含内容' then
sValue := ' like ''%'+self.edLookupText.Text+'%'''+sValue;
end
else
sValue := '';
//
日期
dOp := self.ComboDateFunction.Text;
if not ( (self.MaskEdit1.Text = ' - - ') and (self.MaskEdit2.Text=' - - ') ) then
begin
if self.MaskEdit1.Text = ' - - ' then dValueDate1 := dateTostr(now)
else dValueDate1 := self.MaskEdit1.Text;
if not TPublicFunction.StringIsDate(dValueDate1) then
begin
result := 'error';
exit;
end;
if self.MaskEdit2.Text = ' - - ' then dValueDate2 := dateTostr(now)
else dValueDate2 := self.MaskEdit2.Text;
if dOP = '期间' then
begin
if not TPublicFunction.StringIsDate(dValueDate2) then
begin
result := 'error';
exit;
end;
dValueDate1 := dValueDate1+' '+self.edTime1.Text+':'+self.edTime2.Text;
dValueDate2 := dValueDate2+' '+self.edTime3.Text+':'+self.edTime4.Text;
dValue := ' between '''+dValueDate1+''' and '''+dValueDate2+'''';
end
else
if dOp = '等于' then
begin
dValueDate1 := dValueDate1+' '+self.edTime1.Text+':'+self.edTime2.Text;
dValue := ' = '''+dValueDate1+'''';
end
else
begin
dValueDate1 := dValueDate1+' '+self.edTime1.Text+':'+self.edTime2.Text;
dValue := ''''+dValueDate1+'''';
end;
end
else // 日期同时为空
begin
dValue := '';
end;
//
数字
iOp := self.ComboValueFunction.Text;
if not ( (trim(self.Edit1.Text) = '') and (trim(self.Edit2.Text) = '') ) then
begin
iValue1 := trim(self.Edit1.Text);
ivalue2 := trim(self.Edit2.Text);
if iOp = '区间' then
begin
if iValue1 = '' then iValue1 := '0';
if ivalue2 = '' then iValue2 := '999999';
ivalue := ' between '+iValue1+' and '+iValue2;
end
else
if iOp = '=任意值' then
begin
iValue1 := '';
iValue2 := '';
iValue := '';
end
else
begin
if iValue1 <> '' then
iValue := ' '+iOp+iValue1+' ';
end;
end
else
begin
iValue := '';
end;
// 派生类要加上 select * from 表名 这句可以放在该位置以前的任意位置
SqlStr := SqlStr + ' where ' ;
if sValue <> '' then
begin
SqlStr := SqlStr + sField+sValue+' and ';
end;
if dValue <> '' then
begin
SqlStr := SqlStr + dField+dValue+' and ';
end;
if iValue <> '' then
begin
SqlStr := SqlStr + iField+iValue+' and ';
end;
// 派生类要加了编号 = 编号 这个一定要放在这里位置不能动
result := sqlStr;
end;
父类的方法做好了,子类呢?也就是继承的窗体该怎么做呢?继承的窗体,先看看上面的加了蓝颜色的注释
看完了,再看看继承的窗体是如何来
Override
这个方法的
function CreateSqlStr:string;override; // 生成 sql 语句
…..
……
function TFocOrderSearchForm.CreateSqlStr:string;
var
ss:string;
begin
self.theSqlStr := ' select * from focorder '; // 这里看到了父类的说明
case self.ComboField.ItemIndex of
0 : sField := 'customername';
1 : sField := 'orderstatus';
2 : sField := 'contactPerson';
end;
case self.ComboDate.ItemIndex of
0 : dField := 'DateArrival';
1 : dField := 'DateRequested';
2 : dField := 'DateFinished';
3 : dField := 'PromptDate';
end;
case self.ComboValue.ItemIndex of
0 : iField := 'TotalAmount';
1 : iField := 'PrepayAmt';
2 : iField := 'PaidAmt';
3 : iField := 'ReceivableAmt';
end;
ss := inherited createSqlstr; // 这里是执行父类的方法,取得这个
// sql 语句
if ss = 'error' then // 如果是 error 则再向上返回,退出
begin
result:=ss;
exit;
end;
self.theSqlStr := self.theSqlStr + ss; // 开组合这些 sql 语句了
self.theSqlStr := self.theSqlStr + ' orderid= orderid '; // 又找到了一个这里的作用是让
//
最后一个
and
也可以用上
//showmessage(self.theSqlStr);
end;
组合好
sql
语句了,好,看看查询按纽该怎么做了。
//---------------------
父类的查询按纽
----------------------------//
procedure TFocSearchModelForm.btSearchClick(Sender: TObject);
begin
with self.QuerySear do
begin
disableControls;
if active then close;
sql.Clear;
sql.Add(theSqlStr);
open;
enableControls;
end;
end;
//-------------------------
子类的查询按纽
-------------------------------//
procedure TFocOrderSearchForm.btSearchClick(Sender: TObject);
var
ss:string;
begin
self.iValue:='';
self.dValue:='';
self.sValue:='';
//showmessage( self.CreateSqlStr);
ss := self.CreateSqlStr;
if ss = 'error' then
begin
messagebox(0,pchar('输入的日期无效'),pchar('提示'),mb_ok+windows.MB_ICONWARNING);
exit;
end
else
inherited; // 在这了,没有错误,好,执行父类的查询吧
end;
通过做这个,更加深入了解了面向对象,以上的这个可以应用在任何的查询中。