如何根据 TListbox 项仅显示指定的数据库结果?
How can I display only specified database results based on TListbox items?
我有两种形式:frmMakeQuote 和 frmQuoteTemp
在 frmMakeQuote 中有两个 TListboxes:lboMtrlList 和 lboSelectedMtrl
lboMtrlList 显示数据库中的 产品描述 列。
procedure TfrmMakeQuote.FormCreate(Sender: TObject);
begin
con := TFDConnection.Create(nil);
query := TFDQuery.Create(con);
con.LoginPrompt := false;
con.Open('DriverID=SQLite;Database=C:\Users\kasio\Documents\Embarcadero\' +
'Studio\Projects\ProgramDatabase;');
query.Connection := con;
query.SQL.Text :=
'SELECT [Material Description] FROM MtrlDatabase ORDER BY MtrlID';
try
query.Open;
lboMtrlList.Items.Clear;
while not query.EOF do
begin
lboMtrlList.Items.Add(query.Fields[0].AsString);
query.Next;
end;
finally
query.Close;
end;
end;
当此人双击 lboMtrlList 中的任何 'product' 时,它会移动到 lboSelectedMtrl。 (基本上就是显示选中的'products'。)
procedure TfrmMakeQuote.lboMtrlListDblClick(Sender: TObject);
begin
lboSelectedMtrl.Items.Add(lboMtrlList.Items.Strings[lboMtrlList.ItemIndex]);
end;
我希望能够显示数据库中的 产品描述 和 价格 列,仅显示选定的 'products' 来自 lboSelectedMtrl。它们应该显示在名为 sgdMaterials 的 TStringGrid 中 frmQuoteTemp.
我写了这样的东西:
procedure TfrmMakeQuote.performMtrlQuery;
var
i: integer;
begin
for i := 1 to frmMakeQuote.lboSelectedMtrl.ItemIndex do
begin
query.SQL.Text := 'SELECT [Material Description], Price FROM MtrlDatabase ' +
'WHERE [Material Description] = "'
+ frmMakeQuote.lboSelectedMtrl.Items.Strings[1]
+ '" ORDER BY MtrlID';
query.Open;
query.First;
end;
end;
它没有显示任何错误,但它不起作用并且什么也不显示,我知道它可能完全错误。
你在 performMtrlQuery()
中的循环是错误的。如果在 lboSelectedMtrl
中实际上没有选择任何内容,它的 ItemIndex
将为 -1,并且循环将不会遍历任何项目。不仅如此,即使选择了一个项目,您的循环也不会遍历所有可用项目。此外,当您索引到 Strings[]
属性 时,您使用的是 hard-coded 1
而不是循环变量 i
.
至于您的 TStringGrid
,为什么不改用 TDBGrid
,并将其绑定到按所需项目过滤数据库的数据源?在任何情况下,performMtrlQuery()
根本没有做任何事情来填充网格,无论是直接将搜索结果存储在网格中,还是将结果存储在 frmQuoteTemp
可以随后的某个列表中阅读自。
试试这个:
procedure TfrmMakeQuote.performMtrlQuery;
var
i: integer;
begin
for i := 0 to frmMakeQuote.lboSelectedMtrl.Items.Count-1 do
begin
query.SQL.Text := 'SELECT [Material Description], Price FROM MtrlDatabase' +
' WHERE [Material Description] = "'
+ frmMakeQuote.lboSelectedMtrl.Items.Strings[i]
+ '" ORDER BY MtrlID';
query.Open;
query.First;
// do something with query.Fields[0] and query.Fields[1] ...
query.Close;
end;
end;
话虽如此,按描述搜索资料并不是最有效的搜索选项。您应该改为按他们的 ID 搜索。我建议使用另一种方法来实现这一点——在虚拟模式 (Style=lbVirtual
) 中使用 TListBox
控件,并将搜索结果存储在单独的 TStringList
对象中。这样您就可以将 ID 和描述一起存储在内存中,同时在 UI 中显示描述并在查询中使用 ID。
试试像这样的东西:
procedure TfrmMakeQuote.FormCreate(Sender: TObject);
begin
allmaterials := TStringList.Create;
selectedmaterials := TStringList.Create;
con := TFDConnection.Create(Self);
con.LoginPrompt := false;
con.Open('DriverID=SQLite;Database=C:\Users\kasio\Documents\Embarcadero\Studio\Projects\ProgramDatabase;');
query := TFDQuery.Create(con);
query.Connection := con;
query.SQL.Text := 'SELECT MtrlID, [Material Description] FROM MtrlDatabase ORDER BY MtrlID';
try
query.Open;
while not query.EOF do
begin
allmaterials.Add(query.Fields[0].AsString + '=' + query.Fields[1].AsString);
query.Next;
end;
finally
query.Close;
end;
lboMtrlList.Count = allmaterials.Count;
end;
procedure TfrmMakeQuote.FormDestroy(Sender: TObject);
begin
allmaterials.Free;
selectedmaterials.Free;
end;
// lboMtrlList OnData event handler
procedure TfrmMakeQuote.lboMtrlListData(Control: TWinControl; Index: Integer; var Data: string);
begin
Data := allmaterials.ValueFromIndex[Index];
end;
// lboSelectedMtrl OnData event handler
procedure TfrmMakeQuote.lboSelectedMtrlData(Control: TWinControl; Index: Integer; var Data: string);
begin
Data := selectedmaterials.ValueFromIndex[Index];
end;
procedure TfrmMakeQuote.lboMtrlListDblClick(Sender: TObject);
var
Idx: Integer;
begin
Idx := lboMtrlList.ItemIndex;
if Idx = -1 then Exit;
if selectedmaterials.IndexOfName(allmaterials.Names[Idx]) <> -1 then Exit;
selectedmaterials.Add(allmaterials.Strings[Idx]);
lboSelectedMtrl.Count := selectedmaterials.Count;
end;
procedure TfrmMakeQuote.performMtrlQuery;
var
i: integer;
begin
for i := 0 to selectedmaterials.Count-1 do
begin
query.SQL.Text := 'SELECT [Material Description], Price FROM MtrlDatabase' +
' WHERE MtrlID = '
+ selectedmaterials.Names[i];
query.Open;
query.First;
// do something with query.Fields[0] and query.Fields[1] ...
query.Close;
end;
end;
最后,如果您切换到单个 TCheckListBox
或 TListView
控件而不是 2 个 TListBox
控件,您可以利用它们在每个项目上都有复选框的能力,然后您不再需要处理 OnDblClick
事件,也不需要在您的 UI 中出示两份材料。用户可以在调用 performMtrlQuery()
.
之前检查所需的项目
我还建议对搜索结果使用虚拟 TListView
而不是 TStringGrid
。 UI 看起来会更好(TStringGrid
不是最好看的 UI 控件),并且您可以更有效地利用内存(如果您有要显示的数据很多)。
我有两种形式:frmMakeQuote 和 frmQuoteTemp
在 frmMakeQuote 中有两个 TListboxes:lboMtrlList 和 lboSelectedMtrl
lboMtrlList 显示数据库中的 产品描述 列。
procedure TfrmMakeQuote.FormCreate(Sender: TObject);
begin
con := TFDConnection.Create(nil);
query := TFDQuery.Create(con);
con.LoginPrompt := false;
con.Open('DriverID=SQLite;Database=C:\Users\kasio\Documents\Embarcadero\' +
'Studio\Projects\ProgramDatabase;');
query.Connection := con;
query.SQL.Text :=
'SELECT [Material Description] FROM MtrlDatabase ORDER BY MtrlID';
try
query.Open;
lboMtrlList.Items.Clear;
while not query.EOF do
begin
lboMtrlList.Items.Add(query.Fields[0].AsString);
query.Next;
end;
finally
query.Close;
end;
end;
当此人双击 lboMtrlList 中的任何 'product' 时,它会移动到 lboSelectedMtrl。 (基本上就是显示选中的'products'。)
procedure TfrmMakeQuote.lboMtrlListDblClick(Sender: TObject);
begin
lboSelectedMtrl.Items.Add(lboMtrlList.Items.Strings[lboMtrlList.ItemIndex]);
end;
我希望能够显示数据库中的 产品描述 和 价格 列,仅显示选定的 'products' 来自 lboSelectedMtrl。它们应该显示在名为 sgdMaterials 的 TStringGrid 中 frmQuoteTemp.
我写了这样的东西:
procedure TfrmMakeQuote.performMtrlQuery;
var
i: integer;
begin
for i := 1 to frmMakeQuote.lboSelectedMtrl.ItemIndex do
begin
query.SQL.Text := 'SELECT [Material Description], Price FROM MtrlDatabase ' +
'WHERE [Material Description] = "'
+ frmMakeQuote.lboSelectedMtrl.Items.Strings[1]
+ '" ORDER BY MtrlID';
query.Open;
query.First;
end;
end;
它没有显示任何错误,但它不起作用并且什么也不显示,我知道它可能完全错误。
你在 performMtrlQuery()
中的循环是错误的。如果在 lboSelectedMtrl
中实际上没有选择任何内容,它的 ItemIndex
将为 -1,并且循环将不会遍历任何项目。不仅如此,即使选择了一个项目,您的循环也不会遍历所有可用项目。此外,当您索引到 Strings[]
属性 时,您使用的是 hard-coded 1
而不是循环变量 i
.
至于您的 TStringGrid
,为什么不改用 TDBGrid
,并将其绑定到按所需项目过滤数据库的数据源?在任何情况下,performMtrlQuery()
根本没有做任何事情来填充网格,无论是直接将搜索结果存储在网格中,还是将结果存储在 frmQuoteTemp
可以随后的某个列表中阅读自。
试试这个:
procedure TfrmMakeQuote.performMtrlQuery;
var
i: integer;
begin
for i := 0 to frmMakeQuote.lboSelectedMtrl.Items.Count-1 do
begin
query.SQL.Text := 'SELECT [Material Description], Price FROM MtrlDatabase' +
' WHERE [Material Description] = "'
+ frmMakeQuote.lboSelectedMtrl.Items.Strings[i]
+ '" ORDER BY MtrlID';
query.Open;
query.First;
// do something with query.Fields[0] and query.Fields[1] ...
query.Close;
end;
end;
话虽如此,按描述搜索资料并不是最有效的搜索选项。您应该改为按他们的 ID 搜索。我建议使用另一种方法来实现这一点——在虚拟模式 (Style=lbVirtual
) 中使用 TListBox
控件,并将搜索结果存储在单独的 TStringList
对象中。这样您就可以将 ID 和描述一起存储在内存中,同时在 UI 中显示描述并在查询中使用 ID。
试试像这样的东西:
procedure TfrmMakeQuote.FormCreate(Sender: TObject);
begin
allmaterials := TStringList.Create;
selectedmaterials := TStringList.Create;
con := TFDConnection.Create(Self);
con.LoginPrompt := false;
con.Open('DriverID=SQLite;Database=C:\Users\kasio\Documents\Embarcadero\Studio\Projects\ProgramDatabase;');
query := TFDQuery.Create(con);
query.Connection := con;
query.SQL.Text := 'SELECT MtrlID, [Material Description] FROM MtrlDatabase ORDER BY MtrlID';
try
query.Open;
while not query.EOF do
begin
allmaterials.Add(query.Fields[0].AsString + '=' + query.Fields[1].AsString);
query.Next;
end;
finally
query.Close;
end;
lboMtrlList.Count = allmaterials.Count;
end;
procedure TfrmMakeQuote.FormDestroy(Sender: TObject);
begin
allmaterials.Free;
selectedmaterials.Free;
end;
// lboMtrlList OnData event handler
procedure TfrmMakeQuote.lboMtrlListData(Control: TWinControl; Index: Integer; var Data: string);
begin
Data := allmaterials.ValueFromIndex[Index];
end;
// lboSelectedMtrl OnData event handler
procedure TfrmMakeQuote.lboSelectedMtrlData(Control: TWinControl; Index: Integer; var Data: string);
begin
Data := selectedmaterials.ValueFromIndex[Index];
end;
procedure TfrmMakeQuote.lboMtrlListDblClick(Sender: TObject);
var
Idx: Integer;
begin
Idx := lboMtrlList.ItemIndex;
if Idx = -1 then Exit;
if selectedmaterials.IndexOfName(allmaterials.Names[Idx]) <> -1 then Exit;
selectedmaterials.Add(allmaterials.Strings[Idx]);
lboSelectedMtrl.Count := selectedmaterials.Count;
end;
procedure TfrmMakeQuote.performMtrlQuery;
var
i: integer;
begin
for i := 0 to selectedmaterials.Count-1 do
begin
query.SQL.Text := 'SELECT [Material Description], Price FROM MtrlDatabase' +
' WHERE MtrlID = '
+ selectedmaterials.Names[i];
query.Open;
query.First;
// do something with query.Fields[0] and query.Fields[1] ...
query.Close;
end;
end;
最后,如果您切换到单个 TCheckListBox
或 TListView
控件而不是 2 个 TListBox
控件,您可以利用它们在每个项目上都有复选框的能力,然后您不再需要处理 OnDblClick
事件,也不需要在您的 UI 中出示两份材料。用户可以在调用 performMtrlQuery()
.
我还建议对搜索结果使用虚拟 TListView
而不是 TStringGrid
。 UI 看起来会更好(TStringGrid
不是最好看的 UI 控件),并且您可以更有效地利用内存(如果您有要显示的数据很多)。