Как я могу отображать только указанные результаты базы данных на основе элементов TListbox?

У меня есть две формы: 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, он перемещается в lboSelectedMtrl. (В основном, он показывает выбранные «продукты».)

procedure TfrmMakeQuote.lboMtrlListDblClick(Sender: TObject);
begin
  lboSelectedMtrl.Items.Add(lboMtrlList.Items.Strings[lboMtrlList.ItemIndex]);
end;

Я хочу иметь возможность отображать столбцы Product Description и Price из базы данных ТОЛЬКО для выбранных «продуктов» из lboSelectedMtrl. Они должны отображаться в TStringGrid с именем sgdMaterials в 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;

Он не показывает никаких ошибок, но он не работает и ничего не отображает, и я знаю, что это, вероятно, совершенно неправильно.


person Katiee Park    schedule 30.12.2015    source источник
comment
Это домашнее задание? Не позволяйте этому быть домашним заданием. :-)   -  person Warren P    schedule 30.12.2015
comment
Ваш performMtrlQuery не пытается ничего отображать. Он просто открывает запрос. Если вы хотите отобразить данные, вам нужно либо писать в ячейки сетки строк, либо (лучше) использовать TDBGrid, специально предназначенный для отображения данных из набора данных. В документации Delphi есть руководства по написанию приложений для баз данных. Я настоятельно рекомендую вам пройти через них. Вы можете узнать о параметризованных запросах и элементах управления с учетом данных.   -  person Ken White    schedule 30.12.2015


Ответы (1)


Ваш цикл внутри performMtrlQuery() неверен. Если в lboSelectedMtrl на самом деле ничего не выбрано, его ItemIndex будет равно -1, и цикл не будет перебирать какие-либо элементы. Не только это, но даже если элемент был выбран, ваш цикл не будет перебирать ВСЕ доступные элементы. Кроме того, когда вы индексируете свойство Strings[], вы используете жестко запрограммированное значение 1 вместо переменной цикла i.

Что касается вашего TStringGrid, почему бы вместо этого не использовать TDBGrid и не связать его с DataSource, который фильтрует базу данных по нужным элементам? В любом случае, 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;

При этом поиск ваших материалов по их описаниям — не самый эффективный вариант поиска. Вместо этого вам следует искать по их идентификаторам. Я бы предложил альтернативный подход для достижения этой цели — вместо этого используйте элементы управления TListBox в виртуальном режиме (Style=lbVirtual) и сохраняйте результаты поиска в отдельных объектах TStringList. Таким образом, вы можете хранить в памяти как идентификаторы, так и описания вместе, отображая описания в пользовательском интерфейсе и используя идентификаторы в запросах.

Попробуйте еще что-нибудь вроде этого:

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 вместо двух элементов управления TListBox, вы можете воспользоваться их возможностью устанавливать флажки для каждого элемента, тогда вам больше не нужно иметь дело с событием OnDblClick, и не нужно показать две копии ваших материалов в вашем пользовательском интерфейсе. Пользователь может просто проверить нужные элементы перед вызовом performMtrlQuery().

Я бы также предложил использовать виртуальный TListView для результатов поиска вместо TStringGrid. Пользовательский интерфейс будет выглядеть лучше (TStringGrid — не лучший вид элемента управления пользовательского интерфейса), и вы сможете более эффективно использовать память (TStringGrid может потреблять много памяти, если вам нужно отобразить много данных).

person Remy Lebeau    schedule 30.12.2015
comment
Я пробовал, но результаты те же и ничего не отображается. - person Katiee Park; 30.12.2015