如何根据 TListbox 项仅显示指定的数据库结果?

How can I display only specified database results based on TListbox items?

我有两种形式:frmMakeQuotefrmQuoteTemp

frmMakeQuote 中有两个 TListboxeslboMtrlList 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;

最后,如果您切换到单个 TCheckListBoxTListView 控件而不是 2 个 TListBox 控件,您可以利用它们在每个项目上都有复选框的能力,然后您不再需要处理 OnDblClick 事件,也不需要在您的 UI 中出示两份材料。用户可以在调用 performMtrlQuery().

之前检查所需的项目

我还建议对搜索结果使用虚拟 TListView 而不是 TStringGrid。 UI 看起来会更好(TStringGrid 不是最好看的 UI 控件),并且您可以更有效地利用内存(如果您有要显示的数据很多)。