При разработке интерфейсов в 1С:Предприятии 8 перед программистом нередко встает задача разместить открывающуюся форму (например, печатную форму документа или специализированную панель подбора) в строго определенной части экрана. В старых обычных формах мы могли легко управлять координатами с помощью свойств Лево и Верх. Однако с переходом на управляемые формы (УФ) концепция кардинально изменилась: теперь платформа самостоятельно рассчитывает геометрию окон.
В этой статье мы подробно разберем, как обойти ограничения управляемого интерфейса, рассмотрим штатные механизмы позиционирования окон, научимся сбрасывать кэш настроек пользователя и проанализируем альтернативные «внештатные» методы эмуляции интерфейса.
Разработчики платформы 1С сознательно убрали возможность прямого пиксельного позиционирования для управляемых форм. Это связано с тем, что управляемый интерфейс должен быть кроссплатформенным и адаптивным. Окна должны одинаково предсказуемо отображаться на мониторах с разным разрешением, в веб-клиенте под управлением различных браузеров, а также на мобильных устройствах.
Тем не менее, нам часто требуется закрепить печатную форму сбоку или снизу экрана, чтобы пользователь мог одновременно видеть и документ-источник, и результат формирования печатной формы. Давайте детально изучим доступные нам инструменты.
Платформа 1С предоставляет набор свойств управляемой формы, которые позволяют управлять её начальным положением и поведением на экране. Эти свойства необходимо настраивать строго до открытия формы — например, в обработчике события ПриСозданииНаСервере или передавая их в параметрах метода ОткрытьФорму.
Рассмотрим ключевые свойства, которые помогут нам решить задачу:
СостояниеОкна (WindowState) — определяет, в каком виде откроется форма. Нам доступны значения: ВариантСостоянияОкна.Обычное, ВариантСостоянияОкна.Максимизированное, ВариантСостоянияОкна.Минимизированное, а также наиболее интересные для нас — ВариантСостоянияОкна.Прикрепленное и ВариантСостоянияОкна.Прячущееся.ПоложениеПрикрепленногоОкна (DockedWindowPosition) — если для предыдущего свойства выбрано значение Прикрепленное, то здесь мы можем указать сторону прикрепления формы к главному окну приложения. Доступные варианты: ВариантПоложенияПрикрепленногоОкна.Лево, ВариантПоложенияПрикрепленногоОкна.Право, ВариантПоложенияПрикрепленногоОкна.Верх, ВариантПоложенияПрикрепленногоОкна.Низ.ПоложениеОкна (WindowPosition) — управляет начальным размещением свободного (неприкрепленного) окна. Мы можем выбрать центрирование (ВариантПоложенияОкна.Центрировать) или режим ВариантПоложенияОкна.НеПерекрыватьВладельца, при котором платформа постарается расположить форму рядом с родительским окном.Проанализируем пример программной настройки формы при ее создании на сервере:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Задаем режим прикрепленного окна
ЭтаФорма.СостояниеОкна = ВариантСостоянияОкна.Прикрепленное;
// Прижимаем форму к нижней части экрана
ЭтаФорма.ПоложениеПрикрепленногоОкна = ВариантПоложенияПрикрепленногоОкна.Низ;
// Блокируем окно владельца, если требуется последовательная работа
ЭтаФорма.РежимОткрытияОкна = РежимОткрытияОкнаФормы.Независимый;
КонецПроцедуры
Этот способ является полностью безопасным, кроссплатформенным и будет корректно работать как на тонком клиенте под Windows/Linux, так и в веб-клиенте.
Очень часто разработчики сталкиваются со следующей проблемой: программный код написан верно, но при открытии форма упорно появляется в случайном месте или сохраняет старые размеры. Выясним причину этого поведения.
Дело в том, что платформа 1С по умолчанию сохраняет пользовательские настройки окон (размер, положение, состояние прикрепления) в системном кэше базы данных. Приоритет пользовательских настроек всегда выше программных. Если пользователь хотя бы один раз вручную переместил или растянул форму, платформа запомнит это состояние и проигнорирует ваши установки СостояниеОкна при следующем запуске.
Чтобы решить эту проблему и заставить форму всегда открываться в заданном нами положении, мы можем применить два подхода.
Вариант А. Динамическая генерация уникального ключа сохранения
Мы можем динамически изменять уникальный идентификатор формы при каждом открытии. В этом случае платформа будет считать, что открывается абсолютно новое окно, для которого еще нет сохраненных настроек в кэше, и применит наши программные параметры.
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Генерируем новый ключ, чтобы настройки кэша не влияли на форму
ЭтаФорма.КлючСохраненияПоложенияОкна = Строка(Новый УникальныйИдентификатор);
// Устанавливаем требуемое положение
ЭтаФорма.СостояниеОкна = ВариантСостоянияОкна.Прикрепленное;
ЭтаФорма.ПоложениеПрикрепленногоОкна = ВариантПоложенияПрикрепленногоОкна.Право;
КонецПроцедуры
Вариант Б. Принудительная очистка настроек окна в системном хранилище
Если нам нужно точечно сбросить кэш конкретного окна для пользователя, мы можем программно удалить сохраненные настройки из системного хранилища настроек 1С:
&НаСервере
Процедура СброситьНастройкиПоложенияОкнаНаСервере()
КлючОбъекта = "ОбщаяФорма.ПечатьДокументов/НастройкиОкна";
ИмяПользователя = ПользователиИнформационнойБазы.ТекущийПользователь().Имя;
// Удаляем старые записи позиционирования из базы данных
ХранилищеСистемныхНастроек.Удалить(КлючОбъекта, "", ИмяПользователя);
КонецПроцедуры
Рассмотрим нестандартный метод, предложенный в обсуждении на форуме. Он основан на использовании Windows Script Host и COM-объекта WScript.Shell для имитации нажатий клавиш клавиатуры. Этот способ позволяет эмулировать вызов системного меню окна 1С и выбор команды «Закрепить справа/слева/снизу».
Давайте посмотрим на программную реализацию этого алгоритма:
&НаКлиенте
Процедура ПриОткрытии(Отказ)
// Подключаем однократный обработчик ожидания, чтобы дать форме полностью отрисоваться
ПодключитьОбработчикОжидания("ЗакрепитьФормуСправа", 0.1, Истина);
КонецПроцедуры
&НаКлиенте
Процедура ЗакрепитьФормуСправа()
Если ЭтаФорма.ВводДоступен() Тогда
Попытка
WSHShell = Новый COMОбъект("WScript.Shell");
// Активируем системное меню окна комбинацией клавиш
WSHShell.SendKeys("%"); // Нажатие Alt
WSHShell.SendKeys("{DOWN 5}"); // Переход по элементам системного меню
WSHShell.SendKeys("{RIGHT}"); // Переход в подменю прикрепления
WSHShell.SendKeys("{UP 5}"); // Выбор нужного направления закрепления
WSHShell.SendKeys("{ENTER}"); // Подтверждение действия
Исключение
ЗаписьЖурналаРегистрации("ЭмуляцияИнтерфейса", УровеньЖурналаРегистрации.Предупреждение, , ,
"Не удалось запустить скрипт эмуляции нажатий: " + ОписаниеОшибки());
КонецПопытки;
ОтключитьОбработчикОжидания("ЗакрепитьФормуСправа");
КонецЕсли;
КонецПроцедуры
Важные ограничения и недостатки данного метода:
SendKeys отправляет нажатия в текущее активное окно операционной системы. Если пользователь в момент открытия формы переключится на другое приложение (например, на документ Excel или браузер), то эмулируемые нажатия клавиш будут выполнены там, что может привести к непредсказуемым действиям в сторонних программах.Если перед вами стоит бескомпромиссная задача поместить управляемую форму строго по пиксельным координатам (например, X: 100, Y: 150) под управлением ОС Windows, стандартных средств 1С будет недостаточно. В этом случае на помощь приходит использование WinAPI через внешние компоненты (например, Native API).
Идея метода заключается в получении системного дескриптора окна 1С (так называемого HWND) и вызове стандартных функций библиотеки user32.dll, таких как SetWindowPos или MoveWindow.
Общая схема реализации выглядит следующим образом:
ПриОткрытии на клиенте компонент находит окно 1С по его уникальному заголовку (который можно временно сгенерировать уникальным на момент поиска).SetWindowPos окну принудительно выставляются точные геометрические параметры: координаты левого верхнего угла, ширина и высота.Этот способ требует продвинутых навыков программирования и написания/подключения внешних библиотек, однако он гарантирует абсолютно точное пиксельное позиционирование окна в обход любых внутренних ограничений платформы 1С.
Подводя итоги нашего анализа, выделим оптимальные стратегии для решения задачи позиционирования форм: