В процессе разработки интерфейсов на обычных (неуправляемых) формах в «1С:Предприятии 8» программисты часто сталкиваются со специфическим поведением платформы. Типичная задача: на форме расположены две горизонтальные панели (или рамки группы), разделенные интерактивной границей. Требуется по нажатию кнопки скрыть правую панель, а левую растянуть на всю ширину формы. Однако стандартный вызов метода УстановитьПривязку или скрытие через изменение видимости не дают мгновенного результата — левая панель упорно остается на своем месте до тех пор, пока пользователь вручную не изменит размер всего окна программы.
В рамках этой статьи мы подробно разберем, почему возникает этот визуальный баг, детально проанализируем физику работы механизма привязок в обычных формах и рассмотрим четыре практических способа реализации динамического растяжения элементов, включая готовый универсальный алгоритм управления разделителями.
В обычных формах расчет координат и геометрии элементов жестко оптимизирован платформой для обеспечения высокой производительности интерфейса. Когда мы программно вызываем метод УстановитьПривязку или изменяем свойство Свертка, платформа фиксирует новые правила позиционирования во внутренней памяти, но не инициирует немедленный пересчет сетки разметки (layout).
Этот пересчет принудительно срабатывает только в момент возникновения системного события изменения размеров самой формы (аналог события OnResize в операционной системе). Именно поэтому элемент визуально встает на свое место только после того, как пользователь слегка потянет за край окна или развернет его на весь экран. Нам необходимо заставить платформу обновить интерфейс программно.
---
Для скрытия панелей разработчики платформы предусмотрели специальное свойство Свертка (использующее перечисление РежимСверткиЭлементаУправления). Оно позволяет схлопнуть элемент управления в заданном направлении. Однако если на форме присутствует элемент-разделитель (сплиттер), простая свертка заблокируется жесткими связями разделителя.
Рассмотрим готовую универсальную процедуру, которая решает эту проблему. Алгоритм временно освобождает привязки сворачиваемого элемента, перестраивает цепочку зависимостей «сворачиваемый элемент -> разделитель -> видимый элемент» и корректно управляет свойством Свертка.
Ниже представлен код этой процедуры, которую мы рекомендуем разместить в общем модуле или модуле формы:
Процедура глУстановитьВидимостьПанели(ЭтаФорма, Условие, ЭлементВидимый, ЭлементСворачиваемый, ЭлементРазделитель, Знач Свертка = Неопределено) Экспорт
Если Свертка = Неопределено Тогда
Свертка = "Низ";
КонецЕсли;
// Определяем противоположное направление для настройки зависимостей
Если Свертка = "Низ" Тогда
Обратно = "Верх";
ИначеЕсли Свертка = "Верх" Тогда
Обратно = "Низ";
ИначеЕсли Свертка = "Лево" Тогда
Обратно = "Право";
ИначеЕсли Свертка = "Право" Тогда
Обратно = "Лево";
КонецЕсли;
// Освобождаем сворачиваемый элемент от жестких привязок
ЭлементСворачиваемый.УстановитьПривязку(ГраницаЭлементаУправления[Обратно]);
// Выстраиваем последовательную цепочку привязок элементов друг за другом
ЭлементРазделитель.УстановитьПривязку(
ГраницаЭлементаУправления[Свертка],
ЭлементСворачиваемый,
ГраницаЭлементаУправления[Обратно]
);
ЭлементРазделитель.УстановитьПривязку(
ГраницаЭлементаУправления[Обратно],
ЭлементРазделитель,
ГраницаЭлементаУправления[Свертка]
);
ЭлементВидимый.УстановитьПривязку(
ГраницаЭлементаУправления[Свертка],
ЭлементРазделитель,
ГраницаЭлементаУправления[Обратно]
);
Если Условие Тогда
// Сценарий 1: Показываем скрытую ранее панель
ЭлементСворачиваемый.Свертка = РежимСверткиЭлементаУправления.Нет;
// Меняем зависимость сворачиваемый/разделитель местами для доступности интерактивного перетаскивания
ЭлементРазделитель.УстановитьПривязку(ГраницаЭлементаУправления[Свертка]);
ЭлементСворачиваемый.УстановитьПривязку(
ГраницаЭлементаУправления[Обратно],
ЭлементРазделитель,
ГраницаЭлементаУправления[Свертка]
);
Иначе
// Сценарий 2: Сворачиваем (скрываем) панель
ЭлементСворачиваемый.Свертка = РежимСверткиЭлементаУправления[Свертка];
КонецЕсли;
// Скрываем сам разделитель, чтобы пользователь не мог его двигать в свернутом режиме
ЭлементРазделитель.Доступность = Условие;
ЭлементРазделитель.Видимость = Условие;
КонецПроцедуры
Важное примечание: при вызове метода УстановитьПривязку внутри панели в качестве второго параметра (объект связи) всегда передавайте именно родительский контейнер (например, ЭлементыФормы.ПанельГруппировки), а не ключевое слово ЭтаФорма. Если вы укажете форму для вложенных во внутреннюю панель элементов, привязки нарушатся.
---
Если вы уже настроили корректные привязки и правила свёртки программно, но элементы по-прежнему не встают на свои места мгновенно, можно применить проверенную временем хитрость. Мы можем заставить платформу поверить, что пользователь изменил размер окна.
Для этого сразу после кода скрытия и изменения привязок мы программно увеличиваем ширину (или высоту) формы на 1 пиксель и моментально возвращаем её в исходное состояние. Это действие полностью безопасно, визуально незаметно для пользователя, но гарантированно запускает цикл пересчета координат платформы:
// Выполняем скрытие правой панели и переопределение привязок
ЭлементыФормы.ПраваяПанель.Видимость = Ложь;
ЭлементыФормы.ЛеваяПанель.УстановитьПривязку(ГраницаЭлементаУправления.Право, ЭлементыФормы.ОсновнаяПанель, ГраницаЭлементаУправления.Право);
// Инициируем принудительный пересчет интерфейса платформой 1С
ЭтаФорма.Ширина = ЭтаФорма.Ширина + 1;
ЭтаФорма.Ширина = ЭтаФорма.Ширина - 1;
Этот простой трюк избавляет от необходимости писать десятки строк кода для управления сложными деревьями привязок.
---
Динамическое изменение привязок в рантайме часто приводит к трудночитаемому коду, который тяжело отлаживать. Альтернативный надежный подход — полностью отказаться от изменения привязок «на лету» и управлять геометрией элементов напрямую через свойства Лево, Ширина, Верх и Высота.
Проанализируем этот подход на практическом примере. Допустим, у нас есть ПанельЛ (левая), Разделитель1 и ПанельП (правая). Нам нужно свернуть правую часть и растянуть левую.
Видимость = Ложь.Ширина левой панели. Изменение размеров элементов в коде напрямую отображается на экране мгновенно и не требует хаков с изменением размеров формы.Пример кода для реализации данного метода:
// Скрываем ненужные элементы
ЭлементыФормы.ПанельП.Видимость = Ложь;
ЭлементыФормы.Разделитель1.Видимость = Ложь;
// Рассчитываем новую ширину левой панели
НоваяШирина = ЭлементыФормы.ПанельЛ.Ширина + ЭлементыФормы.Разделитель1.Ширина + ЭлементыФормы.ПанельП.Ширина;
ЭлементыФормы.ПанельЛ.Ширина = НоваяШирина;
При восстановлении исходного состояния выполняем обратную операцию: сначала возвращаем левой панели её исходную ширину, а затем делаем видимыми разделитель и правую панель.
---
Если интерфейс вашей формы слишком перегружен элементами и ручной пересчет координат грозит превратить код в спагетти, мы рекомендуем применить элегантный архитектурный прием — дублирование UI-контейнеров с использованием многостраничной панели.
Разберем этот метод по шагам:
ОтображениеЗакладок = Ложь).
Процедура ДействияФормыПереключитьРежим(Кнопка)
Если РежимРастянутогоЭкрана Тогда
// Переключаемся на страницу с одной широкой панелью
ЭлементыФормы.ОсновнаяПанель.ТекущаяСтраница = ЭлементыФормы.ОсновнаяПанель.Страницы.СтраницаОдинЭлемент;
Иначе
// Возвращаемся к стандартному режиму с двумя панелями
ЭлементыФормы.ОсновнаяПанель.ТекущаяСтраница = ЭлементыФормы.ОсновнаяПанель.Страницы.СтраницаДваЭлемента;
КонецЕсли;
КонецПроцедуры
Платформа мгновенно и без малейших задержек перерисует интерфейс, так как все привязки были заранее жестко просчитаны и сохранены в метаданных формы еще на этапе конфигурирования.
Мы рассмотрели особенности работы геометрического движка обычных форм 1С. Для простых сценариев отлично подойдет метод искусственного изменения размера формы (Способ 2). Если же на форме активно используется разделитель (Splitter), то наиболее надежным решением станет применение готовой процедуры динамической смены привязок (Способ 1) или переход к архитектуре с переключением страниц панелей (Способ 4).