Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
KANSoftWare

Как получить индекс выбранного элемента в ячейке StringGrid с PickList в Delphi

Delphi , Компоненты и Классы , TStringGrid и TDrawGrid

Как получить индекс выбранного элемента в ячейке StringGrid с PickList в Delphi

Компонент TStringGrid в Delphi — мощный инструмент для отображения табличных данных. Одной из его полезных функций является возможность задать для столбца стиль cbsPickList, превращая ячейки этого столбца в выпадающие списки. Однако стандартными средствами получить индекс выбранного элемента из такого списка, особенно если в списке есть повторяющиеся строки, может быть нетривиальной задачей. В этой статье мы разберем проблему и предложим эффективное решение на Object Pascal.

Описание проблемы

Представьте, что у вас есть TStringGrid, в одном из столбцов которого используется PickList. Пользователь выбирает значение из выпадающего списка в одной из ячеек. Ваша задача — получить не только текстовое значение (string), которое выбрал пользователь (это легко сделать через StringGrid.Cells[Col, Row]), но и порядковый номер (ItemIndex) этого элемента внутри самого списка PickList.

Почему это может быть важно? Например, если список содержит неуникальные значения (одинаковые строки), то знание индекса позволит точно идентифицировать, какой именно элемент был выбран.

Простая попытка получить доступ к редактору ячейки (TPickListCellEditor) и его свойству ItemIndex напрямую для каждой ячейки не сработает.

// НЕПРАВИЛЬНЫЙ ПОДХОД: Попытка получить редактор для каждой ячейки
procedure TForm1.Button1Click(Sender: TObject);
var
  i: Integer;
  Editor: TPickListCellEditor; // Это не сработает так, как ожидается
begin
  Memo1.Clear;
  try
    for i := StringGrid1.FixedRows to StringGrid1.RowCount -1 do
    begin
      // ОШИБКА: Редактор существует только для АКТИВНОЙ ячейки,
      // а не для всех ячеек одновременно.
      // Эта строка вернет ссылку на один и тот же экземпляр редактора,
      // не связанный с конкретной строкой i вне режима редактирования.
      Editor := TPickListCellEditor(StringGrid1.EditorByStyle(cbsPickList));
      // Следующая строка вызовет ошибку или вернет некорректные данные
      Memo1.Lines.Append(Format('Строка %d: индекс=%d элемент=%s',
        [i, Editor.ItemIndex, Editor.Items[Editor.ItemIndex]]));
    end;
  except
    Memo1.Lines.Append('<<< Ошибка доступа к редактору! >>>');
  end;
end;

Проблема в том, что TStringGrid использует один экземпляр редактора для всех ячеек столбца. Этот редактор активируется, перемещается и настраивается только тогда, когда пользователь начинает редактировать конкретную ячейку. В остальное время получить доступ к состоянию редактора (например, ItemIndex) для неактивной ячейки невозможно стандартными средствами. Сама сетка хранит только строковое значение ячейки в StringGrid.Cells.

Решение 1: Простой случай (уникальные значения в PickList)

Если вы уверены, что все строки в вашем PickList уникальны, то можно использовать простое решение, предложенное пользователем wp в исходном обсуждении. Вы получаете строку из ячейки и ищете ее индекс в списке PickList, ассоциированном со столбцом:

procedure TForm1.Button1Click(Sender: TObject);
var
  i: Integer;
  cellString: String;
  pickedIndex: Integer;
  colWithPickList: Integer; // Индекс столбца с PickList
begin
  Memo1.Clear;
  colWithPickList := 0; // Замените на реальный индекс вашего столбца

  // Убедимся, что у столбца есть PickList
  if (colWithPickList < StringGrid1.ColCount) and
     Assigned(StringGrid1.Columns[colWithPickList].PickList) then
  begin
    try
      for i := StringGrid1.FixedRows to StringGrid1.RowCount - 1 do
      begin
        // Получаем строковое значение из ячейки
        cellString := StringGrid1.Cells[colWithPickList, i];

        // Ищем индекс этой строки в PickList столбца
        pickedIndex := StringGrid1.Columns[colWithPickList].PickList.IndexOf(cellString);

        Memo1.Lines.Append(Format('Строка %d: индекс=%d элемент=%s',
          [i, pickedIndex, cellString]));
      end;
    except
      on E: Exception do
        Memo1.Lines.Append('<<< Ошибка: ' + E.Message + ' >>>');
    end;
  end
  else
  begin
    Memo1.Lines.Append(Format('<<< Ошибка: Столбец %d не имеет PickList >>>', [colWithPickList]));
  end;
end;

Ограничение: Этот метод вернет индекс первого вхождения строки cellString в PickList. Если у вас есть дубликаты ("Яблоко", "Банан", "Яблоко"), и пользователь выбрал второе "Яблоко", IndexOf все равно вернет индекс первого "Яблока" (индекс 0, если считать с нуля).

Решение 2: Обработка дубликатов с использованием Objects и кастомного редактора

Чтобы надежно хранить и извлекать индекс выбранного элемента, даже при наличии дубликатов, необходимо хранить сам индекс где-то еще, помимо свойства Cells. TStringGrid предоставляет для этого удобное, но часто игнорируемое свойство — массив Objects: array[ACol, ARow] of TObject. Каждой ячейке сетки можно сопоставить объект. Мы можем "злоупотребить" этим свойством, сохраняя в нем целочисленный индекс, предварительно преобразовав его к типу TObject.

Поскольку стандартный редактор TPickListCellEditor не дает нам нужного контроля и доступа, мы заменим его на собственный редактор — обычный TComboBox, который будет скрыт на форме и будет появляться только при редактировании ячейки.

Шаги реализации:

  1. Добавьте TComboBox на форму. Назовем его cbGridEditor. Установите его свойство Visible := False. Заполните его Items теми же значениями, что и ваш PickList (или делайте это динамически).
  2. Добавьте переменные в класс формы для хранения координат редактируемой ячейки:

    pascal private FEditedCol, FEditedRow: Integer; // Координаты редактируемой ячейки procedure cbGridEditorEditingDone(Sender: TObject); // Объявим обработчик procedure cbGridEditorKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); // Для удобства

  3. Реализуйте обработчик OnSelectEditor для TStringGrid: Этот обработчик вызывается, когда сетка собирается показать редактор для ячейки. Здесь мы подменяем стандартный редактор на наш cbGridEditor.

    ```pascal procedure TForm1.StringGrid1SelectEditor(Sender: TObject; ACol, ARow: Integer; var Editor: TWinControl); var storedIndex: PtrInt; // Используем PtrInt для безопасного кастинга Integer <-> TObject obj: TObject; colWithPickList: Integer; begin colWithPickList := 0; // Индекс вашего столбца с PickList

    if ACol = colWithPickList then begin // Назначаем наш ComboBox редактором Editor := cbGridEditor;

    // Позиционируем и показываем ComboBox поверх ячейки
    cbGridEditor.BoundsRect := StringGrid1.CellRect(ACol, ARow);
    cbGridEditor.Visible := True; // Делаем видимым
    
    // Загружаем сохраненный индекс из Objects
    obj := StringGrid1.Objects[ACol, ARow];
    if obj = nil then // Если индекс не был сохранен (или ячейка пуста)
    begin
      cbGridEditor.ItemIndex := -1; // Нет выбора
    
      // Опционально: если ячейка не пуста, но индекса нет,
      // попробуем найти по тексту (для первоначального заполнения)
      if StringGrid1.Cells[ACol, ARow] <> '' then
         cbGridEditor.ItemIndex := cbGridEditor.Items.IndexOf(StringGrid1.Cells[ACol, ARow]);
    
    end
    else
    begin
      // Преобразуем TObject обратно в PtrInt (Integer)
      storedIndex := PtrInt(obj);
      // Устанавливаем ItemIndex в ComboBox
      // Важно: Добавляем 1 к индексу при сохранении и вычитаем при чтении,
      // чтобы отличить индекс 0 от nil (не сохранено).
      cbGridEditor.ItemIndex := stored
    

Создано по материалам из источника по ссылке.

В статье рассматривается проблема получения индекса выбранного элемента из ячейки StringGrid с PickList в Delphi и предлагаются два решения: для уникальных значений в PickList с использованием IndexOf и для обработки дубликатов с использованием свойства


Комментарии и вопросы

Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.


:: Главная :: TStringGrid и TDrawGrid ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-12-22 20:14:06
2025-04-23 04:42:37/0.0041840076446533/0