Разработка под платформу 1С:Предприятие 7.7 в современном мире требует от программиста нестандартных подходов и глубокого понимания внутренних механизмов системы. Легендарная внешняя компонента FormEx до сих пор остается главным инструментом расширения возможностей "семерки", позволяя реализовывать функционал, который штатно появился только в старших версиях платформы 1С:Предприятие 8. В данной статье мы подробно разберем три важнейших практических кейса, затронутых разработчиками в процессе обсуждения: точечное позиционирование присоединяемых секций таблиц, особенности работы со встроенным генератором штрихкодов Zint (включая стандарты ITF-14 и DataMatrix) и безопасный перехват фокуса элементов формы через специализированный объект РасширениеФормы.
При формировании сложных печатных форм, отчетов или этикеток разработчики часто сталкиваются с необходимостью выводить секции макета не последовательно (сверху вниз или слева направо), а в строго определенные координаты таблицы. Штатный метод 1С 7.7 ПрисоединитьСекцию() всегда начинает вывод от правой границы последней выведенной области, что делает невозможным параллельное формирование двух независимых колонок или печать нескольких документов «бок о бок» на одном листе без использования сложных механизмов областей.
Для решения этой проблемы был разработан и внедрен метод Сервис::УстановитьПоследнююЯчейкуТаблицы(Таблица, Строка, Колонка). Он позволяет принудительно сместить внутренний указатель «последней ячейки» объекта Таблица на нужные координаты. Последующий вызов метода Таблица.ПрисоединитьСекцию() выполнит вставку секции именно с указанной ячейки.
Рассмотрим подробнее важную деталь: этот метод не раздвигает сетку таблицы по горизонтали или вертикали. Он фактически производит наложение (перезапись) выводимой области поверх существующей разметки. Это требует от нас предварительного расчета координат вывода и подготовки структуры макета.
Давайте разберем по шагам практический пример, в котором мы сформируем две независимые таблицы (например, два товарных чека) бок о бок на одном печатном листе:
// Создаем объект таблицы и подготавливаем сервис FormEx
Таб = СоздатьОбъект("Таблица");
Сервис = СоздатьОбъект("Сервис");
// Выводим левую часть (первый чек) обычным способом
Таб.ВывестиСекцию("ШапкаЛевая");
Для Ном = 1 По 5 Цикл
Таб.ВывестиСекцию("СтрокаЛевая");
КонецЦикла;
Таб.ВывестиСекцию("ПодвалЛевая");
// Теперь нам нужно вывести правый чек, начиная со строго определенной позиции.
// Пусть правый чек должен начинаться с 1-й строки и 8-й колонки.
// Используем новый метод для изменения позиции указателя вывода:
Сервис.УстановитьПоследнююЯчейкуТаблицы(Таб, 1, 7); // Координата колонки передается на 1 меньше, так как присоединение начнется со следующей ячейки
// Присоединяем секции правого чека
Таб.ПрисоединитьСекцию("ШапкаПравая");
// Для вывода последующих строк правого чека нам необходимо смещать указатель на каждую новую строку вниз
Для Ном = 1 По 5 Цикл
Сервис.УстановитьПоследнююЯчейкуТаблицы(Таб, 1 + Ном, 7);
Таб.ПрисоединитьСекцию("СтрокаПравая");
КонецЦикла;
Сервис.УстановитьПоследнююЯчейкуТаблицы(Таб, 7, 7);
Таб.ПрисоединитьСекцию("ПодвалПравая");
Таб.Показать("Печать двух чеков");
Этот простой и элегантный способ избавляет разработчика от написания громоздких алгоритмов обхода ячеек и ручного копирования их свойств, значительно ускоряя процесс построения нелинейных отчетов.
Внешняя компонента FormEx содержит внутри себя полностью скомпилированный код мощной библиотеки генерации штрихкодов Zint. Это означает, что разработчику больше не нужно регистрировать в операционной системе сторонние компоненты (например, ActiveBarCode или специализированные OCX-файлы) или устанавливать шрифты семейства TrueType на каждый рабочий компьютер пользователя.
Метод вывода штрихкода имеет следующий синтаксис:
глСервис.НарисоватьШтрихкод(ОбъектКартинка, ТипКода, ЗначениеКода, ПрятатьТекст)
Однако при работе с различными стандартами кодирования могут возникать неочевидные ошибки, которые мы сейчас проанализируем.
Проблема с кодированием ITF-14:
При попытке сформировать штрихкод ITF-14 (тип кода 89) строкой вида "14660038340832" (ровно 14 символов) библиотека Zint возвращает ошибку "error: Input too long (C0B)". Выясним причину этого поведения.
Дело в том, что алгоритм Zint самостоятельно рассчитывает контрольный символ (последнюю цифру штрихкода) на основе первых 13 цифр. Если передать ему полную 14-значную строку, библиотека считает ее избыточной и генерирует ошибку переполнения. Чтобы штрихкод сформировался корректно, мы должны передавать на вход ровно 13 символов (без контрольной цифры). Библиотека сама вычислит контрольный символ и сформирует валидный штрихкод ITF-14.
Особенности генерации GS1 DataMatrix для маркировки (Честный Знак):
В условиях обязательной маркировки товаров перед разработчиками 1С 7.7 остро встала задача генерации двумерных кодов DataMatrix. Для того чтобы сформированный штрихкод успешно распознавался мобильным приложением «Честный Знак» и складскими сканерами как код маркировки, необходимо соблюдать жесткие стандарты форматирования:
Посмотрим на пример правильного формирования строки для DataMatrix маркировки обуви или одежды:
// Подготавливаем спецсимволы
СимволFNC1 = Симв(232);
СимволGS = Симв(29);
// Собираем строку маркировки по стандарту GS1
СтрокаМаркировки = СимволFNC1 + "0104660038340835" + "21" + "abc123XYZ" + СимволGS + "91" + "ffd0" + СимволGS + "92" + "testCryptKey==";
// Рисуем штрихкод типа DataMatrix (тип кода 71) на объекте Таблицы "РисунокШтрихкод"
глСервис.НарисоватьШтрихкод(Таб.РисунокШтрихкод, 71, СтрокаМаркировки);
Также важно помнить о масштабировании. Чтобы штрихкод не размывался и считывался сканерами без затруднений, объекту картинки на макете необходимо программно задать режим масштабирования без искажения пропорций. Для этого используется вызов метода РежимРисования(3).
Рассмотрим ситуацию, когда нам необходимо перехватить нажатия клавиш на форме для организации быстрого интерактивного поиска по первой букве в списках значений (например, в многострочных частях или кастомных элементах управления). Для этого в глобальном модуле обычно используется предопределенная процедура FormEx ПриНажатииКнопкиКлавиатуры.
Типичная ошибка начинающих разработчиков заключается в попытке получить объект активного элемента формы напрямую через его имя:
// Опасный код, который приведет к ошибке, если фокус находится на кнопке без реквизита:
ИмяЭлемента = конт.форма.АктивныйЭлемент();
вРш = Шаблон("[глПолучитьАтрибФормы(конт." + ИмяЭлемента + ", вАтрибут)]");
Если в момент нажатия клавиши фокус ввода находится на кнопке управления (например, кнопка "Провести", "Закрыть", "Действия"), у которой в конфигураторе не задан ассоциированный реквизит (переменная), система аварийно завершит работу с ошибкой: "Поле агрегатного объекта не обнаружено". Это происходит потому, что контекст формы не содержит свойства с именем этой кнопки.
Чтобы развязать эту проблему и сделать наш код абсолютно устойчивым к любым действиям пользователя, мы должны использовать объект РасширениеФормы, предоставляемый FormEx. Метод ПолучитьАтрибут() этого объекта возвращает специальный прокси-объект типа АтрибутФормы для абсолютно любого элемента диалога, вне зависимости от наличия у него связанной переменной в метаданных.
Проанализируем правильную, безопасную и оптимизированную реализацию поиска по первой букве:
Процедура ПриНажатииКнопкиКлавиатуры(конт, код, _а, _ш, _к, _с, псФСО = 1) Экспорт
псФСО = 1; // По умолчанию разрешаем штатную обработку события
// Проверяем, что контекст является групповым контекстом формы
Если ТипЗначенияСтр(конт) <> "ГрупповойКонтекст" Тогда
Возврат;
КонецЕсли;
// Получаем имя активного элемента формы
вЭлемент = конт.форма.ActiveControl(); // Безопасное получение имени активного элемента в FormEx
Если ПустоеЗначение(вЭлемент) = 1 Тогда
Возврат;
КонецЕсли;
// Инициализируем РасширениеФормы для безопасного анализа элемента
вРасшФормы = СоздатьОбъект("РасширениеФормы");
вРасшФормы.УстановитьФорму(конт.форма);
Попытка
// Получаем атрибут формы без риска вызвать критическую ошибку выполнения
вАтрРФ = вРасшФормы.ПолучитьАтрибут(вЭлемент);
// Нас интересуют только Списки Значений на форме
Если вАтрРФ.ТипЗначенияСтр() <> "СписокЗначений" Тогда
Возврат;
КонецЕсли;
// Получаем сам объект Списка Значений для работы
вАтрибут = вАтрРФ.Значение;
Исключение
// Если что-то пошло не так, просто выходим, не беспокоя пользователя ошибками
Возврат;
КонецПопытки;
// Обрабатываем нажатие буквенно-цифровых клавиш для позиционирования в списке
вСимвол = Нрег(_с);
вСимволы = "0123456789_abcdefghijklmnopqrstuvwxyzабвгдежзийклмнопрстуфхцчшщъыьэюя";
Если Найти(вСимволы, вСимвол) > 0 Тогда
// Подавляем стандартное поведение системы, чтобы символ не ввелся в другие поля
псФСО = 0;
// Запускаем наш алгоритм интерактивного позиционирования в списке
глПоискИПозиционированиеВСпискеИнтерактивно(вАтрибут, вСимвол);
КонецЕсли;
КонецПроцедуры
Использование связки методов РасширениеФормы и ПолучитьАтрибут позволяет полностью исключить появление системных ошибок при навигации по форме и дает разработчику полный контроль над поведением интерфейса 1С:Предприятия 7.7.