При разработке интерфейсов на платформе 1С 7.7 стандартных элементов управления часто бывает недостаточно. Для реализации красивых закладок, деревьев (TreeView), списков (ListView) или индикаторов процесса (ProgressBar) программисты часто прибегают к использованию внешних ActiveX-компонентов из стандартной библиотеки Windows — MSComCtlLib. Однако при работе с ними разработчики сталкиваются с двумя главными проблемами: отсутствием встроенной документации по методам объектов в 1С и ошибками при попытке принудительного обновления элементов на форме.
В этой статье мы подробно разберем, как быстро находить доступные свойства и методы любых ActiveX-компонентов, рассмотрим правильный способ создания элементов управления на форме 1С 7.7, решим проблему зависания и ошибок метода Refresh(), а также проанализируем стабильные альтернативные варианты реализации интерфейса.
Поскольку среда разработки 1С 7.7 не имеет встроенного автодополнения (IntelliSense) для внешних OLE- и ActiveX-объектов, информацию об их структуре приходится искать во внешних источниках. Самый простой, быстрый и надежный способ узнать состав свойств, методов и событий любого установленного в системе ActiveX-контрола — это использование обозревателя объектов (Object Browser) в пакете Microsoft Office.
Разберем этот процесс по шагам:
<All Libraries>) найдите нужную библиотеку, например MSComCtlLib.MSCOMCTL.OCX в системной директории).ProgressBar, TreeView, ImageList), а в правом — все их методы, свойства и события с указанием типов передаваемых параметров.Для того чтобы внедрить ActiveX-элемент на форму в 1С 7.7, обычно используется внешняя компонента 1С++ или Йоксель, предоставляющая класс АктивИкс. Рассмотрим пример функции, которая инициализирует элемент управления и связывает его с атрибутом формы:
Функция СоздатьКонтрол(ИмяКонтрола, ИмяАтрибутаФормы)
АктивХ = СоздатьОбъект("АктивИкс");
АктивХ.УстановитьАтрибут(Форма, ИмяАтрибутаФормы);
АктивХ.СоздатьЭУ(ИмяКонтрола);
Возврат АктивХ.Объект;
КонецФункции
В этом коде мы создаем объект класса АктивИкс, позиционируем его на форме поверх заранее подготовленного пустого текстового атрибута с идентификатором ИмяАтрибутаФормы и инициализируем сам элемент управления по его программному идентификатору (ProgID). Функция возвращает непосредственный OLE-объект, с методами и свойствами которого мы и будем работать в кодовой базе 1С.
Рассмотрим типичный сценарий использования прогресс-бара из библиотеки MSComCtlLib.ProgCtrl.2. Разработчики часто пытаются обновлять состояние индикатора в цикле следующим образом:
Прог = СоздатьКонтрол("MSComCtlLib.ProgCtrl.2", "Prog");
Прог.Min = 1;
Прог.Max = 100000;
Для ы = 1 По 100000 Цикл
Прог.Value = ы;
// Попытка принудительно обновить элемент
Прог.Refresh(); // Вызывает ошибку IDispatch!
КонецЦикла;
При запуске такого кода система выдает ошибку на строке Прог.Refresh(). Выясним причину этого поведения. Дело в том, что стандартный контейнер 1С 7.7 не всегда корректно транслирует вызовы интерфейса IDispatch для некоторых системных методов элементов ActiveX. Прямой вызов Refresh() отвергается OLE-контейнером.
Вторая проблема заключается в том, что использование штатного метода 1С Форма.Обновить() внутри плотных циклов приводит к катастрофическому падению производительности и жуткому мерцанию экрана, так как система пытается полностью перерисовать все элементы диалога на каждой итерации.
Как правильно решить проблему отрисовки?
Во-первых, в операционных системах Windows изменение свойства Value у элемента ProgressBar автоматически отправляет системе сигнал на перерисовку (событие WM_PAINT) конкретно для этого элемента. Дополнительный вызов Refresh() или Форма.Обновить() просто не требуется. Код работает корректно и без них:
Для ы = 1 По 100000 Цикл
Прог.Value = ы;
КонецЦикла;
Во-вторых, обновление интерфейса на каждой итерации при больших объемах данных избыточно и сильно замедляет работу алгоритма. Проанализируем ситуацию: человеческий глаз не способен заметить изменение прогресса на 0.001%. Оптимально обновлять прогресс-бар только тогда, когда реально меняется целое значение процента выполнения (дискретно). Посмотрим на пример оптимизированного цикла:
ВсегоОпераций = 100000;
Прог.Min = 0;
Прог.Max = 100;
ПредыдущийПроцент = -1;
Для ы = 1 По ВсегоОпераций Цикл
// Выполняем полезную работу...
ТекущийПроцент = Цел((ы / ВсегоОпераций) * 100);
Если ТекущийПроцент <> ПредыдущийПроцент Тогда
Прог.Value = ТекущийПроцент;
ПредыдущийПроцент = ТекущийПроцент;
КонецЕсли;
КонецЦикла;
Такой подход снижает количество обращений к графической подсистеме Windows с 100 000 до 100 раз. Скорость выполнения операции при этом возрастает в разы, а индикатор заполняется плавно и красиво.
При использовании компонентов из библиотеки MSComCtlLib на современных операционных системах (Windows 10, Windows 11, Windows Server) важно учитывать следующие ограничения:
MSCOMCTL.OCX должна быть зарегистрирована в системе через 32-битный загрузчик, находящийся по пути C:\Windows\SysWOW64\regsvr32.exe, запущенный от имени администратора.1cv77.exe при попытке инициализации устаревших элементов ActiveX. При возникновении беспричинных "вылетов" программы необходимо добавить исполняемый файл 1С в исключения DEP.Если вы хотите избежать проблем с регистрацией внешних ActiveX-библиотек на компьютерах пользователей, рассмотрим более надежные и простые альтернативы.
1. Использование внешней компоненты FormEx
Популярная библиотека FormEx предоставляет собственный встроенный объект класса ПрогрессБар. Он работает стабильно, не требует регистрации сторонних OCX-файлов в реестре Windows и может быть легко размещен как в любом месте формы, так и непосредственно внутри системной строки состояния (Status Bar) внизу экрана.
2. Текстовая псевдографика в строке состояния (без внешних компонент)
Это самый быстрый, надежный и бесконфликтный способ вывода прогресса выполнения задачи. Шкала формируется программно из текстовых символов-заполнителей и выводится в статус-строку с помощью стандартной функции Состояние(). Посмотрим на пример реализации:
ВсегоШагов = 500;
Для Шаг = 1 По ВсегоШагов Цикл
// Полезный код алгоритма...
Процент = Цел((Шаг / ВсегоШагов) * 100);
Шкала = СтрЗаменить(Формат("", "С" + Цел(Процент / 5)), " ", "|");
Состояние("Обработка данных: " + Процент + "% [" + ФиксШирина(Шкала, 20, ".") + "]");
КонецЦикла;
В данном примере функция Формат("", "С" + Число) генерирует строку из пробелов заданной длины, которая затем заменяется на символы-разделители "|". Этот способ работает мгновенно, не вызывает мерцания интерфейса и гарантированно откроется на любом компьютере без установки дополнительных библиотек.
3. Использование HTML-контейнера (Shell.Explorer.2)
Вместо нестабильных библиотек ActiveX на форму можно поместить стандартный браузерный контейнер через ProgID "Shell.Explorer.2". Сам прогресс-бар в этом случае верстается на CSS и HTML, а управление его состоянием и анимацией происходит с помощью простых скриптов на JavaScript, передаваемых из кода 1С. Это дает неограниченные возможности для стилизации интерфейса под любые современные стандарты дизайна.