В практике разработчика на платформе 1С:Предприятие 7.7 часто возникает задача интерактивного выбора нескольких связанных объектов для формирования одной печатной формы. Типичный пример: сначала нужно выбрать ребенка из списка детей клиента, а затем — законного представителя (родителя). Для экономии ресурсов и упрощения структуры кода часто пытаются использовать одну и ту же ТаблицуЗначений (ТЗ). Рассмотрим подробно, как реализовать этот механизм правильно, какие ошибки могут возникнуть и как их избежать.
Основной вопрос заключается в следующем: если мы заполняем ТЗ данными, даем пользователю выбрать строку, а затем очищаем таблицу для новых данных — не пропадут ли результаты первого выбора? Проанализируем ситуацию. Если вы просто сохраняете номер строки (индекс), то после вызова метода УдалитьСтроки() этот индекс станет бесполезным, так как данные по нему будут стерты. Однако, если правильно организовать процесс сохранения выбранных объектов в промежуточные переменные, использование одной ТЗ становится вполне оправданным и удобным.
Разберем по шагам правильную последовательность действий, которую необходимо выполнить программисту для решения этой задачи:
ТаблицаЗначений и определяем необходимые колонки один раз в начале процедуры.ВыбратьСтроку().ВыбранныйРебенок).УдалитьСтроки(). При этом структура колонок сохраняется, а содержимое очищается.ВыбратьСтроку() и сохраняем результат во вторую переменную (например, ВыбранныйРодитель).ВыбранныйРебенок и ВыбранныйРодитель для вывода в печатную форму.Проанализируем программный код, реализующий данную логику. Обратите внимание на важные нюансы работы с выборками справочников в 1С 7.7.
// Инициализация
ТЗ = СоздатьОбъект("ТаблицаЗначений");
ТЗ.НоваяКолонка("Объект");
ТЗ.НоваяКолонка("ФИО");
ТЗ.НоваяКолонка("Возраст");
// Заполнение №1: Дети
Спр = СоздатьОбъект("Справочник.Проживающие");
Спр.ИспользоватьВладельца(ТекущийЭлемент());
Спр.ВыбратьЭлементы();
Пока Спр.ПолучитьЭлемент() = 1 Цикл
Возраст = (РабочаяДата() - Спр.ФизЛицо.ДатаРождения) / 365.25;
Если Возраст < 14 Тогда
ТЗ.НоваяСтрока();
ТЗ.Объект = Спр.ТекущийЭлемент();
ТЗ.ФИО = Спр.ФизЛицо.Наименование;
ТЗ.Возраст = Цел(Возраст);
КонецЕсли;
КонецЦикла;
// Выбор ребенка
Стр = 0;
Если ТЗ.ВыбратьСтроку(Стр, "Выберите ребенка") = 1 Тогда
// Сохраняем ссылку на объект в отдельную переменную!
ВыбранныйРебенок = ТЗ.ПолучитьЗначение(Стр, "Объект");
Иначе
Предупреждение("Ребенок не выбран!");
Возврат;
КонецЕсли;
// ОЧИСТКА ДАННЫХ ДЛЯ ПОВТОРНОГО ИСПОЛЬЗОВАНИЯ
ТЗ.УдалитьСтроки();
// Заполнение №2: Взрослые
// ВАЖНО: нужно сбросить выборку справочника перед повторным использованием
Спр.ВыбратьЭлементы(0);
Пока Спр.ПолучитьЭлемент() = 1 Цикл
Возраст = (РабочаяДата() - Спр.ФизЛицо.ДатаРождения) / 365.25;
Если Возраст >= 18 Тогда
ТЗ.НоваяСтрока();
ТЗ.Объект = Спр.ТекущийЭлемент();
ТЗ.ФИО = Спр.ФизЛицо.Наименование;
ТЗ.Возраст = Цел(Возраст);
КонецЕсли;
КонецЦикла;
// Выбор родителя
Стр = 0;
Если ТЗ.ВыбратьСтроку(Стр, "Выберите представителя") = 1 Тогда
ВыбранныйРодитель = ТЗ.ПолучитьЗначение(Стр, "Объект");
Иначе
Предупреждение("Родитель не выбран!");
Возврат;
КонецЕсли;
// Теперь у нас есть две переменные с объектами, которые можно выводить в макет
Рассмотрим подробнее технические детали, которые часто становятся причиной ошибок в 1С 7.7.
1. Сброс выборки справочника. В платформе 7.7, если вы один раз прошли циклом Пока Спр.ПолучитьЭлемент() = 1, указатель выборки остается в конце списка. Чтобы просканировать тот же самый справочник второй раз (например, сначала искали детей, а потом взрослых), необходимо ОБЯЗАТЕЛЬНО вызвать метод ВыбратьЭлементы() заново. Если этого не сделать, второй цикл просто не начнется, и ваша таблица останется пустой.
2. Расчет возраста. Использование формулы деления разницы дат на 365 дней является приблизительным. Для более точных расчетов, учитывающих високосные годы, рекомендуется использовать значение 365.25 или специализированные функции из глобального модуля. Это критично, если ребенку "почти 14" или взрослому "почти 18".
3. Метод УдалитьСтроки() vs Очистить(). Проанализируем разницу. Метод УдалитьСтроки() удаляет только записи, сохраняя структуру колонок. Это идеально подходит для нашей задачи. Метод Очистить() полностью уничтожает структуру ТЗ, включая колонки, что заставило бы нас заново вызывать НоваяКолонка().
Если вам нужно просто дать пользователю выбрать один элемент из списка, и вам не требуется отображать сложную таблицу с несколькими колонками (ФИО, Возраст, Родство), выясним, не будет ли проще использовать объект СписокЗначений. Рассмотрим пример:
Список = СоздатьОбъект("СписокЗначений");
Спр.ВыбратьЭлементы();
Пока Спр.ПолучитьЭлемент() = 1 Цикл
// В значение кладем ссылку на объект, в представление - текст для пользователя
Список.ДобавитьЗначение(Спр.ТекущийЭлемент(), Спр.ФизЛицо.Наименование + " (" + Спр.Принадлежность + ")");
КонецЦикла;
ВыбранныйОбъект = "";
Если Список.ВыбратьЗначение(ВыбранныйОбъект, "Выберите лицо") = 1 Тогда
// В переменной ВыбранныйОбъект уже лежит ссылка на элемент справочника
КонецЕсли;
Этот способ гораздо лаконичнее, если вам не нужна табличная визуализация при выборе.
Мы выяснили, что использовать одну таблицу значений несколько раз за одну процедуру — это абсолютно нормальная и эффективная практика. Главное условие — сохранять результат каждого выбора в промежуточные переменные до того, как таблица будет очищена методом УдалитьСтроки().
Основные правила совместной работы с ТЗ и макетом:
ТЗ.ПолучитьЗначение(НомерСтроки, "ИмяКолонки") для получения конкретных данных.ВыбранныйРебенок.Наименование).ВыбратьЭлементы()), если используете один и тот же объект справочника для разных циклов.Таким образом, комбинируя правильную работу с объектами 1С 7.7 и логическую последовательность действий, вы сможете создавать быстрые и надежные механизмы подбора данных для любых отчетов и печатных форм.