Delphi Delphi XE 应用程序中的 DBCombobox,仅在 .Items 中显示值而不是实际的不合格数据字段值
Delphi DBCombobox in Delphi XE app, only shows values if in .Items and not the actual nonconforming Datafield value
我在使用 ADO 访问的 master/detail 应用程序中遇到了一个非常奇怪的 DBComboBox 问题。如果您有一个包含项目列表的 DBComboBox (.Style=csDropDown),并且您输入了一些列表中不存在的文本,则 table 的 DBComboBox 字段中的值在返回时不会出现到那个记录。我已使用下面的 DBNavigator.OnClick 代码尝试解决此问题,但只有当 table 中的第一条记录包含不在列表中的值时它才有效。当您将第一条记录中的 DBComboBox 的值更改为列表中的值时,DBComboBox 文本中将不会出现不一致的项目。有人找到解决办法了吗?
procedure TForm1.DBNavigator1Click(Sender: TObject; Button: TNavigateBtn);
var
SavePlace : TBookmark;
begin
if (DBComboBox1.Text='') then begin
SavePlace := TADODataSet(DBNavigator1.DataSource.DataSet).GetBookmark;
TADODataSet(DBNavigator1.DataSource.DataSet).Requery;
TADODataSet(DBNavigator1.DataSource.DataSet).GotoBookMark(SavePlace);
TADODataSet(DBNavigator1.DataSource.DataSet).FreeBookMark(SavePlace);
end;
end;
不幸的是我没有安装XE,但我做了一个示例项目
在 D7 和西雅图重现您的问题。代码如下所示,我认为
你会发现,如果你按照下面的确切步骤,它表明有一些东西
相当奇怪的事情。 更新 请参阅答案的底部以获得可能的 work-around,我认为这比您在问题中引用的代码更可取。
如您所见,除了 Form1 本身,所有组件都是在 运行 时间创建的
完全在代码中。这是为了消除任何怀疑行为是否引起的
通过一些晦涩的 属性 设置(不是),如果你想提交它
作为错误报告提交给 EMBA。出于类似的原因,我使用了 TClientDataSet 这样
该应用程序不依赖于任何外部数据。
步骤(第一次尝试时请完全按照步骤 4-7 )
重新启动IDE并创建一个新项目并编辑主窗体的.Pas文件,如下所示。重新启动 IDE 的原因是我发现如果它已经 运行ning 了很长时间(在我的情况下是两天),则不当行为的详细信息
应用程序略有变化)。
编译并运行.
应用将从所选 DBGrid 中的第一个开始。
在 DBComboBox 中输入任何内容('X' 即可),然后单击“保存”工具按钮
在 DBNavigator 上。
只单击 DBNavigator 上的下一步 (>) 工具按钮一次。 DBComboBox 现在显示
'Two'.
只单击 DBNavigator 上的优先 (<) 工具按钮一次。 DBComboBox 现在是空的。
只单击 DBNavigator 上的优先 (<) 工具按钮一次。 DBComboBox 现在显示
您在第 4 步中输入的内容。
关闭应用程序。 IDE 调试器很可能会捕获错误并打开 CPU window。
此故障发生在线路
DestroyWindow(FHandle);
在 TApplication.Destroy。我不是 Windows 内部专家,但我认为这很可能是因为在第 6 步中导致空白结果的任何原因导致了一些损坏。事实是
第 7 步导致 DBComboBox 正确显示您键入的内容让我怀疑原因实际上是
在 DBComboBox 与其 FieldDataLink 交互的方式中,FieldDataLink 将它连接到数据集。
顺便说一句,如果您在 TForm1 的 FormDestroy 中调用 DBComboBox1.Free,则不会发生错误
在我看来,可以确认故障与导致您的问题的原因有关。
所有这一切,以及它在 Delphi 的 25 年中显然已被忽视的事实,似乎很奇怪
大部头书。这个演示应用程序可以显示另一个在 DBGrid 中潜伏了类似时间的怪癖。查看
它:
注释掉所有对 DBComboBox 的引用并在网格选项中恢复 dgMultiSelect
设置它们的线。编译并 运行 应用程序。
单击第一行“名称”列中的单元格,键入内容并保存。
单击“下一步”工具按钮一次。第一行没有 de-select 本身。
AFAICT(通过在表单标题上显示 DBGrid 的书签计数)这不是
因为它在第一行保存了一个书签。
在我写这篇文章的时候,我想到了一个可能的 work-around,我会更新它
如果我能让它工作的话,这包括在内。
代码
type
TForm1 = class(TForm)
procedure FormCreate(Sender : TObject);
private
procedure SetUpDataSet;
procedure SetUpGUI;
protected
public
ClientDataSet1 : TClientDataSet;
DBGrid1: TDBGrid;
DataSource1: TDataSource;
DBNavigator1: TDBNavigator;
DBComboBox1: TDBComboBox;
end;
[...]
procedure TForm1.SetUpGUI;
begin
ClientDataset1 := TClientDataSet.Create(Self);
DataSource1 := TDataSource.Create(Self);
DataSource1.DataSet := ClientDataSet1;
DBGrid1 := TDBGrid.Create(Self);
DBGrid1.Top := 8;
DBGrid1.Left := 8;
DBGrid1.Width := 425;
DBGrid1.Options := [dgEditing, dgTitles, dgColumnResize, dgColLines, dgRowLines, dgTabs, dgConfirmDelete, dgCancelOnExit{, dgMultiSelect}];
DBGrid1.DataSource := DataSource1;
DBGrid1.Parent := Self;
DBNavigator1 := TDBNavigator.Create(Self);
DBNavigator1.DataSource := DataSource1;
DBNavigator1.Top := 144;
DBNavigator1.Left := 16;
DBNavigator1.Parent := Self;
DBComboBox1 := TDBComboBox.Create(Self);
DBComboBox1.DataField := 'Name';
DBComboBox1.DataSource := DataSource1;
DBComboBox1.Top := 240;
DBComboBox1.Left := 16;
DBComboBox1.Parent := Self;
end;
procedure TForm1.SetUpDataSet;
var
Field : TField;
begin
// Create 2 fields in the CDS
Field := TIntegerField.Create(Self);
Field.FieldName := 'ID';
Field.FieldKind := fkData;
Field.DataSet := ClientDataSet1;
Field := TStringField.Create(Self);
Field.FieldName := 'Name';
Field.Size := 40;
Field.FieldKind := fkData;
Field.DataSet := ClientDataSet1;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
SetUpGUI;
SetUpDataSet;
// Set up DBComboBox
DBComboBox1.Style := csDropDown;
DBComboBox1.Items.Add('One');
DBComboBox1.Items.Add('Two');
DBComboBox1.Items.Add('Three');
// Next, set up the CDS
ClientDataSet1.CreateDataSet;
ClientDataSet1.InsertRecord([1, '']);
ClientDataSet1.InsertRecord([2, 'Two']);
ClientDataSet1.InsertRecord([3, '']);
ClientDataSet1.First;
end;
可以work-around在Form1中添加如下方法:
procedure TForm1.ClientDataSet1AfterScroll(DataSet: TDataSet);
var
S : String;
begin
S := DataSet.FieldByName('Name').AsString;
if S <> DbComboBox1.Text then
DbComboBox1.Text := S;
Caption := IntToStr(DBGrid1.SelectedRows.Count);
end;
然后,在 SetUpGUI
方法中,在创建 ClientDataSet1 的行之后立即添加以下内容:
ClientDataset1.AfterScroll := ClientDataSet1AfterScroll;
我没有对此进行彻底的测试,但它似乎在我上面描述的步骤的测试条件下工作。
我在使用 ADO 访问的 master/detail 应用程序中遇到了一个非常奇怪的 DBComboBox 问题。如果您有一个包含项目列表的 DBComboBox (.Style=csDropDown),并且您输入了一些列表中不存在的文本,则 table 的 DBComboBox 字段中的值在返回时不会出现到那个记录。我已使用下面的 DBNavigator.OnClick 代码尝试解决此问题,但只有当 table 中的第一条记录包含不在列表中的值时它才有效。当您将第一条记录中的 DBComboBox 的值更改为列表中的值时,DBComboBox 文本中将不会出现不一致的项目。有人找到解决办法了吗?
procedure TForm1.DBNavigator1Click(Sender: TObject; Button: TNavigateBtn);
var
SavePlace : TBookmark;
begin
if (DBComboBox1.Text='') then begin
SavePlace := TADODataSet(DBNavigator1.DataSource.DataSet).GetBookmark;
TADODataSet(DBNavigator1.DataSource.DataSet).Requery;
TADODataSet(DBNavigator1.DataSource.DataSet).GotoBookMark(SavePlace);
TADODataSet(DBNavigator1.DataSource.DataSet).FreeBookMark(SavePlace);
end;
end;
不幸的是我没有安装XE,但我做了一个示例项目 在 D7 和西雅图重现您的问题。代码如下所示,我认为 你会发现,如果你按照下面的确切步骤,它表明有一些东西 相当奇怪的事情。 更新 请参阅答案的底部以获得可能的 work-around,我认为这比您在问题中引用的代码更可取。
如您所见,除了 Form1 本身,所有组件都是在 运行 时间创建的 完全在代码中。这是为了消除任何怀疑行为是否引起的 通过一些晦涩的 属性 设置(不是),如果你想提交它 作为错误报告提交给 EMBA。出于类似的原因,我使用了 TClientDataSet 这样 该应用程序不依赖于任何外部数据。
步骤(第一次尝试时请完全按照步骤 4-7 )
重新启动IDE并创建一个新项目并编辑主窗体的.Pas文件,如下所示。重新启动 IDE 的原因是我发现如果它已经 运行ning 了很长时间(在我的情况下是两天),则不当行为的详细信息 应用程序略有变化)。
编译并运行.
应用将从所选 DBGrid 中的第一个开始。
在 DBComboBox 中输入任何内容('X' 即可),然后单击“保存”工具按钮 在 DBNavigator 上。
只单击 DBNavigator 上的下一步 (>) 工具按钮一次。 DBComboBox 现在显示 'Two'.
只单击 DBNavigator 上的优先 (<) 工具按钮一次。 DBComboBox 现在是空的。
只单击 DBNavigator 上的优先 (<) 工具按钮一次。 DBComboBox 现在显示 您在第 4 步中输入的内容。
关闭应用程序。 IDE 调试器很可能会捕获错误并打开 CPU window。 此故障发生在线路
DestroyWindow(FHandle);
在 TApplication.Destroy。我不是 Windows 内部专家,但我认为这很可能是因为在第 6 步中导致空白结果的任何原因导致了一些损坏。事实是 第 7 步导致 DBComboBox 正确显示您键入的内容让我怀疑原因实际上是 在 DBComboBox 与其 FieldDataLink 交互的方式中,FieldDataLink 将它连接到数据集。
顺便说一句,如果您在 TForm1 的 FormDestroy 中调用 DBComboBox1.Free,则不会发生错误 在我看来,可以确认故障与导致您的问题的原因有关。
所有这一切,以及它在 Delphi 的 25 年中显然已被忽视的事实,似乎很奇怪 大部头书。这个演示应用程序可以显示另一个在 DBGrid 中潜伏了类似时间的怪癖。查看 它:
注释掉所有对 DBComboBox 的引用并在网格选项中恢复 dgMultiSelect 设置它们的线。编译并 运行 应用程序。
单击第一行“名称”列中的单元格,键入内容并保存。
单击“下一步”工具按钮一次。第一行没有 de-select 本身。 AFAICT(通过在表单标题上显示 DBGrid 的书签计数)这不是 因为它在第一行保存了一个书签。
在我写这篇文章的时候,我想到了一个可能的 work-around,我会更新它 如果我能让它工作的话,这包括在内。
代码
type
TForm1 = class(TForm)
procedure FormCreate(Sender : TObject);
private
procedure SetUpDataSet;
procedure SetUpGUI;
protected
public
ClientDataSet1 : TClientDataSet;
DBGrid1: TDBGrid;
DataSource1: TDataSource;
DBNavigator1: TDBNavigator;
DBComboBox1: TDBComboBox;
end;
[...]
procedure TForm1.SetUpGUI;
begin
ClientDataset1 := TClientDataSet.Create(Self);
DataSource1 := TDataSource.Create(Self);
DataSource1.DataSet := ClientDataSet1;
DBGrid1 := TDBGrid.Create(Self);
DBGrid1.Top := 8;
DBGrid1.Left := 8;
DBGrid1.Width := 425;
DBGrid1.Options := [dgEditing, dgTitles, dgColumnResize, dgColLines, dgRowLines, dgTabs, dgConfirmDelete, dgCancelOnExit{, dgMultiSelect}];
DBGrid1.DataSource := DataSource1;
DBGrid1.Parent := Self;
DBNavigator1 := TDBNavigator.Create(Self);
DBNavigator1.DataSource := DataSource1;
DBNavigator1.Top := 144;
DBNavigator1.Left := 16;
DBNavigator1.Parent := Self;
DBComboBox1 := TDBComboBox.Create(Self);
DBComboBox1.DataField := 'Name';
DBComboBox1.DataSource := DataSource1;
DBComboBox1.Top := 240;
DBComboBox1.Left := 16;
DBComboBox1.Parent := Self;
end;
procedure TForm1.SetUpDataSet;
var
Field : TField;
begin
// Create 2 fields in the CDS
Field := TIntegerField.Create(Self);
Field.FieldName := 'ID';
Field.FieldKind := fkData;
Field.DataSet := ClientDataSet1;
Field := TStringField.Create(Self);
Field.FieldName := 'Name';
Field.Size := 40;
Field.FieldKind := fkData;
Field.DataSet := ClientDataSet1;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
SetUpGUI;
SetUpDataSet;
// Set up DBComboBox
DBComboBox1.Style := csDropDown;
DBComboBox1.Items.Add('One');
DBComboBox1.Items.Add('Two');
DBComboBox1.Items.Add('Three');
// Next, set up the CDS
ClientDataSet1.CreateDataSet;
ClientDataSet1.InsertRecord([1, '']);
ClientDataSet1.InsertRecord([2, 'Two']);
ClientDataSet1.InsertRecord([3, '']);
ClientDataSet1.First;
end;
可以work-around在Form1中添加如下方法:
procedure TForm1.ClientDataSet1AfterScroll(DataSet: TDataSet);
var
S : String;
begin
S := DataSet.FieldByName('Name').AsString;
if S <> DbComboBox1.Text then
DbComboBox1.Text := S;
Caption := IntToStr(DBGrid1.SelectedRows.Count);
end;
然后,在 SetUpGUI
方法中,在创建 ClientDataSet1 的行之后立即添加以下内容:
ClientDataset1.AfterScroll := ClientDataSet1AfterScroll;
我没有对此进行彻底的测试,但它似乎在我上面描述的步骤的测试条件下工作。