目录
1 前言
2 不定长表、定长表的定义
3 根据已有的电子表格制作数据库表并导入数据
3.1 订单
3.2 订单明细
3.3 客户
4 配置主从关联关系
5 继续增加一个主从关联关系
6 测试一下运行结果
7 一段代码用于实现在panel中画出字段列表面板
1 前言
实际工作中,经常遇到一对多的主从表编辑需求,例如,主表是订单列表,从表是每个订单包含的一个或多个产品信息。
这里尝试实现以下主从表编辑:
订单——订单明细,一对多
订单——客户,一对一
2 不定长表、定长表的定义
- 不定长表是指,与主表某条记录对应的从表记录数量不定,例如一个订单中,可能包含1种产品,也可能包含多种产品。
- 定长表与不定长表相反。例如,某个班级的学生明细为主表,对应的从表是每个学生的学科分数情况,每个学生对应的行数是固定的。
定长表与不定长表,需要不一样的处理。
3 根据已有的电子表格制作数据库表并导入数据
与上一篇操作相同,制作3个表:
3.1 订单
3.2 订单明细
3.3 客户
4 配置主从关联关系
工具——关联设计
注意是主表的订单ID字段与从表的订单ID进行关联,拖放的时候一定不要搞错了。
这样就完成了一个主从关系的配置。完成后,在编辑列表中自动显示出来。
双击可看到效果。
5 继续增加一个主从关联关系
订单表的客户ID字段与客户表的客户ID字段进行关联,完成后在主界面左上角编辑列表中自动显示出名称。
6 测试一下运行结果
由于两个主从关系指向同一个主表,所以在从表界面中,显示2个主从关系选项卡,可以切换使用。
7 一段代码用于实现在panel中画出字段列表面板
本来想实现可以自由拖动面板位置、拖放后在2个字段之间连线、保存面板状态等功能,太费时间,以后再说。这里仅仅实现最基本功能。
// 根据表名称画字段列表面板
procedure TFormLinks.drawTbl(parName, tblOrViewName, table_or_view: string; bCreateOrDestroy: boolean);
var
//iLinks: integer;
APanel: TPanel;
ACheckListBoxFldCn: TCheckListBox;
AListBoxTblEn, AListBoxFldEn: TListBox;
ALabel: TLabel;
//sql, sLeftPanelTop, sLeftPanelLeft, sRightPanelTop, sRightPanelLeft, linkNameTmp, srcTblTmp, dstTblTmp,
tblNameCn,
sFldCn, sFldEn: string;
begin
// 创建 table 面板
if bCreateOrDestroy = true then
begin
tblNameCn := clbTablesCnTobeChked.Items[clbTablesCnTobeChked.ItemIndex];
memo1.append('tblNameCn: ' + tblNameCn);
APanel := TPanel.Create(self);
APanel.Name := 'panel_' + tblOrViewName;
APanel.Parent := PanelMain;
APanel.Caption := '';
APanel.Hint := '';
if ifMouseClick = True then // 如果鼠标单击表名生成的panel
begin
if (panel_left + checkedTableCnt * 200) < PanelMain.Width then
APanel.Left := panel_left + checkedTableCnt * 300
else
APanel.Left := PanelMain.Width - 200;
//memo1.append('APanel.Left: ' + intToStr(APanel.Left));
APanel.Top := panel_top; // + (checkedTableCnt mod 2) * 100;
//memo1.append('APanel.Top: ' + intToStr(APanel.Top));
end
else // 如果不是鼠标点击表名生成的,则从数据库中读取位置信息
begin
end;
APanel.Height := 300; //ZROQuery.RecordCount * 20 + 30;
APanel.Width := 180;
// 中文字段名列表
if Assigned(FindComponent('clb_' + tblOrViewName)) then
FindComponent('clb_' + tblOrViewName).Destroy;
ACheckListBoxFldCn := TCheckListBox.Create(self);
ACheckListBoxFldCn.Name := 'clb_' + tblOrViewName;
ACheckListBoxFldCn.Parent := TPanel(FindComponent('panel_' + tblOrViewName));
ACheckListBoxFldCn.Height := 300; //ZROQuery.RecordCount * 20;
ACheckListBoxFldCn.Align := alClient;
//ACheckListBoxFldCn.Left:=0;
//ACheckListBoxFldCn.Top:=40;
ACheckListBoxFldCn.DragMode := dmAutomatic;
赋予创建的 CheckListBox 自定义函数
ACheckListBoxFldCn.OnClick := @ACheckListBoxClick;
自定义 复选列表 复选事件
//ACheckListBoxFldCn.OnClickCheck := ACheckListBoxClickCheck;
ACheckListBoxFldCn.OnDragOver := @ACheckListBoxDragOver;
ACheckListBoxFldCn.OnDragDrop := @ACheckListBoxDragDrop;
// 创建 listbox 用于记录原始英文表名(用于记录原始表名称)
if Assigned(FindComponent('lbt_' + tblOrViewName)) then
FindComponent('lbt_' + tblOrViewName).Destroy;
AListBoxTblEn := TListBox.Create(self);
AListBoxTblEn.Name := 'lbt_' + tblOrViewName;
AListBoxTblEn.Parent := TPanel(FindComponent('panel_' + tblOrViewName));
AListBoxTblEn.Height := 300; //ZROQuery.RecordCount * 10;
AListBoxTblEn.Width := 100;
AListBoxTblEn.Left := 60;
AListBoxTblEn.Top := 40;
AListBoxTblEn.Visible := false;
//memo1.Append('创建了:' + 'lbt_' + tblOrViewName);
// 创建 listbox 用于记录英文字段名(处理视图时用于查找英文字段)
if Assigned(FindComponent('lb_' + tblOrViewName)) then
FindComponent('lb_' + tblOrViewName).Destroy;
AListBoxFldEn := TListBox.Create(self);
AListBoxFldEn.Name := 'lb_' + tblOrViewName;
AListBoxFldEn.Parent := TPanel(FindComponent('panel_' + tblOrViewName));
AListBoxFldEn.Height := 300; // ZROQuery.RecordCount * 10;
AListBoxFldEn.Width := 100;
AListBoxFldEn.Left := 90;
AListBoxFldEn.Top := 120;
AListBoxFldEn.Visible := false;
ALabel := TLabel.Create(self);
ALabel.Name := 'lbl_' + tblOrViewName;
ALabel.Caption := tblNameCn;
ALabel.Parent := TPanel(FindComponent('panel_' + tblOrViewName));
ALabel.Align:= alTop;
//ALabel.Top := 0; //ACheckListBoxFldCn.Top - 17;
//ALabel.Left := 0; //ACheckListBoxFldCn.Left + 5;
ALabel.BorderSpacing.Left := 5;
ALabel.BorderSpacing.Bottom := 5;
//ALabel.Color := $7FFF0000;
ACheckListBoxFldCn.Clear;
//AListBoxTblEn.Clear;
AListBoxFldEn.Clear;
Form_main.queryFields.disablecontrols;
//ACheckListBoxEn.Clear;
Form_main.queryFields.First;
while not Form_main.queryFields.EOF do
begin
if Form_main.queryFields.FieldByName('TABLE_NAME_EN').AsString = tblOrViewName then
begin
sFldCn := Form_main.queryFields.FieldByName('FIELD_NAME_CN').AsString;
sFldEn := Form_main.queryFields.FieldByName('FIELD_NAME_EN').AsString;
ACheckListBoxFldCn.Items.Add(sFldCn);
AListBoxTblEn.items.Add(tblOrViewName);
AListBoxFldEn.Items.Add(sFldEn);
end;
Form_main.queryFields.Next;
end;
checkedTableCnt := checkedTableCnt + 1;
end;
Form_main.queryFields.EnableControls;
end;