unit DBPanel; interface uses windows, messages, sysutils, classes,graphics, controls, forms, dialogs, extctrls, dbctrls, stdctrls, db; type TDBPanel = class(tpanel) private { private declarations } fleft: integer; ftop: integer; maxtextlen: integer; maxlabellen: integer; fscrollbox: tscrollbox; {滚动控件} flineheight: integer; fclick: tnotifyevent; editors: array of tdbcombobox; file://- >具体进行编辑所用的数据控件数组,动态生成 labels: array of tlabel; file://- >各字段的标题,动态生成 okbutton: tbutton; file://- >最后增加的确定按钮,用于实现提交动作。 { 数据源} fdatasource: tdatasource; fcolumns: integer; file://- >输入表格的列数 protected { protected declarations } procedure freeeditors; file://- >释放数据输入控件的内存 public procedure createeditors(ds: tdatasource; colcount: integer); file://- >创建各字段的数据输入控件 constructor create(aowner: tcomponent); override; destructor destroy; override; procedure akeypress(sender: tobject; var key: char); procedure akeydown(sender: tobject; var key: word; shift: tshiftstate); procedure clearhits(itemindex: integer); procedure addhits(itemindex: integer; hits: array of string); function editor(index: integer): tdbcombobox; { public declarations } published property leftlimit: integer read fleft write fleft default 10; property toplimit: integer read ftop write ftop default 10; property editorlen: integer read maxtextlen write maxtextlen; property labellen: integer read maxlabellen write maxlabellen default 100; property lineheight: integer read flineheight write flineheight default 15; property onokclick: tnotifyevent read fclick write fclick; property datasource: tdatasource read fdatasource write fdatasource; file://数据源 property columns: integer read fcolumns write fcolumns;//- >表列数 { published declarations } end; procedure Register; implementation { 为第i字段增加提示信息的方法} procedure tdbpanel.addhits(itemindex: integer; hits: array of string); var m,n,i: integer; begin n := length(editors); m := length(hits); if itemindex< n then begin for i:=0 to m-1 do editors[itemindex].items.add(hits[i]); end; end; procedure tdbpanel.akeydown (sender: tobject; var key: word; shift: tshiftstate); begin if (sender is tdbcombobox) then begin case key of vk_next: (sender as tdbcombobox) .datasource.dataset.next; vk_prior: (sender as tdbcombobox) .datasource.dataset.prior; end; end; end; procedure tdbpanel.akeypress(sender: tobject; var key: char); begin if (sender is tdbcombobox) then begin if key=#13 then (owner as tform).perform(wm_nextdlgctl, 0, 0); end; end; procedure tdbpanel.clearhits(itemindex: integer); var n: integer; begin n := length(editors); if itemindex< n then editors[itemindex].items.clear; end; constructor tdbpanel.create(aowner: tcomponent); begin inherited create(aowner); fleft :=10; ftop := 10; maxtextlen := 100; maxlabellen := 100; flineheight := 15; end; { 创建各字段的数据输入控件的方法} procedure tdbpanel.createeditors(ds: tdatasource; colcount: integer); var i, n, rowcount: integer; textheight: integer; begin if datasource.dataset.active then begin n := datasource.dataset.fieldcount; { 计算最大的标题长度及显示长度} datasource.dataset.first; { 计算高度} textheight := canvas.textheight(datasource .dataset.fields[0].displaylabel) + flineheight; file://10; { 计算行列数} rowcount := n div columns; if n mod columns <> 0 then inc(rowcount); { 分配内存} freeeditors; setlength(editors, n); setlength(labels, n); { 创建滚动盒} fscrollbox := tscrollbox.create(owner); fscrollbox.parent := self; fscrollbox.align := alclient; { 创建编辑} for i:=0 to n-1 do begin { 创建标题} labels[i] := tlabel.create(owner); labels[i].parent := fscrollbox; file://self; labels[i].caption := datasource.dataset.fields[i].displaylabel; labels[i].left := fleft + (maxlabellen + maxtextlen + 10) * (i div rowcount); labels[i].width := maxlabellen; labels[i].top := ftop + (i mod rowcount) * textheight + 5; { 创建编辑对象} editors[i] := tdbcombobox.create(owner); editors[i].parent := fscrollbox; file://self; editors[i].left := labels[i].left + labels[i].width; editors[i].width := maxtextlen; editors[i].top := ftop + (i mod rowcount) * textheight; editors[i].datasource := datasource; editors[i].datafield := datasource.dataset.fields[i].fieldname; editors[i].onkeypress := akeypress; editors[i].onkeydown := akeydown; end; { 创建ok按钮} okbutton := tbutton.create(owner); okbutton.parent := fscrollbox; okbutton.left := editors[n-1].left; okbutton.top := editors[n-1].top + textheight; okbutton.caption := '确定'; okbutton.onclick := fclick; end; end; destructor tdbpanel.destroy; begin freeeditors; inherited destroy; end; function tdbpanel.editor(index: integer): tdbcombobox; begin if index< length(editors) then result := editors[index] else result := nil; end; procedure tdbpanel.freeeditors; var i,n: integer; begin { 内存的释放是要有顺序的!必须以创建的相反的顺序进行! 尤其是当组件之间有父子关系时} if okbutton<>nil then okbutton.free; if editors<>nil then begin n := length(editors); for i:=0 to n-1 do editors[i].free; editors := nil; n := length(labels); for i:=0 to n-1 do labels[i].free; labels := nil; end; if fscrollbox<>nil then begin fscrollbox.free; fscrollbox := nil; end; end; procedure Register; begin RegisterComponents('OK', [TDBPanel]); end; end.