§ 18. Компоненты для работы с таблицами

18.2. Компонент DrawGrid

Компонент DrawGrid используется для создания таблицы, которая может содержать графические изображения. На панели компонентов Additional компонент DrawGrid изображен в виде , имя объекта DrawGrid. Компонент DrawGrid, помещенный на форму, получает имя  DrawGridN, где N — номер 1, 2, 3… (пример 18.5).

Этот компонент подобен компоненту StringGrid, который является наследником от DrawGrid. В DrawGrid присутствуют все свойства, методы, события компонента StringGrid, кроме относящихся к тексту, т.е. кроме свойств Cells, Cols, Rows.

Компонент DrawGrid (также StringGrid) имеет канву, на которой можно размещать изображения. Для занесения изображений в ячейки DrawGrid используют обработчик событий OnDrawCell. Это событие наступает для каждой ячейки таблицы в момент ее перерисовки. Размещая в обработчике события OnDrawCell программный код, можно раскрашивать ячейки, выводить рисунки, и делать текстовые надписи. Таблица сама постоянно вызывает это событие для того, чтобы отрисовать свои ячейки. Прорисовать изображение можно, используя методы канвы StratchDraw или CopyRect.

Обработчик OnDrawCell имеет параметры (пример 18.6).

Пример 18.7. Создать проект, в котором при выборе ячейки таблицы, будет либо закрашиваться ячейка, либо прорисовываться картинка. Если сумма номера строки и номера столбца нечетная, то происходит закраска ячейка, иначе прорисовывается картинка.

Этапы выполнения задания

  1. Разместить на форме компонент DrawGrid.
  2. Убрать фиксированные строки и столбцы.
  3. Установить для таблицы 5 строк и 5 столбцов.
  4. Установить ширину и высоту столбца равной 60.
  5. В событии OnCreate для формы загрузить рисунок в битовый образ.
  6. Написать обработчик события OnDrawCell, в котором зарисовывать ячейки.

Если свойство DefaultDrawing компонента DrawGrid имеет значение true (установлено по умолчанию), то зарисовываться будут только выделенные ячейки таблицы. Как только выделение изменится ячейка становится закрашенной тем цветом, который установлен по умолчанию. Если для свойства DefaultDrawing установить значение false, то после смены выделенной ячейки раскраска предыдущих ячеек не меняется.

Компонент DrawGrid удобно использовать для создания игр на клеточном поле. Для программирования игры понадобится матрица состояния игры. В такой матрице будет храниться обстановка игры на текущем ходу. После выполнения хода обстановка меняется, соответствующие изменения записываются в матрицу состояния и происходит обновление компонента DrawGrid. Матрица состояния игры может использоваться для сохранения игры и последующей ее загрузки.

Пример 18.8. Подготовить поле игры в крестики-нолики для двух игроков.

Этапы выполнения задания

  1. Разместить на форме компонент DrawGrid и кнопку.
  2. Убрать фиксированные строки и столбцы.
  3. Количество строк и столбцов равно 3.
  4. Для хранения матрицы состояния игры описать двумерный массив pole из 3 строк и 3 столбцов. Состояние клетки будем описывать одним из трех значений: 0 — клетка пуста, 1 — в клетке крестик, 2 — в клетке нолик.
  5. Написать обработчик события OnCreat для формы, в котором следует загрузить два битовых образа — рисунки для крестика и нолика.
  6. Написать обработчик события OnSelectCell, в котором необходимо изменить значение элемента массива pole для выбранной клетки. Для определения того, что рисовать в клетке на текущем шаге будем использовать символьную переменную znak, которая будет менять свое значение после каждого хода. Вначале znak = 'X';
  7. Написать обработчик события OnDrawCell, в котором нужно рисовать в ячейке картинку, соответствующую матрице состояния.
  8. Написать обработчик события OnClick для кнопки, в котором необходимо обнулить массив. После обнуления массива перерисовать таблицу на форме. Команда DrawGrid1 -> Refresh(); вызывает обработчик события OnDrawCell.

Компонент StringGrid обладает существенно большими возможностями, чем DrawGrid, поскольку он может хранить в ячейках и изображения, и тексты. Если необходимо внести текст в какие-то ячейки DrawGrid, то потребуется  использовать методы вывода текста на канву, что не всегда удобно.

Пример 18.5. Компонент DrawGrid на форме:

Пример 18.6. Параметры обработчика OnDrawCell:

  • ACol, ARow — индексы столбца и строки;
  • Rect — прямоугольник в рамках ячейки, заданной индексами ACol и ARow;
  • State — состояние ячейки:

-  gdSelected — ячейка выделена;
- gdFocused — ячейка имеет фокус ввода;
- gdFixed — ячейка относится к фиксированной строке или столбцу.

Пример 18.7. Форма на этапе проектирования:

Обработчик события OnCreate для формы.

void __fastcall TForm1::

FormCreate(TObject *Sender)

{

  ris -> LoadFromFile("fly.bmp");

}

Обработчик события OnSelectCell для таблицы.

void __fastcall TForm1::
DrawGrid1DrawCell(TObject *Sender,

int ACol, int ARow, TRect &Rect, 
TGridDrawState State)

{

  if (State.Contains(gdSelected)) {

    if ((ACol + ARow) % 2) {

      DrawGrid1 -> Canvas -> Brush

       -> Color = clSkyBlue;

      DrawGrid1 -> Canvas ->

       FillRect(Rect);

    }

    else

      DrawGrid1 -> Canvas ->

      StretchDraw(Rect, ris);

  }

}

Работающее приложение:

Пример 18.8. Форма на этапе проектирования:

Обработчик события OnCreate для формы.

void __fastcall TForm1::

FormCreate(TObject *Sender) 

{

  znak = 'X';

  kr -> LoadFromFile("k.bmp");

  nl -> LoadFromFile("n.bmp");

}

Обработчик события OnSelectCell для таблицы.

void __fastcall TForm1::

DrawGrid1SelectCell(TObject 
*Sender, int ACol,
int ARow,  bool &CanSelect)

{

  if (pole[ACol][ARow] == 0)

    if (znak == 'X') {

      pole[ACol][ARow] = 1;

      znak = 'O';

    }

    else {

      pole[ACol][ARow] = 2;

      znak = 'X';

    }

}

Обработчик события OnDrawCell для таблицы.

void __fastcall TForm1::

DrawGrid1DrawCell(TObject 

*Sender, int ACol, int ARow,

 TRect &Rect, TGridDrawState State) 

{

  switch (pole[ACol][ARow]) {

    case 1: {

      DrawGrid1 -> Canvas -> 

      StretchDraw(Rect, kr);

      break;

    }

    case 2: {

      DrawGrid1 -> Canvas -> 

      StretchDraw(Rect, nl);

      break;

    }

  }

}

Обработчик события OnClick для кнопки.

void __fastcall TForm1::

BitBtn1Click(TObject *Sender)

{

  for (int i = 0; i < 3; i++)

    for (int j = 0; j < 3; j++)

      pole[i][j] = 0;

  DrawGrid1 -> Refresh();

}

Работающее приложение: