В разработке на платформе 1С:Предприятие 7.7 часто возникает задача создания гибких отчетов, где состав колонок и их визуальное расположение (например, многострочное отображение ячеек) должны меняться «на лету» в зависимости от настроек пользователя. Стандартные средства платформы сильно ограничены в управлении геометрией таблиц на форме, поэтому программисты часто прибегают к использованию внешней компоненты FormEx.
Рассмотрим ситуацию, когда при изменении флага на форме (например, «Полная ведомость») нам необходимо не только скрыть или показать колонки, но и изменить их положение, имитируя многострочную шапку, как в табличных частях документов. Проанализируем типичные ошибки, возникающие при таком подходе, и выработаем оптимальный алгоритм решения задачи.
Основная сложность заключается в том, что при программном удалении и добавлении колонок в объект ТаблицаЗначений, который связан с визуальным элементом на форме, связь между данными и их представлением может нарушиться. Это приводит к «вылетам» системы или отображению пустой таблицы. Выясним основные причины нестабильности:
УдалитьКолонку() менее эффективно, чем специализированные методы.ПриОткрытии или ПриОбновленииФормы часто приводит к ошибкам, так как визуальный объект (контрол Windows) может быть еще не инициализирован или находиться в процессе перерисовки.Вместо того чтобы в цикле удалять каждую колонку по отдельности, проанализируем возможности стандартного метода Очистить(). Этот метод полностью сбрасывает и строки, и структуру колонок таблицы значений, что позволяет начать формирование структуры «с чистого листа».
Рассмотрим фрагмент кода для подготовки таблицы:
Процедура НастроитьТбТовары()
// Полностью очищаем структуру и данные
тбТовары.Очистить();
// Добавляем базовые колонки, которые есть всегда
тбТовары.НоваяКолонка("Цвет", "Строка");
тбТовары.ВидимостьКолонки("Цвет", 0); // Служебная колонка для раскраски
тбТовары.НоваяКолонка("Товар", , , , "Товар", 50);
Если ПолнаяВедомость = 1 Тогда
тбТовары.НоваяКолонка("СуммаНачИнв", "Число", 12, 2, "Сумма Нач. Инв.", 10);
тбТовары.НоваяКолонка("КвоНачИнв", "Число", 12, 0, "Кво Нач. Инв.", 10);
// ... добавление остальных колонок
КонецЕсли;
КонецПроцедуры
Важный нюанс: метод Очистить() работает надежнее, чем ручное удаление колонок в цикле Пока тбТовары.КоличествоКолонок() <> 0, так как гарантирует атомарность операции.
Метод ПоложениеКолонкиТаблицы объекта РасширениеФормы позволяет управлять тем, как колонки размещаются друг относительно друга. Разберем параметры этого метода:
Посмотрим на пример реализации настройки многострочного вида:
Процедура НастроитьГеометриюТаблицы()
РФорма = СоздатьОбъект("РасширениеФормы");
Если ПолнаяВедомость = 1 Тогда
// Размещаем КвоНачИнв под СуммаНачИнв
// Допустим, СуммаНачИнв — это 3-я колонка, а КвоНачИнв — 4-я
РФорма.ПоложениеКолонкиТаблицы("тбТовары", 4, 2);
// Размещаем КвоНач под СуммаНач (колонки 5 и 6)
РФорма.ПоложениеКолонкиТаблицы("тбТовары", 6, 2);
Иначе
// Возвращаем стандартное отображение (в ряд)
РФорма.ПоложениеКолонкиТаблицы("тбТовары", 4, 1);
РФорма.ПоложениеКолонкиТаблицы("тбТовары", 6, 1);
КонецЕсли;
КонецПроцедуры
Для ускорения работы, особенно если используется 1С++ и прямой доступ к SQL, рекомендуется формировать данные в одну временную таблицу и затем выгружать их. Выясним, как правильно связать результат запроса с динамической таблицей на форме.
Если мы используем ODBCRecordset, лучше всего сначала получить данные в промежуточную (внутреннюю) таблицу значений, а затем перенести их в экранную таблицу. Это позволяет избежать конфликтов при отрисовке в момент изменения структуры.
// Пример получения данных через 1С++
тбДанные = RS.ВыполнитьИнструкцию(ТекстЗапроса);
// Вместо прямой выгрузки (которая убьет структуру экранной ТЗ),
// заполняем экранную таблицу построчно или через Заполнить()
тбТовары.КоличествоСтрок(0);
тбДанные.ВыбратьСтроки();
Пока тбДанные.ПолучитьСтроку() = 1 Цикл
тбТовары.НоваяСтрока();
// Копируем данные по именам колонок
Для Ном = 1 По тбТовары.КоличествоКолонок() Цикл
ИмяКол = тбТовары.ПолучитьПараметрыКолонки(Ном);
Если тбДанные.КоличествоКолонок(ИмяКол) > 0 Тогда
тбТовары.УстановитьЗначение(тбТовары.НомерСтроки, ИмяКол, тбДанные.ПолучитьЗначение(тбДанные.НомерСтроки, ИмяКол));
КонецЕсли;
КонецЦикла;
КонецЦикла;
Как отмечалось в обсуждении, методы FormEx наиболее стабильно работают, когда форма уже полностью «жива». Рекомендуется использовать специальное событие ПослеОткрытия(), предоставляемое компонентой FormEx.
Проанализируем правильную последовательность действий при переключении режима (флажка):
ПолнаяВедомость.Сформировать().Сформировать() сначала вызывается НастроитьТбТовары() (очистка и создание колонок).ПоложениеКолонкиТаблицы.Форма.Обновить().Совет: Если при смене режима 1С все же ведет себя нестабильно, попробуйте вынести настройку положения колонок в ОбработкаОжидания с минимальной задержкой (0.1 сек). Это даст платформе время завершить внутренние процессы перерисовки ТЗ.
Работа с видимостью: Если вам нужно просто скрыть колонки без изменения их «этажности», используйте штатный метод ВидимостьКолонки(Имя, Состояние). Однако помните, что скрытые колонки все равно занимают индекс в коллекции. Если вы скрыли колонку №2, то визуально колонка №3 станет второй, но для FormEx она может остаться под номером 3. Всегда проверяйте соответствие индексов после изменения видимости.
Цветовое выделение: При динамическом формировании строк удобно использовать возможности FormEx для раскраски. Создайте колонку Цвет, сделайте ее невидимой и записывайте туда значения в формате "BRUSH[0xRRGGBB]". Это позволит наглядно выделить ошибки или итоги в вашей обновленной таблице.
Закрытие формы: Если при проверке условий (например, не найдена предыдущая инвентаризация) вам нужно прервать работу, используйте конструкцию СтатусВозврата(0); Возврат; в предопределенных процедурах. Это корректно остановит открытие формы или выполнение процесса.
Подводя итог, можно сказать, что связка динамической таблицы значений и FormEx — мощный инструмент, требующий строгого соблюдения последовательности действий: сначала данные и структура, затем — визуальные эффекты и позиционирование.