"EhLib.Com"
https://forum.ehlib.com/ru/

Отрисовка границ ячеек
https://forum.ehlib.com/ru/viewtopic.php?f=4&t=148
Страница 1 из 1

Автор:  Andrew Deviatikh [ 15 апр 2012, 18:52 ]
Заголовок сообщения:  Отрисовка границ ячеек

Существует ли в Ehlib какой-нибудь штатный способ изменить отрисовку границ у ячеек TDBGridEh? Или только путём рисования на канвасе? Пример конкретной задачи - нужно изменить толщину и цвет правой границы только определённых ячеек (в зависимости от их содержимого, например). Сейчас данную задачу решаем следующим образом - в OnDrawColumnCell засовывается следующий код:
Код:
      if *некое условие* then
      begin
        (Sender as TCustomDBGridEh).Canvas.Pen.Color := clBlack;
        (Sender as TCustomDBGridEh).Canvas.Pen.Width := 2;
        (Sender as TCustomDBGridEh).Canvas.MoveTo(Rect.Right, Rect.Top);
        (Sender as TCustomDBGridEh).Canvas.LineTo(Rect.Right, Rect.Bottom);
      end;

Данный метод работает, но вызывает ряд проблем с отрисовкой грида. Так, например, если включен OptionsEh.dghExtendVertLines, то "продолжения" вертикальных границ ячеек начинают всегда прорисовываться толщиной в 2 пикселя, а при быстрой горизонтальной прокрутке грида появляются артефакты прорисовки. Что можете порекомендовать?

Автор:  Administrator [ 22 апр 2012, 22:27 ]
Заголовок сообщения:  Re: Отрисовка границ ячеек

Добрый день.

В текущей версии библиотеки можно влиять только на два базовых цвета линий.

DBGridEh1.GridLineColors.DarkColor - цвет линий разделяющей фиксированные ячейки.
DBGridEh1.GridLineColors.BrightColor - цвет линий разделяющей ячейки c данными.

После прорисовки не забывайте возвращать старое значения свойств объектов канваса

Код:
        OldColor := (Sender as TCustomDBGridEh).Canvas.Pen.Color;
        OldWidth := (Sender as TCustomDBGridEh).Canvas.Pen.Width;
        (Sender as TCustomDBGridEh).Canvas.Pen.Color := clBlack;
        (Sender as TCustomDBGridEh).Canvas.Pen.Width := 2;
        (Sender as TCustomDBGridEh).Canvas.MoveTo(Rect.Right, Rect.Top);
        (Sender as TCustomDBGridEh).Canvas.LineTo(Rect.Right, Rect.Bottom);
        (Sender as TCustomDBGridEh).Canvas.Pen.Color := OldColor;
        (Sender as TCustomDBGridEh).Canvas.Pen.Width := OldWidth;

Best regards
Admin

Автор:  GoldMedium [ 03 мар 2021, 13:36 ]
Заголовок сообщения:  Re: Отрисовка границ ячеек

Прошло почти 9 лет, очень надеюсь, что в версии 10.x функционал в плане отрисовки линий расширился.

Благодаря примеру выше я могу отрисовать вертикальные линий для заданных строк (чёрные линии на Screen1.png).
Подскажите, пожалуйста, а как задать цвет отрисовки горизонтальных линий (сверху и снизу) для заданных строк (красные линии на Screen1.png)?

И ещё как задать вертикальные и горизонтальные линии для текущей выделенной строки (красные линии на Screen2.png)?

Очень надеюсь на Вашу помощь!
Спасибо

P.S. В документации всё перерыл - не нашёл решения

Вложения:
Screen1.png
Screen1.png [ 16.46 KiB | Просмотров: 3095 ]
Screen2.png
Screen2.png [ 9.66 KiB | Просмотров: 3095 ]

Автор:  EhLibSupport [ 04 мар 2021, 00:29 ]
Заголовок сообщения:  Re: Отрисовка границ ячеек

Добрый день.

Для отрисовки окантовки ячеек грида вы можете использовать событие TColumnEh.OnAdvDrawDataCell
Обработчик события необходимо присвоить каждой колонке грида.

В событии понадобиться обращения к protected методам грида.
Код:
type
  TDBGridEhCrack = class(TCustomDBGridEh);

а также возможность обращения к следующей записи грида для корректной отрисовки нижней линии для окантовки следующей ячейки.

Код:
  if (AreaCell.Y < Grid.InstantReadRecordCount - 1) then
  begin
    try
      Grid.InstantReadRecordEnter(AreaCell.Y + 1);
      NextRowIsSpecial := MemTableEh1.FieldByName('SpecialBorderState').AsInteger = 1;
    finally
      Grid.InstantReadRecordLeave;
    end;
  end;


Полный код обработчика события приведен ниже:

Код:
type
  TDBGridEhCrack = class(TCustomDBGridEh);

procedure TForm1.DBGridEh1Columns0AdvDrawDataCell(Sender: TCustomDBGridEh; Cell,
  AreaCell: TGridCoord; Column: TColumnEh; const ARect: TRect;
  var Params: TColCellParamsEh; var Processed: Boolean);
var
  Grid: TDBGridEhCrack;
  NextRowIsSpecial: Boolean;
begin
  Grid := TDBGridEhCrack(Sender);
  NextRowIsSpecial := False;

  if (MemTableEh1.FieldByName('SpecialBorderState').AsInteger = 1) then
  begin
    Params.Background := $006DD3EB;
    Params.Font.Style := [fsBold];
  end;

  Grid.DefaultDrawColumnDataCell(Cell, AreaCell, Column, ARect, Params);

  if (AreaCell.Y < Grid.InstantReadRecordCount - 1) then
  begin
    try
      Grid.InstantReadRecordEnter(AreaCell.Y + 1);
      NextRowIsSpecial := MemTableEh1.FieldByName('SpecialBorderState').AsInteger = 1;
    finally
      Grid.InstantReadRecordLeave;
    end;
  end;

  if (MemTableEh1.FieldByName('SpecialBorderState').AsInteger = 1) then
  begin
    Grid.Canvas.Pen.Color := clRed;
    Grid.DrawPolyline(Grid.Canvas, [Point(ARect.Left, ARect.Bottom), Point(ARect.Right, ARect.Bottom)]);
    Grid.DrawPolyline(Grid.Canvas, [Point(ARect.Right, ARect.Top), Point(ARect.Right, ARect.Bottom+1)]);
    if (AreaCell.X = 0) then
      Grid.DrawPolyline(Grid.Canvas, [Point(ARect.Left, ARect.Top), Point(ARect.Left, ARect.Bottom+1)]);
  end else if NextRowIsSpecial then
  begin
    Grid.Canvas.Pen.Color := clRed;
    Grid.DrawPolyline(Grid.Canvas, [Point(ARect.Left, ARect.Bottom), Point(ARect.Right+1, ARect.Bottom)]);
  end;

  Processed := True;
end;


Демо проект прилагается.
В Демо проекте в Unit2 приведен пример реализации окантовки через наследование грида.

Вложения:
2021-03-03-ColoringGridLines.zip [9.54 KiB]
Скачиваний: 109
sshot-174.png
sshot-174.png [ 31.95 KiB | Просмотров: 3073 ]

Автор:  GoldMedium [ 04 мар 2021, 08:40 ]
Заголовок сообщения:  Re: Отрисовка границ ячеек

Просто фантастика!! Это то, что нужно. Спасибо Вам ОГРОМНОЕ!!
Вы всегда находите решение и делаете это оперативно. Отличная поддержка.

Единственный момент, можно ли задавать цвет границ для текущей строки (синим цветом на примере)?
У меня остаются артефакты при перемещении к следующей строке.

Вложения:
Screen3.png
Screen3.png [ 38.32 KiB | Просмотров: 3062 ]

Автор:  EhLibSupport [ 04 мар 2021, 16:17 ]
Заголовок сообщения:  Re: Отрисовка границ ячеек

Добрый день.

Чтобы ушли артефакты при перемещении на следующую строку необходимо перерисовывать весь грид.
Добавьте следующее событие

Код:
procedure TForm1.DataSource1DataChange(Sender: TObject; Field: TField);
begin
  DBGridEh1.Invalidate;
end;

Автор:  GoldMedium [ 04 мар 2021, 21:28 ]
Заголовок сообщения:  Re: Отрисовка границ ячеек

Добрый день.
Это именно то, чего не хватало! Теперь всё работает именно так, как нужно.
Надеюсь только, что постоянные вызовы DBGridEh1.Invalidate при переходе к следующий записи в гриде не сильно скажутся на скорости.

Вы меня очень выручили.
Спасибо вам БОЛЬШОЕ!! :D :D :D

Автор:  GoldMedium [ 09 мар 2021, 20:39 ]
Заголовок сообщения:  Re: Отрисовка границ ячеек

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

Чтобы обратить к следующей записи грида нужно, чтобы он был подключен через MemTableEh. В этом случае всё отлично работает.
Но в нашем проекте очень много форм, где грид подключен напрямую к TFDQuery (FireDAC) и там прочитать значение следующей записи без изменения текущей (как в MemTableEh) нельзя.
По-крайней мере, насколько мне известно.

Чтобы добавить во все формы посредника в виде MemTableEh - это очень большой фронт работы и в разумные сроки сделать это нереально.
Можно ли каким-то образом прочитать из грида значение заданной ячейки?
Например, находясь в колонке 1 и строке 1 получить значение из колонки 1 и строки 2. При этом оставаясь в 1-й строке.

Очень жду ответа.
Спасибо Вам большое!

Автор:  istrebitel [ 10 мар 2021, 02:39 ]
Заголовок сообщения:  Re: Отрисовка границ ячеек

бегать по датасету без генерации событий на свой страх и риск.

Автор:  GoldMedium [ 10 мар 2021, 07:28 ]
Заголовок сообщения:  Re: Отрисовка границ ячеек

istrebitel писал(а):

Причём здесь датасет.
Цитата:
...прочитать из грида...

К слову, и датасет датасету рознь. Где-то есть подобный функционал. Но это другая тема.
Вопрос по-прежнему открытый.

Из текущей строки без проблем получаю значение любой ячейки функцией:
GetEditText(ACol, ARow: Longint)
Но работает, к сожалению, только для текущей строки.

Автор:  istrebitel [ 10 мар 2021, 09:16 ]
Заголовок сообщения:  Re: Отрисовка границ ячеек

GoldMedium писал(а):
...прочитать из грида...

в гриде данных нет

GoldMedium писал(а):
К слову, и датасет датасету рознь. Где-то есть подобный функционал. Но это другая тема.
Вопрос по-прежнему открытый.

Этот функционал и есть стандартный, грид именно этим функционалом и бежит по датасету когда его отрисовывает.
Код:
procedure TCustomDBGridEh.DrawDataCell(ACol, ARow: Longint;
  AreaCol, AreaRow: Longint; ARect: TRect; AState: TGridDrawState;
  CellAreaType: TCellAreaTypeEh);
///
begin
  ///

  InstantReadRecordEnter(AreaRow);

end.

procedure TCustomDBGridEh.InstantReadRecordEnter(DataRowNum: Integer);
var
  InstReadNode: TGroupDataTreeNodeEh;
begin
  if ViewScroll then
  begin
  end else
  begin
      // всё что не MemTable (все остальные датасеты)
    FOldActiveRecord := DataLink.ActiveRecord;
    DataLink.ActiveRecord := DataRowNum;
  end;
end;


Автор:  GoldMedium [ 10 мар 2021, 09:36 ]
Заголовок сообщения:  Re: Отрисовка границ ячеек

Спасибо Вам за участие и желание помочь. Я понимаю, что в гриде данных нет.
Просто отчаянно ищу решение, чтобы избежать большого объёма работ. Дергать каждый раз при отрисовке датасет не лучшее решение

Автор:  EhLibSupport [ 10 мар 2021, 15:04 ]
Заголовок сообщения:  Re: Отрисовка границ ячеек

Если тип датасета не MemTableEh, то следующий обработчик события должен работать.

Код:
procedure TForm1.DBGridEh1Columns0AdvDrawDataCell(Sender: TCustomDBGridEh; Cell,
  AreaCell: TGridCoord; Column: TColumnEh; const ARect: TRect;
  var Params: TColCellParamsEh; var Processed: Boolean);
var
  Grid: TDBGridEhCrack;
  NextRowIsSpecial: Boolean;
  BottomLineIsDrawn: Boolean;
  LinesIsDrawn: Boolean;
  DataSet: TDataSet;
  OldActiveRecord: Integer;
begin
  Grid := TDBGridEhCrack(Sender);
  DataSet := Grid.DataSource.DataSet;
  NextRowIsSpecial := False;

  if (DataSet.FieldByName('SpecialBorderState').AsInteger = 1) then
  begin
    Params.Background := $006DD3EB;
    Params.Font.Style := [fsBold];
  end;

  Grid.DefaultDrawColumnDataCell(Cell, AreaCell, Column, ARect, Params);

  if (AreaCell.Y < Grid.InstantReadRecordCount - 1) then
  begin
    try
      //Grid.InstantReadRecordEnter(AreaCell.Y + 1);
      OldActiveRecord := Grid.DataLink.ActiveRecord;
      Grid.DataLink.ActiveRecord := AreaCell.Y + 1;
      NextRowIsSpecial := DataSet.FieldByName('SpecialBorderState').AsInteger = 1;
    finally
      //Grid.InstantReadRecordLeave;
      Grid.DataLink.ActiveRecord := OldActiveRecord;
    end;
  end;

  LinesIsDrawn := False;
  BottomLineIsDrawn := False;

  if (Params.Row = Grid.Row) or (Params.Row = Grid.Row - 1) then
  begin
    Grid.Canvas.Pen.Color := clBlue;
    if (Params.Row = Grid.Row) then
    begin
      Grid.DrawPolyline(Grid.Canvas, [Point(ARect.Left, ARect.Bottom), Point(ARect.Right, ARect.Bottom)]);
      Grid.DrawPolyline(Grid.Canvas, [Point(ARect.Right, ARect.Top), Point(ARect.Right, ARect.Bottom+1)]);
      if (AreaCell.X = 0) then
        Grid.DrawPolyline(Grid.Canvas, [Point(ARect.Left, ARect.Top), Point(ARect.Left, ARect.Bottom+1)]);
      LinesIsDrawn := True;
      BottomLineIsDrawn := True;
    end else
    begin
      Grid.DrawPolyline(Grid.Canvas, [Point(ARect.Left, ARect.Bottom), Point(ARect.Right+1, ARect.Bottom)]);
      BottomLineIsDrawn := True;
    end;
  end;

  if (DataSet.FieldByName('SpecialBorderState').AsInteger = 1) and not LinesIsDrawn then
  begin
    Grid.Canvas.Pen.Color := clRed;
    if not (BottomLineIsDrawn) then
      Grid.DrawPolyline(Grid.Canvas, [Point(ARect.Left, ARect.Bottom), Point(ARect.Right, ARect.Bottom)]);
    Grid.DrawPolyline(Grid.Canvas, [Point(ARect.Right, ARect.Top), Point(ARect.Right, ARect.Bottom+1)]);
    if (AreaCell.X = 0) then
      Grid.DrawPolyline(Grid.Canvas, [Point(ARect.Left, ARect.Top), Point(ARect.Left, ARect.Bottom+1)]);
  end else if NextRowIsSpecial and not BottomLineIsDrawn then
  begin
    Grid.Canvas.Pen.Color := clRed;
    Grid.DrawPolyline(Grid.Canvas, [Point(ARect.Left, ARect.Bottom), Point(ARect.Right+1, ARect.Bottom)]);
  end;

  Processed := True;
end;

Автор:  GoldMedium [ 10 мар 2021, 18:38 ]
Заголовок сообщения:  Re: Отрисовка границ ячеек

Просто подарок! Всё отлично отрабатывает!
Не представляете, как Вы меня выручили. Сэкономили мне вагон времени.
Спасибо ВАМ большое!!!

Автор:  Stalker4 [ 12 мар 2021, 07:48 ]
Заголовок сообщения:  Re: Отрисовка границ ячеек

GoldMedium писал(а):
Добрый день.
Чтобы добавить во все формы посредника в виде MemTableEh - это очень большой фронт работы и в разумные сроки сделать это нереально.
Можно ли каким-то образом прочитать из грида значение заданной ячейки?
Например, находясь в колонке 1 и строке 1 получить значение из колонки 1 и строки 2. При этом оставаясь в 1-й строке.

FireDAC (FDQuery, FDMemTable) может как и MemTableEh перемещается по записям не меняя текущую позицию курсора

Цитата:
http://www.sql.ru/forum/actualutils.aspx?action=gotomsg&tid=1008012&msg=21419431

TFDDatSRow есть запись. Объект создается для каждой записи.

Скажем пробежаться по внутренностями TFDDataSet

for i := 0 to FDQuery1.SourceView.Rows.Count - 1 do
FDQuery1.SourceView.Rows[i].GetData(0);

http://www.sql.ru/forum/actualutils.asp ... g=21513141
SourceView.Rows - с учетом фильтра и сортировки
Table.Rows - без учета

Автор:  GoldMedium [ 12 мар 2021, 10:30 ]
Заголовок сообщения:  Re: Отрисовка границ ячеек

Большое спасибо, не знал. Это просто здорово :)

Сравнил у себя скорость отрисовки границ при использовании Grid.DataLink.ActiveRecord и FDQuery1.SourceView.Rows[i].GetData(0).
Оказалось, что вариант Grid.DataLink.ActiveRecord всегда чуть быстрее. Ненамного, но стабильно.
Поэтому остановился пока на первом варианте.

Но за подсказку большое спасибо, буду иметь ввиду

Автор:  GoldMedium [ 12 мар 2021, 11:01 ]
Заголовок сообщения:  Re: Отрисовка границ ячеек

Что касается скорости, есть вопрос по перерисовке грида.
В таблице с 12 колонками, у большинства из которых цвет фона и шрифта меняется в зависимости от значения ячейки, при прокрутке остаётся шлейф из линий, которым выделяется текущая строка.
Grid.Invalidate выполняется в событии OnDataChange у DataSource.
Вероятнее всего при прокрутке грид прорисоваться не успевает и сообщения Invalidate помещаются в очередь. Отсюда заметные артефакты на экране.
С гридами, где меньше цветной раскраски, всё отрабатывает незаметно.

Грид подключен через FDQuery

Вложения:
Simple.gif
Simple.gif [ 120.32 KiB | Просмотров: 2934 ]

Автор:  EhLibSupport [ 12 мар 2021, 12:34 ]
Заголовок сообщения:  Re: Отрисовка границ ячеек

Добрый день.

Вместо DBGridEh.Invalidate; можно попробовать использовать DBGridEh.Repaint;
Отрисовка должна происходить сразу, в коде Repaint.
Но это может замедлить навигацию по гриду.

Автор:  GoldMedium [ 12 мар 2021, 12:52 ]
Заголовок сообщения:  Re: Отрисовка границ ячеек

Добрый день.
Спасибо, проверил. Не помогло, шлейф такой же.
Пробовал добавить DBGridEh.Repaint ещё и в событие AfterScroll. Артефакты отрисовки без изменений.
Вероятно, надо искусственно замедлять навигацию, чтобы грид успевал прорисоваться

Автор:  GoldMedium [ 15 мар 2021, 08:52 ]
Заголовок сообщения:  Re: Отрисовка границ ячеек

В общем, кажется нашёл причину/решение артефактов при прокрутка своего грида. Причина была не в количестве колонок и их отрисовки, а банально в количестве контролов, связанных с тем же DataSource. У меня их было 15-20. Если у всех, кроме грида, обнулить DataSource - прокрутка выполняется быстро и без артефактов.
Похоже нужно при прокрутке отключать обновление (DisableControls) всем контролам, кроме грида.
Иначе Grid.Invalidate в событии TDataSource.OnDataChange просто не успевает

Страница 1 из 1 Часовой пояс: UTC
Powered by phpBB® Forum Software © phpBB Group
http://www.phpbb.com/