Грид с объединяемыми ячейками данных
Оформил: DeeCo
Автор: Михаил Зайкин
1. Что было нужно.По ходу выполнения проекта встала следующая задача: обеспечить ввод данных в таблицу, с возможностью визуально объединить/сгруппировать ячейки данных. Так как даже для одной задачи могут быть различные требования к представлению данных, грид должен как можно гибче взаимодействовать с пользователем.Опробовав замечательные MSHFlexGrid, ObjectiveGrid и получив пару десятков вопросов “а почему…”, “а как..”, и замечаний “а вотя я …, а он не…” решено было, что пусть грид будет поглупее, попроще, зато пользователь будет в полной мере контролировать структуру таблицы.
2. Что было сделано.
Определены типы объединения: TMergeMode=(mmNone,mmByCol,mmByRow,mmFree);- mmNone – объединение не производится, MergeCells всегда возвращает nil
- mmByCol – объединяются клетки внутри одного столбца, из заданного для объединения диапазона используется его левая часть
- mmByRow – объединяются клетки внутри одной строки, из заданного для объединения диапазона используется его верхняя часть
- mmFree - объединяются клетки в любых диапазонах
Определен класс-диапазон:
TMZRange = class(TObject) private FOwner: TMZMergeStringGrid; FRect: TGridRect; function GetValue: string; procedure SetValue(Value: string); public constructor Create(AOwner: TMZMergeStringGrid; Range: TGridRect); function Contain(ACol, ARow: integer): boolean; overload; function Contain(ARect: TGridRect): boolean; overload; function Intersect(ARect: TGridRect): boolean; function Visible: boolean; function VisibleRect: TGridRect; property Rect: TGridRect read FRect; property Value: string read GetValue write SetValue; end;
- Небольшие пояснения:
-
- Contain – содержит ли внутри клетку (диапазон)
- Intersect – пересекается ли с диапазоном
- Value – значение. В качестве оного используется значение левой верхней клетки. Данные в остальных клетках не изменяются.
- VisibleRect – видимая часть диапазона
Часть полей и функций была напрямую скопирована из приватной секции TCustomGrid.
Добавлены public функции и свойства:- function MergeCells(ARect:TGridRect):TMZRange
- – пытается произвести объединение заданного диапазона и возвращает
указатель в случае успеха и nil в противном случае.
Отказ функции может быть в следующих случаях:- MergeMode=mmNone
- заданный диапазон включает только одну ячейку
- диапазон задан не с левого верхнего угла
- такой диапазон уже есть
- заданный диапазон конфликтует с уже имеющимися
- function Range(ACol,ARow:integer):TMZRange
- – диапазон, содержащий ячейку, nil – в случае отсутствия оного.
- procedure SplitAllRanges
- function SplitRange(ACol,ARow:integer):boolean
- function SplitRange(rng:TMZRange):Boolean
- – уничтожение диапазонов
- property Ranges[Index:Integer]:TMZRange
- property RangeCount:integer
- – понятно
- property RangeValue[ACol,ARow:integer]:string
- – значение диапазона. Если не существует диапазона, включающего данную
ячейку, возвращается Cells[ACol, ARow]
- property MergeMode:TMergeMode
- – понятно
Переписаны методы Paint и DrawCell.
Paint:- убрана неиспользуемая теперь переменная LineColor
- в DrawCells убраны все вызовы DrawFocusRect
- основном коде метода убран четвертый вызов DrawLines
- в конце процедуры сами рисуем рамку фокуса DrawFocusRect
DrawCell:
Краса и гордость класса. ;-) Метод полностью переписан.
Попробую объяснить, что же я тут наваял.
- 1) Рисуем границы.
- Работаем мы не с фиксированными ячейками. Если ячейка не принадлежит ни одному диапазону – рисуем все ее границы. В противном же случае, внутри диапазона границы стираем, внешние же, напротив, пожирнее.
- 2) Рисуем содержимое ячейки.
- Сначала рассчитываем размер области вывода, затем выводим текст. Все просто.
3. Использование компонента.
При использовании таблицы считаем, что в опциях не установлены флажки goRovMoving, goColMoving, goEditing, goAlwaysShowEditor. Эти ситуации, соответственно, не обрабатываются. Также не используется и InplaceEditor.4. Недостатки компонента.
- Событие OnCellDraw отсутствует. Но нам оно и не было нужно. Хотя… Диапазоны разным цветом можно было бы…
- Содержимое диапазона отрисовывается при каждом вызове DrawCell для ячейки диапазона. Т.е. если на экране видно 100 ячеек диапазона, столько и будет и отрисовок. Ну и еще поскроллируйте туда, обратно.…
- Нет переноса слов.
- Нет выравнивания. Да, это Вам не Ексель.
- Когда курсором бегаем по гриду, пересекая объединения, замечаем разрывы на правой и нижней границе.
- И самое неприятное. Попробуйте поверх окна с гридом (не важно, в runtime или designtime) повозить другое окно. Или размеры окна примера поизменять. Вот такие вот артефакты. Их появление связано с тем, что, собственно, большого опыта по написанию именно визуальных компонент у меня нет.
Скачать архив проекта: MergeGrid.zip (10 K)

Вот так вот. Надеюсь, эта тема будет интересна не только новичкам, но и продвинутым программистам.
Жду ваших замечаний, советов и пожеланий. Спасибо.Далее: Добавление колонки в StringGrid »»