В 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)

Ссылки

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *