Компонент StringGrid Delphi

Графика в StringGrid




Уроки Delphi
  1.  Первая программа
  2.  Использование компонентов
  3.  События Delphi
  4.  Типы данных Delphi
  5.  Создание своих типов данных
  6.  Выражения и операторы
  7.  Работа с файлами в Delphi
  8.  Дополнительные формы
  9.  Подпрограммы в Delphi
  10. Исключительные ситуации
  11. Взаимодействие приложения с пользователем
  12. Указатели в Delphi
  13. Обзор компонентов
  14. Работа со строками
  15. Создание интерфейса
  16. Графика в Delphi
  17. Многопоточность в Delphi
  18. Динамическое создание
        компонентов
Поиск по сайту




 Это важно:
   Метод Application.ProcessMessages;

 Это полезно:
   Параметр Sender в обработчиках событий;










Бояться не надо



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

   Работа с графическими свойствами компонента StringGrid происходит в обработчике OnDrawCell. По событию OnDrawCell происходит перерисовка таблицы, и следовательно, код в обработчике этого события будет управлять выводом на холст таблицы необходимой графики. Переменные этого обработчика помогут определить и прямоугольник, в котором будет происходить вывод графики:

procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
begin
  //ACol - индекс столбца
  //ARow - индекс строки
  //Rect - прямоугольник вывода, заданный ячейкой (ACol, ARow)
end;

   Для начала давайте выведем в ячейку (1, 1) компонента StringbGrid какой-нибудь рисунок. Вывести рисунок в ячейку компонента StringGrid проще всего, предварительно загрузив его в компонент Image:

Image1.Picture.LoadFromFile('Имя_файла');

   Загрузить рисунок в компонент Image можно, конечно, уже на этапе проектирования, в Инспекторе Объектов, вызвав графический редактор нажатием кнопочки в свойстве Picture.

   Затем нужно определить размеры загруженного рисунка:

W:=Image1.Picture.Width;
H:=Image1.Picture.Height;

   Далее, готовим ячейку под размещение рисунка. Для этого нужно задать её размеры кратными размерам рисунка. Например, сделаем размеры ячейки в 10 раз меньше размеров рисунка:

StringGrid1.ColWidths[1]:=Round(W/10);
StringGrid1.RowHeight[1]:=Round(H/10);

   Все эти манипуляции делаем предварительно, в обработчике OnCreate Формы, например. Ну и, наконец, в обработчике OnDrawCell выводим рисунок:

procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
begin
if ACol*ARow=1 then //Условие ACol*ARow=1 тождественно (ACol=1)and(ARow=1)
  StringGrid1.Canvas.StretchDraw(Rect, Image1.Picture.Graphic);
end;

   Таким образом, при перерисовке таблица просматривает все ячейки и, встретив комбинацию ACol=1 и ARow=1, выводит в эту ячейку рисунок.

   Таким же способом можно и раскрасить заданные по любому условию ячейки в нужные цвета. Например, раскрасим ячейки с положительными числами в зелёный цвет, с отрицательными - в красный, с равными нулю в синий:

procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
var X: Real;
begin
with StringGrid1 do
  begin
   try
    X:=StrToFloat(Cells[ACol, ARow]);
    if X>0 then Canvas.Brush.Color:=clGreen;
    if X<0 then Canvas.Brush.Color:=clRed;
    if X=0 then Canvas.Brush.Color:=clBlue;
   except
   end;
   Canvas.FillRect(Rect); //Текст тоже будет закрашен, его нужно перерисовать:
   Canvas.TextOut(Rect.Left+2, Rect.Top+2, Cells[ACol, ARow]);
  end;
end;

   Осталось рассмотреть возможности компонента StringGrid по выводу текста в ячейку таблицы в несколько строк. Если строки для вывода уже подготовлены, достаточно просто выводить строки со сдвигом по вертикали на высоту строки. Высота ячейки таблицы должна позволять вывод нескольких строк текста. Например, заголовок первого столбца:

//В обработчике OnCreate Формы подготавливаем высоту строки:
StringGrid1.RowHeight[0]:=(StringGrid1.Canvas.TexHeight('A')+2)*N; //N - количество строк
//теперь в обработчике OnDrawCell выводим текст:
if (ACol=1) and (ARow=0) then
  begin
    Canvas.TextOut(Rect.Left+2, Rect.Top+2, 'Многострочный заголовок');
    Canvas.TextOut(Rect.Left+2, Canvas.TextHeight('A')+Rect.Top+2, 'Вторая строка');
    Canvas.TextOut(Rect.Left+2, Canvas.TextHeight('A')*2+Rect.Top+2, 'Третья строка');
  end;

   Разумеется, вывод лучше делать в цикле, заголовки столбцов записать в массив, ну и добавить возможность центрирования заголовка в строке.


В начало урока


Вопросы и комментарии (10)      Решение задач в Delphi

Гость, добавлено 26.09.11, 16:07:38 
Многострочный заголовок, простой вариант

procedure TForm1.FormCreate(Sender: TObject);
begin
  with StringGrid1 do
  begin
  RowHeights[0] := 31;
  ColWidths[1] := 150;

  Cells[1,0] := 'Строка 1' +#10+ 'Строка 2';
  end;
end; // FormCreate


procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);
var
  pStr: PChar;
begin
  (Sender as TStringGrid).Canvas.FillRect(Rect);
  pStr := pchar((Sender as TStringGrid).Cells[ACol, ARow]);

  InflateRect(Rect, -2, -2); // Для красоты сделаем отступ слева и сверху на 2 пикселя

  DrawText((Sender as TStringGrid).Canvas.Handle, pStr, StrLen(pStr), Rect, DT_NOCLIP or DT_WORDBREAK);
end; // StringGrid1DrawCell

Гость, добавлено 26.09.11, 16:44:19 
Многострочный заголовок, выровнен по центру вертикали и горизонтали

procedure TForm1.FormCreate(Sender: TObject);
begin
  with StringGrid1 do
  begin
  RowHeights[0] := 70;
  ColWidths[1] := 152;

  Cells[1,0] := 'Многострочный заголовок, по центру вертикали и горизонтали';
  end;
end; // FormCreate


procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);
var
  F: Word;
  pStr: PChar;
  H: integer;
  CanvHandle: HDC;
  SaveRect: TRect;
begin
  if (ACol = 1) and (ARow = 0) then
  begin
  CanvHandle := (Sender as TStringGrid).Canvas.Handle;
  pStr := pchar((Sender as TStringGrid).Cells[ACol, ARow]);
  SaveRect := Rect; // Сохраним наш изначальный Rect, т.к. дальше по тексту, параметр DT_CALCRECT изменит размеры нашего изначального Rect

  (Sender as TStringGrid).Canvas.FillRect(Rect);


  {***********************************************************************************
  Если нет переноса слов, то выровнять по центру вертикали и горизонтали можно так:
  F := DT_NOCLIP or DT_VCENTER or DT_CENTER or DT_SINGLELINE;
  ************************************************************************************}


  { Т.к. у нас есть перенос по словам, то для вертикального выравнивания предется извернуться }
  // При использовании параметра DT_CALCRECT текст как таковой НЕ выводится, зато мы определим высоту и ширину текста.
  // Поскольку будет использоваться не просто DT_CALCRECT, а совместно с DT_WORDBREAK, то узнаем высоту многострочного текста.
  F := DT_NOCLIP or DT_WORDBREAK or DT_CALCRECT;
  H := DrawText(CanvHandle, pStr, StrLen(pStr), Rect, F); // Вообще, по определению, функция DrawText возвращает значение высоты текста, если функция успешна.

  // Теперь, зная высоту текста, можно вывести его центром по вертикали
  SaveRect.Top := (SaveRect.Bottom - H) div 2;
  F := DT_NOCLIP or DT_WORDBREAK or DT_CENTER;
  DrawText(CanvHandle, pStr, StrLen(pStr), SaveRect, F);
  end;
end; // StringGrid1DrawCell

Владимир, добавлено 8.10.11, 07:10:24 
Вопрос:
как на этапе выполнения изменить шрифт всей нефиксированной части таблицы?
Grid.Font.Assign(dlg.Font); не работает.
Автор, добавлено 8.10.11, 07:37:38 
Спешу ответить. По смыслу написанного вами кода, если бы он и работал (сам я не проверял), то изменял бы шрифт всей таблицы, а не только нефиксированнных ячеек - ведь в нём нет указания на область действия!

Вот так работает:

with Dlg do
  if Execute then
    Grid.Font:=Dlg.Font;

Вот такая конструкция изменяет шрифт текста в нефиксированной зоне после выбора другого шрифта в Диалоге:

procedure TForm1.Button1Click(Sender: TObject);
var i, j: Integer;
begin
with Dlg do
  if Execute then
//Код, забранный в скобки, модифицирует уже существующий в таблице текст.
//В противном случае он изменится лишь после щелчка по соответствующей ячейке.
{ begin
    for i:=Grid.FixedCols to Grid.ColCount-1 do
    for j:=Grid.FixedRows to Grid.RowCount-1 do
      Grid.Cells[i, j]:=Grid.Cells[i, j];
  end;}
end;

procedure TForm1.GridDrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
begin
Grid.Canvas.Font:=Dlg.Font;
with Grid, Grid.Canvas do
  if ((ARow>FixedRows-1)and(ACol>FixedCols-1)) then
    TextOut(Rect.Left+2, Rect.Top+2, Cells[ACol, ARow]);
end;

солнышко, добавлено 8.12.11, 01:17:12 
а как можно объединить ячейки фиксированной или не зафиксированной части таблицы в определенном месте,посередине например?
Автор, добавлено 8.12.11, 08:39:36 
Да никак их не объединишь. Я уже отвечал на подобный вопрос. И придумал лишь, что можно затереть границы между определёнными ячейками фоновым цветом. Ну, сейчас попробую.

Но на самом деле таблица StringGrid это же вам не таблица в Excell. В Delphi есть компонент на вкладке ActiveX сделанный как таблица Excell. Думаю, нужно учиться в таких случаях использовать имено его.
Анна, добавлено 8.02.12, 14:40:15 
Как сделать так, чтобы в изменяемой таблице при вводе данных с клавиатуры сразу шло выравнивание по центру (однострочное содержимое)?
Дивиджей, добавлено 6.04.13, 20:19:54 
Вот это круто!
Игорь, добавлено 18.01.14, 23:57:48 
Добрый вечер!
Подскажите, пожалуйста, как это реализовать. Я загружаю по нажатию кнопки данные из Excel в SG. Некоторые строки таблицы, специальные ячейки в которых помечены символом '1', необходимо окрасить. Как это реализовать в процедуре нажатия кнопки, если окрашивание осуществляется в процедуре StringGrid1DrawCell?
Игорь, добавлено 19.01.14, 00:22:02 
Прошу прощения за беспокойство. Отправил сообщение как-то сразу дошло. Событие StringGrid1DrawCell на то и событие. Оно непрерывно вызывается при изменениях в ячейках SG. Все равно, большое спасибо. Постоянно обращаюсь к Вашему сайту за необходимой информацией.
Оставить комментарий:

Имя  

Текст комментария