Михаил Зайкин дата публикации 28-11-2002 12:01 Грид с объединяемыми ячейками данных
По ходу выполнения проекта встала следующая задача: обеспечить ввод данных в таблицу, с возможностью визуально объединить/сгруппировать ячейки данных. Так как даже для одной задачи могут быть различные требования к представлению данных, грид должен
как можно гибче взаимодействовать с пользователем.
Опробовав замечательные MSHFlexGrid, ObjectiveGrid и получив пару десятков вопросов “а почему…”, “а как..”, и замечаний “а вотя я …, а он не…” решено было, что пусть грид будет поглупее, попроще, зато пользователь будет в полной мере контролировать структуру таблицы.
Определены типы объединения: 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 – видимая часть диапазона
Остальное, думаю, понятно.
Определен, собственно, грид: TMZMergeStringGrid = class(TStringGrid)
Часть полей и функций была напрямую скопирована из приватной секции 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)
Компонент и пример были созданы в D5. Но компилировались и работали также и в D6.
Вот так вот. Надеюсь, эта тема будет интересна не только новичкам, но и продвинутым программистам.
Жду ваших замечаний, советов и пожеланий. Спасибо.
За развитием компонента следите на сайте автора: http://www.mzdelphi.h10.ru/
[TStringGrid] [Перерисовка компонент] [Отображение списков, сеток]
Обсуждение материала [ 29-10-2003 11:37 ] 5 сообщений |