====== Настройка внешнего вида и поведения UniLines ====== Для **UniLines**-а уже разработаны и предусмотрены различные варианты кастомизации его работы. В целом, их можно разделить на следующие группы: * Работа с выборными элементами (представление элементов как чекбоксов); * Управление выбранными элементами; * Кастомизация управляющих кнопок * Текстовые опции. ===== Работа с выборными элементами (представление элементов как чекбоксов)===== **UniLines** позволяет отобразить элементы в виде галочек. Например, как это сделано в модуле **DiscExt.pas** (внешняя дисконтная схема), для отображения таблицы со скидками на каждую группу слуг. {{:pasted:20220905-101535.png}} Включение галочного представления осуществляется за счёт опции **ShowCheckBoxes** (по умолчанию **False**). Включение этой опции, по сути, для каждой ноды **VST** выставляет свойство **CheckType := ctCheckBox**. Опция **IsTriStateCheckBoxes** отвечает за возможность отображать "смешанное" состояние чекбокса (когда у дочерних элементов как стоят галочки, так и не стоят): {{:pasted:20220905-101950.png}} В коде обработка происходит следующим образом: procedure TUniLinesFrame.SetShowCheckBoxes(const Value: boolean); var Node: PVirtualNode; begin FShowCheckBoxes := Value; //присвоение опции Node:=VST.GetFirst; //получаем указатель на первую ноду while Node<>nil do //в цикле по всем нодам begin if FShowCheckBoxes then //для каждой выставляем CheckType либо ctNone (без чекбокса), либо ctCheckBox (два состояния), либо ctTriStateCheckBox (три состояния). if FIsTriStateCheckBoxes then VST.CheckType[Node]:=ctTriStateCheckBox else VST.CheckType[Node] := ctCheckBox else VST.CheckType[Node]:=ctNone; Node:=VST.GetNext(Node); end; end; //для новых нод тоже анализируется эта опция, чтобы сразу им выставить CheckType. function TUniLinesFrame.AddData(ANode: PVirtualNode = nil): PLinesData; var Node: PVirtualNode; i: integer; begin if ANode=nil then begin Node:=VST.AddChild(nil); if FIsMultiline then Node.States:=Node.States+[vsMultiline]; end else Node:=ANode; if FShowCheckBoxes then if FIsTriStateCheckBoxes then VST.CheckType[Node]:=ctTriStateCheckBox else VST.CheckType[Node] := ctCheckBox; //... и т.д. end; Опция **ShowCustomCheckBoxes** позволяет подгрузить специальные иконки для чекбоксов. У нас они берутся из **ImgDMForm.ilChecksTree32**: begin FShowCustomCheckBoxes := Value; if FShowCustomCheckBoxes then begin vst.CustomCheckImages:=ImgDMForm.ilChecksTree32; vst.CheckImageKind:=ckCustom; vst.DefaultNodeHeight:=Max(vst.DefaultNodeHeight, ScaleMeasure(40)); end else begin vst.CheckImageKind:=ckXP; vst.CustomCheckImages:=nil; end; end; Для работы с чекбоксами в рамках **UniLines** реализованы на текущий момент следующие функции/процедуры: * function GetCheckedValues(const ValueName: string; GetSQLStr: boolean = True; Delimiter: string = ','): string; - через указанный разделитель собирает все значения ValueName, у которых отмечены галочки; * procedure SetCheckedValues(ValueName, Checked: string; Delimiter: string = ','); - всем значениям, которые соответствуют указанным через Delimiter ValueName, выставить значение Checked; * procedure CheckAll; - проставить галочки у всех нод; * procedure UnCheckAll; - убрать галочки у всех нод; * procedure Inversion; - инвертировать галочки у всех нод. Изменение галочек осуществляется через свойство ноды **CheckState**, например: procedure TUniLinesFrame.CheckAll; var Node: PVirtualNode; begin if not FShowCheckBoxes then Exit; Node:=VST.GetFirst; while Node<>nil do begin if Node.CheckState<>csCheckedNormal then Node.CheckState:=csCheckedNormal; Node:=VST.GetNext(Node); end; end; ===== Управление выбранными элементами ===== Выбранной нодой, если по-простому, можно считать ту ноду, по которой случился клик. Через **ctrl** выбранных нод может оказаться несколько: {{:pasted:20220905-105127.png}} Основное управление выбранными нодами осуществляется через **VST**, например VST.Selected[LastNode] := True; У нас реализованы функции и процедуры: * function SelectedCount: int64; - возвращает количество выбранных нод; * function TUniLinesFrame.GetIDsFromSel: string; - получает список значений PrimaryValue выбранных нод через запятую; * procedure TUniLinesFrame.SelectAll; - выбрать все ноды; * procedure TUniLinesFrame.SelectLastNode; - выбрать последнюю ноду; * procedure LastLine(FirstVisible: boolean = True); - выбрать последнюю строку; * procedure PrevLine(PrevVisible: boolean = True); - выбрать предыдущую строку. ===== Кастомизация управляющих кнопок ===== Для **UniLines**-а предусмотрено несколько методов, позволяющих добавить кастомные кнопки и элементы меню, чтобы можно было сделать уникальное поведение этого фрейма на разных формах, без необходимости изменения в дизайн-тайме. ==== Добавление элементов выпадающего меню в заголовок ==== Имеется в виду меню, возникающее по правому клику на заголовке: {{:pasted:20220905-123441.png}} Реализовано с помощью функции function AddHeaderMenuItem(const ACaption: string; AAutoCheck, AChecked: boolean; AOnClick: TNotifyEvent; InMenu: TMenuItem; DoHookPopup: boolean = True): TMenuItem; * ACaption - Название меню; * AAutoCheck - позволяет автоматически менять свойство Checked при клике; * AChecked - позволяет работать с меню, как с чекбоксом; * AOnClick - событие, которое должно сработать при нажатии на кнопку; * InMenu - ссылка на объект меню, внутри которого должен создаться новый объект; * DoHookPopup - позволяет отрисовывать меню в скине. Пример: it:=UDL.ULF.AddHeaderMenuItem('Показывать только с остатками', True, False, OnShowOnlyRestClick, nil); procedure TTovarsModalForm.OnShowOnlyRestClick(Sender: TObject); var st: TSetting; begin //st := DMForm.SettingList.GetSetting(dkObject,MetaObject_Tag,'SHOW_ONLY_AT_CUR_SCLAD',dtBoolean); st := DMForm.SettingList.GetSetting(dkObject,MetaObject_Tag,'SHOW_ONLY_REST',dtBoolean); if st<>nil then begin if Sender<>nil then begin st.AsBoolean := TMenuItem(Sender).Checked; st.Save(RdTr, UpTr); end; ShowOnlyRest := st.AsBoolean; end; RefreshAll; end; ==== Добавление меню в выпадающий список дерева ==== Имеется в виду окно, возникающее при правом клике на элементе **UniLines** {{:pasted:20220905-130209.png}} Реализация выполнена с помощью function AddPopupMenuItem(const ACaption: string; AOnClick: TNotifyEvent; AImageIndex: integer; AVisible: boolean = True; DoHookPopup: boolean = True): TMenuItem; * **ACaption** - Название пункта меню; * **AOnClick** - событие при клике; * **AImageIndex** - номер иконки (берётся из **ImgDMForm.ilAll**); * **AVisible** - видимость пункта меню; * **DoHookPopup** - позволяет отрисовывать меню в скине. Из интересного тут появляется возможность рулить видимостью пункта меню. Пример: ULF.AddPopupMenuItem('Переотправить сообщение', ResendSMS, -1); //процедура срабатывает при получении состояний дерева, находит нужный элемент меню и меняет его видимостью procedure TSMSLogForm.ULFVSTStateChange(Sender: TBaseVirtualTree; Enter, Leave: TVirtualTreeStates); var it: TMenuItem; i: integer; begin if ULF.Value['ID'] <> Null then begin for i := ULF.VST.PopupMenu.Items.Count - 1 downto 0 do begin it := TMenuItem(ULF.VST.PopupMenu.Items[i]); if it.Caption = Translat('Переотправить сообщение') then begin it.Visible := ((ULF.Value['oper_status'] = 'СМС заблокировано химчисткой') or (ULF.Value['oper_status'] = 'Не доставлено')); break; end; end; end; end; ==== Добавление кнопки в тулбар ==== Имеется в виду вот эта область: {{:pasted:20220905-131422.png}} Реализовано с помощью function AddToolbarButton(const ACaption: string; AAfterPosition: integer; AImageIndex: integer; AOnClick: TNotifyEvent; AIsCheck: boolean = False): TsSpeedButton; * **ACaption** - название кнопки; * **AAfterPosition** - позиция кнопки (есть значения tpsEndButtons = 0 - после всех основных кнопок и tpsEndCheckbox = 1 - после всех чекбоксов); * **AImageIndex** - индекс картинки, берётся из ImgDMForm.ilAll; * **AOnClick** - событие нажатия; * **AIsCheck** - должна ли кнопка быть чекбоксом. Пример: AddToolbarButton('Отправка документов', tpsEndCheckbox, 47, btEmailClick); procedure TInvoicesForm.btEmailClick(Sender: TObject); var frm: TInvoicesSendEmailForm; begin Application.CreateForm(TInvoicesSendEmailForm, frm); try if frm.ShowModal in [mrOK, mrCancel] then begin if frm.IsSendMail then acRefreshExecute(self); end; finally frm.Free; end; end; ==== Видимость стандартных пунктов меню ==== Под стандартными подразумеваются кнопки "Создать", "Изменить", "Редактировать", "Печать" и прочие подобные, а также соответствующие им элементы выпадающего меню. В **UniLines**-е предусмотрено множество вариаций по их отображению, также как и отображение целых панелей. Подробно рассматривать не будем, названия должны понятно отражать их суть. property ShowPopupMenu: boolean read FShowPopupMenu write SetShowPopupMenu; property ShowToolbar: boolean read FShowToolbar write SetShowToolbar; property ShowToolbarAndPopup: boolean read FShowToolbarAndPopup write SetShowToolbarAndPopup; property ShowToolbarOnlyLoadSave: boolean read FShowToolbarOnlyLoadSave write SetShowToolbarOnlyLoadSave; property ShowToolbarHorizontalSelectUnselect: boolean read FShowToolbarHorizontalSelectUnselect write SetShowToolbarHorizontalSelectUnselect; property ShowOnlyAddButtons: Boolean read GetShowAddButton write SetShowAddButton; property ShowOnlyParentButtons: Boolean read GetShowParentButton write SetShowParentButton; property ShowOnlyEditButtons: Boolean read GetShowCorrButton write SetShowCorrButton; property ShowOnlyDelButton: Boolean read GetShowDelButton write SetShowDelButton; property ShowAddEditButtons: Boolean read GetShowAddCorrButtons write SetShowAddCorrButtons; property ShowAddDelButtons: Boolean read GetShowAddDelButtons write SetShowAddDelButtons; property ShowEditButtons: Boolean read GetShowAllEditButtons write SetShowAllEditButtons; ===== Текстовые опции===== Также, в **UniLines**-е возможно настраивать ячейки с информацией, правила её отображения и возможность изменения. ==== Настройка отображения ==== property IsMultiline: boolean - добавляет всем нодам настройку vsMultiline (Node.States:=Node.States+[vsMultiline]), поддерживающую многострочность текста в соответствии с шириной колонки; property IsHtml: boolean - при True позволяет обрабатывать html-теги, а также позволяет подключить ряд опций по обработке текста; property FullText: boolean - при True предотвращает обрезание текста, в противном случае весь невлезший текст будет заменён многоточием (только для IsHtml = True); property FullTextIsCenter: boolean - при True центрирует текст по высоте (только для IsHtml = True); property SmallNodeHeight: boolean - нода имеет фиксированную высоту (25 пикселей), иначе 37; её включение блокирует опцию AutoCalcHodeHeight; property AutoCalcHodeHeight: boolean - автоматический расчёт требуемой высоты ноды (только для IsHtml = True); property MinNodeHeight: integer - если не равен 0, то выступает в качестве значения высоты ноды при включённой SmallNodeHeight (только для IsHtml = True); Таким образом, в стандартном **ULF** разрешается только многострочность и ручная регулировка высоты ноды. Но при включении **IsHtml** становится возможным серьёзно управлять отображением текста. ==== Настройка редактирования ==== property AutoEdit: boolean - включает возможность редактирования колонок (при клике на ней можно вписать своё значение). Вызывает процедуру VST.EditNode При редактировании появляется возможность использовать несколько полезных обработчиков: procedure VSTEditing(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean); - перед редактированием колонки Column можно изменить её Allowed, чтобы запретить/разрешить редактирование; procedure VSTNewText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; NewText: String); - срабатывает, когда в колонке Column появляется NewText, который можно получить для какой-либо обработки. В этой процедуре у ноды можно изменить её текст. [[https://agbis.getcourse.ru/pl/teach/control/lesson/view?id=254286906|Пройти тест]] [[https://doc.agb.is/develop/unilines|Назад]]