В My Visual Database имеется возможность ручной настройки ширины колонок для каждого табличного представления. Но в некоторых случаях хочется более разумного поведения: автоматическое выравнивание по ширине данных или выравнивание ширины при изменении размера таблицы. С помощью скриптов можно добиться нужного эффекта.
Предлагаю вниманию читателей несколько скриптов, которые позволят пользователю самостоятельно выбирать необходимый ему уровень автоматизации выравнивания колонок из четырёх доступных вариантов:
- По умолчанию – ручное выравнивание
- Пропорционально – равная ширина для всех колонок, сохраняется при изменении размера таблицы
- По данным – ширина устанавливается таким образом, чтобы все данные отображались целиком, без обрезки
- Растянуть последнюю – последняя колонка растягивается и заполняет видимую область таблицы
Управление
Управление будет осуществляться через всплывающее меню грида, поэтому прежде всего понадобится процедура Grid_AddColWidthMenu(), создающая необходимые пункты меню. В процессе создания мы определяем, какая настройка была установлена ранее, используя чтение данных из файла settings.ini с помощью функции IniFile_Read() из модуля IniFile.pas.
const
// режимы автоматической установки ширины колонок
GRID_CW_DEFAULT_NAME = 'Default'; // по умолчанию - ручная установка
GRID_CW_PROPORTIONAL_NAME = 'Proportional'; // все видимые колонки равной ширины
GRID_CW_DATA_NAME = 'Data'; // ширина колонки по ширине данных
GRID_CW_FILL_NAME = 'Fill'; // последнюю колонку растянуть так, чтобы заполнить грид
GRID_CW_MIN = 20; // минимальная ширина колонки; используется в режиме GRID_CW_FILL_NAME
GRID_EXTRA_DATA_SECTION = 'GridsExt'; // название секции для хранения дополнительных параметров гридов
GRID_CW_PARAM_NAME = 'CWMode'; // название параметра для хранения режима выравнивания колонок
procedure Grid_AddColWidthMenu(AGrid: TdbStringGridEx);
// добавить во всплывающее меню пункты управления поведением колонок
var
tmpMenu: TPopupMenu;
tmpItem: TMenuItem;
tmpSubItem: TMenuItem;
tmpForm: TForm;
tmpMode:string;
tmpParamName: string;
begin
CForm(AGrid, tmpForm);
// читаем режим из настроек
tmpParamName := tmpForm.Name +'.'+ AGrid.Name+'.'+GRID_CW_PARAM_NAME;
tmpMode := IniFile_Read(GRID_EXTRA_DATA_SECTION,tmpParamName,GRID_CW_DEFAULT_NAME); // если нет данных, то устанавливаем режим по умолчанию
tmpMenu := AGrid.PopupMenu; // будем работать с меню грида
// добавить визуальный разделитель
tmpItem := TMenuItem.Create(tmpForm);
tmpItem.Caption := '-';
tmpMenu.Items.Add(tmpItem);
// добавить переключение в режим дерево, по умолчанию
tmpItem := TMenuItem.Create(tmpForm);
tmpItem.Caption := 'Ширина колонок';
tmpMenu.Items.Add(tmpItem);
// добавить переключение в режим списка
tmpSubItem := TMenuItem.Create(tmpForm);
tmpSubItem.Name := T_MENU_ITEM + GRID_CW_DEFAULT_NAME+'_'+AGrid.Name;
tmpSubItem.Caption := 'По умолчанию';
tmpSubItem.Checked := tmpMode = GRID_CW_DEFAULT_NAME;
tmpSubItem.RadioItem := True;
tmpSubItem.GroupIndex := 1;
tmpSubItem.onClick := 'Grid_CW_Click';
tmpItem.Add(tmpSubItem);
//
tmpSubItem := TMenuItem.Create(tmpForm);
tmpSubItem.Caption := 'Пропорционально';
tmpSubItem.Checked := tmpMode = GRID_CW_PROPORTIONAL_NAME;
tmpSubItem.RadioItem := True;
tmpSubItem.GroupIndex := 1;
tmpSubItem.Name := T_MENU_ITEM + GRID_CW_PROPORTIONAL_NAME+'_'+AGrid.Name;
tmpSubItem.onClick := 'Grid_CW_Click';
tmpItem.Add(tmpSubItem);
//
tmpSubItem := TMenuItem.Create(tmpForm);
tmpSubItem.Caption := 'По данным';
tmpSubItem.Checked := tmpMode = GRID_CW_DATA_NAME;
tmpSubItem.RadioItem := True;
tmpSubItem.GroupIndex := 1;
tmpSubItem.Name := T_MENU_ITEM + GRID_CW_DATA_NAME+'_'+AGrid.Name;
tmpSubItem.onClick := 'Grid_CW_Click';
tmpItem.Add(tmpSubItem);
//
tmpSubItem := TMenuItem.Create(tmpForm);
tmpSubItem.Caption := 'Растянуть последнюю';
tmpSubItem.Checked := tmpMode = GRID_CW_FILL_NAME;
tmpSubItem.RadioItem := True;
tmpSubItem.GroupIndex := 1;
tmpSubItem.NAME := T_MENU_ITEM + GRID_CW_FILL_NAME+'_'+AGrid.Name;
tmpSubItem.onClick := 'Grid_CW_Click';
tmpItem.Add(tmpSubItem);
end;
Code language: PHP (php)
Для всех четырёх пунктов меню используется один обработчик – Grid_CW_Click(), в котором производится оперативные изменения ширины колонок и сохранение выбранного режима в файл settings.ini.
procedure Grid_CW_Click(Sender: TObject);
// обработка выбора пункта меню - изменить ширину колонок
var
tmpItem: TMenuItem;
tmpMenu: TPopupMenu;
tmpGrid: TdbStringGridEx;
tmpName: string;
tmpParamName: string;
tmpForm: TForm;
begin
CForm(Sender,tmpForm);
tmpItem := TMenuItem(Sender);
tmpMenu := TPopupMenu(tmpItem.GetParentMenu);
tmpGrid := TdbStringGridEx(tmpMenu.PopupComponent);
tmpName := DeleteClassName( DeleteSuffix( tmpItem.Name ) );
tmpItem.Checked := True; // выделить пункт меню.
// в некоторых случаях требуется незамедлительная реакция (выравнивание)
case tmpName of
GRID_CW_PROPORTIONAL_NAME: Grid_OnResize(tmpGrid);
GRID_CW_DATA_NAME: tmpGrid.BestFitColumns(bfBoth);
GRID_CW_FILL_NAME: Grid_OnResize(tmpGrid);
end; {case}
tmpParamName := tmpForm.Name +'.'+ tmpGrid.Name+'.'+GRID_CW_PARAM_NAME;
// сохранить настойку в параметрах
IniFile_Write(GRID_EXTRA_DATA_SECTION,tmpParamName,tmpName);
end;
Code language: PHP (php)
Выравнивание
В зависимости от типа выравнивания оно должно осуществляться при обновлении данных и/или при изменении размера грида. Поэтому алгоритмы выравнивания находятся в двух процедурах:
- Grid_OnChange() – изменение данных (по значению)
- Grid_OnResize() – изменение размера (пропорциональное выравнивание и заполнение)
В обработчике Grid_OnChange() вызывается метод грида BestFitColumns(), который собственно и осуществляет нужное действие. Метод имеет параметр – тип выравнивания TBestFitMode:
- bfCells – по данным в ячейках
- bfHeader – по надписям заголовка
- bfBoth – по данным и по заголовку
procedure Grid_OnChange (Sender: TObject );
// обработчик по умолчанию с поддержкой выравнивания по данным
var
tmpGrid:TdbStringGridEx;
tmpForm:TForm;
begin
CForm(Sender,tmpForm);
tmpGrid := TdbStringGridEx(Sender);
// выравнивание по ширине данных
if Grid_CW_IsMode(tmpGrid,GRID_CW_DATA_NAME) then
tmpGrid.BestFitColumns(bfBoth)
else // остальные выравнивания
if Grid_CW_IsMode(tmpGrid,GRID_CW_PROPORTIONAL_NAME) or Grid_CW_IsMode(tmpGrid,GRID_CW_FILL_NAME) then
Grid_OnResize(tmpGrid);
end;
Code language: JavaScript (javascript)
Обработчик Grid_OnResize() реализует остальные типы выравнивания, включая особый случай, когда в гриде одна колонка. В этом случае колонка растягивается на всю ширину грида, даже если установлен другой тип авторазмера. Мне это показалось разумным, но создавать отдельную опцию управления для этого я не стал. Зато вынес для удобства алгоритм определения числа видимых колонок в отдельную функцию – Grid_VisibledColCount(). А также понадобилась функция, с помощью которой можно определить, включен ли тот или иной режим автовыравнивания – Grid_CW_IsMode().
function Grid_VisibledColCount(AGrid:TdbStringGridEx):integer;
// возвращает число видимых колонок в гриде
var
i: integer;
begin
Result := 0;
for i:=0 to AGrid.Columns.Count - 1 do
if AGrid.Columns[i].Visible then
inc(Result);
end;
function Grid_CW_IsMode(AGrid:TdbStringGridEx; AModeName:string):boolean;
// определить, включен ли указанный режим для таблицы
var
tmpForm: TForm;
tmpItem: TMenuItem;
tmpName: string;
begin
// функция ищет чекер у соотвесвтующего элемента меню
CForm(AGrid,tmpForm);
tmpName := T_MENU_ITEM+AModeName+'_'+AGrid.Name;
FindC(tmpForm,tmpName,tmpItem,False);
if tmpItem <> nil then
begin // если элемент найден, то вернуть чекер
Result := tmpItem.Checked;
end
else // если не найден по каким-то причинам, то выравнивание по умолчанию
begin
Result := AModeName = GRID_CW_DEFAULT_NAME;
end;
end;
procedure Grid_OnResize(Sender: TObject);
// обработчик, отвечающий за автоматический размер колонок к таблице
var
tmpGrid: TdbStringGridEx;
tmpColumnCount: integer;
tmpColWidth: integer;
tmpCol: integer;
i:integer;
tmpGridLineWidth: integer;
begin
tmpGrid := TdbStringGridEx(Sender);
tmpGridLineWidth := 1; // TODO: свойства goGrid и GridLineStyle влияют на эту величину и могут сделать её нулевой. добавить алгоритм определения фактической толщины вертикальной линии разметки
// на автоширину колонок влияют число колонок и выбранный режим выравнивания
if tmpGrid.Columns.Count = 1 then // только если одна колонка
tmpGrid.Columns[0].Width := tmpGrid.ClientWidth // растягиваем её на всю клиентскую область таблицы
else // если колонок много, то действуем по правилам
if Grid_CW_IsMode(tmpGrid,GRID_CW_PROPORTIONAL_NAME) then
begin // пропорционально количеству видимых колонок
tmpColumnCount := Grid_VisibledColCount(tmpGrid);
tmpColWidth := trunc( tmpGrid.ClientWidth / tmpColumnCount );
for i:=0 to tmpGrid.Columns.Count - 1 do
if tmpGrid.Columns[i].Visible then
tmpGrid.Columns[i].Width := tmpColWidth;
end
else // растягивание последней видимой колонки
if Grid_CW_IsMode(tmpGrid,GRID_CW_FILL_NAME) then
begin // последнюю колонку растянуть так, чтобы заполнить грид
// находим последнюю видимую колонку
for i := tmpGrid.Columns.Count - 1 downto 0 do
if tmpGrid.Columns[i].Visible then
begin
tmpCol := i;
Break
end;
// считаем ширину всех колонок, кроме последней видимой
tmpColWidth := 0;
for i:=0 to tmpCol - 1 do
if tmpGrid.Columns[i].Visible then
inc(tmpColWidth, tmpGrid.Columns[i].Width+tmpGridLineWidth );
tmpColWidth := tmpGrid.ClientWidth - tmpColWidth;
if tmpColWidth <= GRID_CW_MIN then
tmpGrid.Columns[tmpCol].Width := GRID_CW_MIN
else
tmpGrid.Columns[tmpCol].Width := tmpColWidth;
end;
end;
Code language: PHP (php)
Автоматизация
Для того, чтобы создать меню настройки выравниванием и подключить обработчики у всех гридов приложения нам потребуется ещё парочка процедур:
- From_AddColWidthMenu() – добавить меню и обработчики для всех гридов на указанной форме
- App_AddColWidthMenu() – добавить меню и обработчики для всех форм
Таким образом, для того, чтобы у всех таблиц появилась возможность настраивать автоматическое выравнивание, достаточно вызвать процедуру – App_AddColWidthMenu().
procedure App_AddColWidthMenu();
// добавляем ко всем формам меню управления автошириной колонок таблиц
var
i:integer;
begin
for i := 0 to Screen.FormCount - 1 do
From_AddColWidthMenu(Screen.Forms[i]);
end;
procedure From_AddColWidthMenu(AForm: TForm);
// добавляем ко всем таблицам меню управления автошириной колонок таблиц
var
i: integer;
tmpGrid: TdbStringGridEx;
begin
for i:=0 to AForm.ComponentCount - 1 do
begin
if AForm.Components[i] is TdbStringGridEx then
begin
tmpGrid := TdbStringGridEx(AForm.Components[i]);
Grid_AddColWidthMenu(tmpGrid);
// если есть пользовательский обработчик, то нужно добавлять вызов обработчика по умолчанию непосредственно в нем
// если нет, то будет добавлен обработчик по умолчанию
if tmpGrid.OnResize = '' then // на изменение размера грида
tmpGrid.OnResize := 'Grid_OnResize';
if tmpGrid.OnChange = '' then // на изменение данных в гриде
tmpGrid.OnChange := 'Grid_OnChange';
end;
end;
end;
Code language: JavaScript (javascript)
Ссылки
- DataKeeper 1.8 – исходный код проекта