项目中有一个需求,为单据的表头增加自定义项。受制于现在的架构和表头布局自定义的实现机制,自定义项的内容只能预先在IDE里面创建好,而不能通过代码动态创建,只好在单据基类里面预先放入一组控件。由于自定义项本身需要提供编辑、参照、配置、读取与保存等操作,而基类本身已经臃肿不堪,接这个机会尝试一次界面与业务逻辑分离的尝试。因为架构中本身没有数据访问曾的设计和实现,而这个仅仅是作为一个尝试,因此控制类里面并没有对数据访问这块进行分离。类图如下:
因为自定义项目前支持的是3个,所以定义了一个常量来描述自定义项的个数,以后如果有扩充,修改这个常量即可。
详细代码如下:
1 { 2 该类用于控制单据表头自定义项。 3 created by fhying@2012.05.04 4 } 5 unit BillTitleCustomItemClass; 6 7 interface 8 9 uses 10 SysUtils, Classes, Controls, Variants, Dialogs, DB, DBClient, cxEdit, cxDBEdit, 11 Forms, Messages; 12 13 const 14 Const_BillTitleCustomItem_MAX = 3; 15 16 type 17 TBillTitleCustomItem = record 18 itemindex : Integer; {自定义项序号(1-3)} 19 itemtype : Integer; {自定义项类型(0编辑、1参照)} 20 itemdatasource : string; {参照的话,数据来源(目前考虑的是基本信息表,如附加说明)} 21 itemdatafield : string; {参照的话,数据来源的字段} 22 end; 23 TBillTitleCustomItems = array[1..Const_BillTitleCustomItem_MAX] of TBillTitleCustomItem; 24 25 TBillTitleCustomItemClass = class(TComponent) 26 private 27 FcdsSQL : TClientDataSet; 28 FBillType: Integer; 29 FBillTitleCustomItems : TBillTitleCustomItems; 30 FBillTitleCustomDataSource: TDataSource; 31 function GetBillTitleCustomItems: TBillTitleCustomItems; 32 procedure SetBillTitleCustomDataSource(const Value: TDataSource); 33 protected 34 { 根据索引获取自定义项的编辑组件 } 35 function GetButtonEdit(AItemIndex : Integer) : TcxDBButtonEdit; virtual; 36 { 初始化自定义项内容 } 37 procedure InitBillTitleCustomItems; 38 { 创建cds,用于执行sql语句 } 39 procedure CreateCDS; 40 { 保存自定义项配置到数据库 } 41 function SaveBillTitleCustomItems(AItemIndex : Integer = 0) : Boolean; 42 { 从数据库读取自定义项配置 } 43 procedure LoadBillTitleCustomItems; 44 { 为自定义项编辑组件进行事件绑定 } 45 procedure BindcxButtonEdits(AItemIndex : Integer = 0); virtual; 46 { 绑定自定义项组件的按钮单击事件 } 47 procedure PropertiesButtonClick(Sender: TObject; AButtonIndex: Integer); 48 { 执行自定义项编辑组件的参照功能 } 49 procedure Reference(AItemIndex : Integer); 50 { 打开自定义项的配置界面 } 51 procedure CustomConfig(AItemIndex : Integer); 52 { 绑定数据源 } 53 procedure SetEditDataSource; 54 public 55 { 自定义构造函数,传入单据类型。 } 56 constructor CreateMy(AOwnerForm : TComponent; ABillType : Integer); virtual; 57 destructor Destroy; override; 58 { 对外部调用者公布自定义项配置内容 } 59 property BillTitleCustomItems : TBillTitleCustomItems read GetBillTitleCustomItems; 60 { 外部调用者给对象设置数据源 } 61 property BillTitleCustomDataSource : TDataSource read FBillTitleCustomDataSource write SetBillTitleCustomDataSource; 62 end; 63 64 implementation 65 66 uses BillTitleCustomItemForm, un_DM, un_ShowForm, Main, PDWizard, 67 BaseBillA, ProdDw, un_ToolsLC; 68 69 { TBillTitleCustomItemClass } 70 71 procedure TBillTitleCustomItemClass.BindcxButtonEdits(AItemIndex : Integer); 72 var 73 i : Integer; 74 procedure BindcxButtonEdit(AItemIndex : Integer); 75 var 76 AItemType : Integer; 77 AEdit : TcxDBButtonEdit; 78 begin 79 AItemType := FBillTitleCustomItems[AItemIndex].itemtype; 80 AEdit := GetButtonEdit(AItemIndex); 81 if AEdit = nil then 82 Exit; 83 case AItemType of 84 0 : { 编辑 } 85 begin 86 AEdit.Properties.Buttons[0].Visible := False; 87 AEdit.Properties.ReadOnly := False; 88 end; 89 1 : { 参照 } 90 begin 91 AEdit.Properties.Buttons[0].Visible := True; 92 AEdit.Properties.ReadOnly := True; 93 end; 94 end; 95 { 用tag来标记是哪个自定义项 } 96 AEdit.Tag := AItemIndex; 97 { 与内置事件绑定 } 98 AEdit.Properties.OnButtonClick := PropertiesButtonClick; 99 end; 100 begin 101 if AItemIndex = 0 then 102 begin 103 for i := 1 to Const_BillTitleCustomItem_MAX do 104 begin 105 BindcxButtonEdit(i); 106 end; 107 end 108 else 109 begin 110 BindcxButtonEdit(AItemIndex); 111 end; 112 end; 113 114 procedure TBillTitleCustomItemClass.CreateCDS; 115 begin 116 if FcdsSQL = nil then 117 begin 118 FcdsSQL := TClientDataSet.Create(nil); 119 FcdsSQL.RemoteServer := DM.Con_SubWork; 120 FcdsSQL.ProviderName := 'dsp_Oper'; 121 end; 122 end; 123 124 constructor TBillTitleCustomItemClass.CreateMy(AOwnerForm: TComponent; 125 ABillType: Integer); 126 begin 127 inherited Create(AOwnerForm); 128 FBillType := ABillType; 129 InitBillTitleCustomItems; 130 LoadBillTitleCustomItems; 131 BindcxButtonEdits; 132 end; 133 134 procedure TBillTitleCustomItemClass.CustomConfig(AItemIndex : Integer); 135 var 136 frmBillTitleCustomItem: TfrmBillTitleCustomItem; 137 begin 138 frmBillTitleCustomItem := TfrmBillTitleCustomItem.Create(Application); 139 with frmBillTitleCustomItem do 140 begin 141 try 142 ItemType := FBillTitleCustomItems[ItemIndex].itemtype; 143 ShowModal; 144 if ModalResult = mrOK then 145 begin 146 FBillTitleCustomItems[AItemIndex].itemtype := ItemType; // 现在只能设置类型。 147 if SaveBillTitleCustomItems(AItemIndex) then 148 begin 149 { 保存前,已经更新了本地变量,所以不需要再从数据库获取一次。及时性要求不需要这样高。 } 150 {LoadBillTitleCustomItems;} 151 BindcxButtonEdits(AItemIndex); 152 end; 153 end; 154 finally 155 Free; 156 end; 157 end; 158 end; 159 160 destructor TBillTitleCustomItemClass.Destroy; 161 begin 162 if FcdsSQL <> nil then 163 begin 164 FcdsSQL.Close; 165 FcdsSQL.Free; 166 end; 167 inherited; 168 end; 169 170 function TBillTitleCustomItemClass.GetBillTitleCustomItems: TBillTitleCustomItems; 171 begin 172 Result := FBillTitleCustomItems; 173 end; 174 175 function TBillTitleCustomItemClass.GetButtonEdit( 176 AItemIndex: Integer): TcxDBButtonEdit; 177 var 178 AEditName : string; 179 AEdit : TComponent; 180 begin 181 AEditName := 'edtBillTitleCustomItem' + IntToStr(AItemIndex); 182 AEdit := TForm(Owner).FindComponent(AEditName); 183 if (AEdit <> nil) and (AEdit is TcxDBButtonEdit) then 184 Result := TcxDBButtonEdit(AEdit) 185 else 186 Result := nil; 187 end; 188 189 procedure TBillTitleCustomItemClass.InitBillTitleCustomItems; 190 var 191 i : Integer; 192 begin 193 for i := 1 to Const_BillTitleCustomItem_MAX do 194 begin 195 FBillTitleCustomItems[i].itemindex := i; 196 FBillTitleCustomItems[i].itemtype := 0; 197 FBillTitleCustomItems[i].itemdatasource := 'commoninfo'; 198 FBillTitleCustomItems[i].itemdatafield := 'u_Remark'; 199 end; 200 end; 201 202 procedure TBillTitleCustomItemClass.LoadBillTitleCustomItems; 203 begin 204 CreateCDS; 205 FcdsSQL.CommandText := 206 'select * from BillTitleCustomItem where billtype = '+IntToStr(FBillType)+' order by ItemIndex'; 207 FcdsSQL.Open; 208 with FcdsSQL do 209 begin 210 if RecordCount > Const_BillTitleCustomItem_MAX then 211 begin 212 Exit; 213 end; 214 First; 215 while not Eof do 216 begin 217 FBillTitleCustomItems[RecNo].itemindex := FieldByName('ItemIndex').AsInteger; 218 FBillTitleCustomItems[RecNo].itemtype := FieldByName('itemtype').AsInteger; 219 FBillTitleCustomItems[RecNo].itemdatasource := FieldByName('itemdatasource').AsString; 220 FBillTitleCustomItems[RecNo].itemdatafield := FieldByName('itemdatafield').AsString; 221 222 Next; 223 end; 224 end; 225 end; 226 227 procedure TBillTitleCustomItemClass.PropertiesButtonClick(Sender: TObject; 228 AButtonIndex: Integer); 229 begin 230 case AButtonIndex of 231 0 : Reference(TcxDBButtonEdit(Sender).Tag); 232 1 : CustomConfig(TcxDBButtonEdit(Sender).Tag); 233 end; 234 end; 235 236 { 因为现在这里只是针对进货单和销售单,且参照仅针对附加说明,所以先这样处理。 } 237 procedure TBillTitleCustomItemClass.Reference(AItemIndex : Integer); 238 var 239 szFieldName : string; 240 begin 241 if tclientdataset(BillTitleCustomDataSource.DataSet).ReadOnly then 242 Exit; 243 244 fm_main.vpSingleType := 13; 245 246 fm_ProdDw := Tfm_ProdDw.create(application); 247 try 248 with fm_ProdDw do 249 begin 250 fm_ProdDw.vpCalltype := 3; 251 252 T1_Showmodal(fm_ProdDw); 253 if modalresult = mrok then 254 begin 255 szFieldName := 'Item' + IntToStr(AItemIndex); 256 tclientdataset(BillTitleCustomDataSource.DataSet).Edit; 257 tclientdataset(BillTitleCustomDataSource.DataSet).FieldByName(szFieldName).AsString := cds_SingleList.FieldByName('U_Remark').AsString; 258 tclientdataset(BillTitleCustomDataSource.DataSet).Post; 259 end; 260 end; 261 finally 262 gl_Trans.Info1 := ''; 263 fm_ProdDw.free; 264 end; 265 end; 266 267 function TBillTitleCustomItemClass.SaveBillTitleCustomItems(AItemIndex : Integer): Boolean; 268 var 269 szSQL : string; 270 function MakeSaveSQL : string; 271 var 272 i : Integer; 273 szDelete : string; 274 szTmp : string; 275 begin 276 Result := ''; 277 if AItemIndex = 0 then 278 begin 279 szDelete := ' delete from BillTitleCustomItem where BillType = '+IntToStr(FBillType); 280 281 for i := 1 to Const_BillTitleCustomItem_MAX do 282 begin 283 szTmp := ' insert into BillTitleCustomItem (BillType, itemindex, itemtype, itemdatasource, itemdatafield) values (%d,%d,%d,'+Char(39)+'%s'+Char(39)+','+Char(39)+'%s'+Char(39)+')'; 284 with FBillTitleCustomItems[i] do 285 szTmp := Format(szTmp, [FBillType, itemindex, itemtype, itemdatasource, itemdatafield]); 286 287 Result := Result + szTmp ;//+ Char(13)+Char(10); 288 end; 289 end 290 else 291 begin 292 szDelete := ' delete from BillTitleCustomItem where BillType = '+IntToStr(FBillType) + ' and itemindex =' + IntToStr(AItemIndex); 293 szTmp := ' insert into BillTitleCustomItem (BillType, itemindex, itemtype, itemdatasource, itemdatafield) values (%d,%d,%d,'+Char(39)+'%s'+Char(39)+','+Char(39)+'%s'+Char(39)+')'; 294 with FBillTitleCustomItems[AItemIndex] do 295 szTmp := Format(szTmp, [FBillType, AItemIndex, itemtype, itemdatasource, itemdatafield]); 296 Result := Result + szTmp ; 297 end; 298 299 Result := szDelete + Result; 300 end; 301 begin 302 szSQL := MakeSaveSQL; 303 FcdsSQL.CommandText := szSQL; 304 try 305 FcdsSQL.Execute; 306 307 Result := True; 308 except 309 on e : Exception do 310 begin 311 Result := False; 312 ShowDlg(1, '保存单据表头自定义项设置失败。'+#13+'错误信息:'+#13+e.Message); 313 end; 314 end; 315 end; 316 317 procedure TBillTitleCustomItemClass.SetBillTitleCustomDataSource( 318 const Value: TDataSource); 319 begin 320 FBillTitleCustomDataSource := Value; 321 SetEditDataSource; 322 end; 323 324 procedure TBillTitleCustomItemClass.SetEditDataSource; 325 var 326 i : Integer; 327 AEdit : TcxDBButtonEdit; 328 begin 329 for i := 1 to Const_BillTitleCustomItem_MAX do 330 begin 331 AEdit := GetButtonEdit(i); 332 AEdit.DataBinding.DataSource := BillTitleCustomDataSource; 333 AEdit.DataBinding.DataField := 'Item'+IntToStr(i); 334 end; 335 end; 336 337 end.
此外,对于多账户支付的功能,我也用类似的思路设计了一个类,但是感觉里面比较紊乱,应该能够分得更清晰,降低耦合,增强内聚。请达者指教。谢谢。