При разработке отчетов и печатных форм в среде 1С:Предприятие 7.7 часто возникает задача последовательного интерактивного выбора нескольких параметров. Например, для формирования двустороннего акта или сравнительного отчета пользователю необходимо поочередно выбрать двух разных сотрудников (физических лиц) из списка. Начинающие разработчики часто сталкиваются с трудностями при попытке инициализировать и использовать несколько объектов типа ТаблицаЗначений подряд в рамках одного программного модуля.
В этой статье мы подробно разберем, почему может возникать ошибка при повторном создании таблицы значений, как правильно организовать последовательный выбор с помощью встроенных модальных методов и какие альтернативные подходы используют профессиональные разработчики.
Если в процессе написания кода вы сталкиваетесь с тем, что второй объект таблицы значений не инициализируется или ведет себя непредсказуемо, проанализируем три наиболее распространенные ошибки:
ТЗ, эта переменная резервируется системой для управления элементом интерфейса. Попытка переопределить её в коде через команду ТЗ = СоздатьОбъект("ТаблицаЗначений") вызовет конфликт типов. Запомните: визуальные таблицы значений на форме создаются платформой автоматически при открытии, их нельзя инициализировать программно заново.ТЗ1 и ТЗ2). Использование одного и того же имени без явного обнуления ссылки на предыдущий объект может привести к перезаписи данных и потере контекста первого выбора.Очистить() удаляет только строки таблицы, но оставляет структуру колонок нетронутой. Если для второго выбора вам требуется другая структура данных (другой набор колонок), это вызовет ошибку заполнения. В таком случае необходимо использовать метод УдалитьКолонки() или полностью переинициализировать объект.Рассмотрим подробнее по шагам, как правильно реализовать эту задачу двумя различными способами.
Самый надежный и понятный способ — создать два отдельных объекта ТаблицаЗначений под разными именами. В этом случае мы гарантируем, что данные первого выбора не будут затерты при подготовке данных для второго выбора.
Для интерактивного выбора строки мы применим стандартный модальный метод ВыбратьСтроку(). Этот метод приостанавливает выполнение программного кода до тех пор, пока пользователь не выберет строку или не закроет окно выбора.
Посмотрим на пример реализации этого алгоритма:
Процедура ВыбратьФизЛиц()
// Шаг 1: Инициализируем и заполняем первую Таблицу Значений
ТЗ1 = СоздатьОбъект("ТаблицаЗначений");
ТЗ1.НоваяКолонка("ФизЛицо", "Справочник.ФизическиеЛица");
ТЗ1.НоваяКолонка("Должность", "Строка");
// Заполняем ТЗ1 данными (например, выборка из справочника)
СпрФиз = СоздатьОбъект("Справочник.ФизическиеЛица");
СпрФиз.ВыбратьЭлементы();
Пока СпрФиз.ПолучитьЭлемент() = 1 Цикл
ТЗ1.НоваяСтрока();
ТЗ1.ФизЛицо = СпрФиз.ТекущийЭлемент();
ТЗ1.Должность = СпрФиз.Должность;
КонецЦикла;
// Шаг 2: Выводим окно выбора для первого физлица
Ном1 = 0;
Если ТЗ1.ВыбратьСтроку(Ном1, "Выберите первое физическое лицо") = 1 Тогда
// Получаем выбранное значение по номеру строки
ВыбранноеФизЛицо1 = ТЗ1.ПолучитьЗначение(Nom1, "ФизЛицо");
// Шаг 3: Инициализируем и заполняем вторую Таблицу Значений
ТЗ2 = СоздатьОбъект("ТаблицаЗначений");
ТЗ2.НоваяКолонка("ФизЛицо", "Справочник.ФизическиеЛица");
ТЗ2.НоваяКолонка("Отдел", "Строка");
// Заполняем ТЗ2 данными (например, только сотрудники определенного отдела)
СпрФиз.ВыбратьЭлементы();
Пока СпрФиз.ПолучитьЭлемент() = 1 Цикл
// Исключим уже выбранное первое физлицо из второго списка
Если СпрФиз.ТекущийЭлемент() = ВыбранноеФизЛицо1 Тогда
Продолжить;
КонецЕсли;
ТЗ2.НоваяСтрока();
ТЗ2.ФизЛицо = СпрФиз.ТекущийЭлемент();
ТЗ2.Отдел = СпрФиз.Подразделение;
КонецЦикла;
// Шаг 4: Выводим окно выбора для второго физлица
Ном2 = 0;
Если ТЗ2.ВыбратьСтроку(Ном2, "Выберите второе физическое лицо") = 1 Тогда
ВыбранноеФизЛицо2 = ТЗ2.ПолучитьЗначение(Nom2, "ФизЛицо");
// Обе переменные успешно определены, переходим к формированию печатной формы
ОткрытьПечатнуюФорму(ВыбранноеФизЛицо1, ВыбранноеФизЛицо2);
Иначе
Предупреждение("Выбор второго физического лица был отменен.");
EndIf;
Иначе
Предупреждение("Выбор первого физического лица был отменен.");
КонецЕсли;
КонецПроцедуры
В данном примере мы видим четкое разделение логики. Второй выбор инициируется только в том случае, если пользователь успешно выполнил первый выбор (метод ВыбратьСтроку() вернул значение 1). Это защищает программу от ошибок, связанных с пустыми значениями переменных.
Если структура колонок для обоих выборов абсолютно одинакова, мы можем сэкономить ресурсы памяти и использовать одну и ту же переменную. Однако в этом случае крайне важно правильно очищать строки таблицы перед повторным заполнением.
Проанализируем пример кода с использованием одной переменной ТЗ:
Процедура ВыбратьФизЛицОднойТаблицей()
// Создаем объект один раз
ТЗ = СоздатьОбъект("ТаблицаЗначений");
ТЗ.НоваяКолонка("ФизЛицо", "Справочник.ФизическиеЛица");
// Заполняем для первого выбора
Спр = СоздатьОбъект("Справочник.ФизическиеЛица");
Спр.ВыбратьЭлементы();
Пока Спр.ПолучитьЭлемент() = 1 Цикл
ТЗ.НоваяСтрока();
ТЗ.ФизЛицо = Спр.ТекущийЭлемент();
КонецЦикла;
Ном = 0;
Если ТЗ.ВыбратьСтроку(Ном, "Выберите первого сотрудника") = 1 Тогда
ВыбранноеФизЛицо1 = ТЗ.ПолучитьЗначение(Ном, "ФизЛицо");
// Важный шаг: очищаем только строки таблицы, колонки остаются нетронутыми
ТЗ.Очистить();
// Заполняем повторно для второго выбора
Спр.ВыбратьЭлементы();
Пока Спр.ПолучитьЭлемент() = 1 Цикл
// Логика исключения дублирования
Если Спр.ТекущийЭлемент() = ВыбранноеФизЛицо1 Тогда
Продолжить;
КонецЕсли;
ТЗ.НоваяСтрока();
ТЗ.ФизЛицо = Спр.ТекущийЭлемент();
КонецЦикла;
Ном = 0; // Сбрасываем индекс выбора строки
Если ТЗ.ВыбратьСтроку(Nom, "Выберите второго сотрудника") = 1 Тогда
ВыбранноеФизЛицо2 = ТЗ.ПолучитьЗначение(Nom, "ФизЛицо");
// Вывод печатной формы
ОткрытьПечатнуюФорму(ВыбранноеФизЛицо1, ВыбранноеФизЛицо2);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Важное примечание: Если бы структура колонок во втором выборе отличалась, нам пришлось бы вызвать метод ТЗ.УдалитьКолонки() перед созданием новых колонок, иначе система выдала бы ошибку о дублировании идентификаторов колонок при вызове метода НоваяКолонка().
Хотя метод ВыбратьСтроку() для объекта ТаблицаЗначений прост в реализации, профессиональные разработчики стараются избегать его использования в пользовательских интерфейсах. Системное окно выбора ТЗ в 1С 7.7 имеет ряд недостатков: оно выглядит устаревшим, не масштабируется должным образом, в нем отсутствует удобный полнотекстовый поиск и сортировка по колонкам.
Рассмотрим две альтернативы, которые сделают работу пользователя гораздо более комфортной:
Если для выбора требуется показать только одно текстовое представление (например, только ФИО сотрудника) и вернуть конкретный элемент справочника, вместо таблицы значений гораздо эффективнее использовать объект СписокЗначений и его метод ВыбратьЗначение(). Окно выбора списка значений выглядит более аккуратно и привычно для пользователя.
СписокВыбора = СоздатьОбъект("СписокЗначений");
// Наполняем список элементами справочника
СписокВыбора.ДобавитьЗначение(ФизЛицоСсылка, ФизЛицоСсылка.Наименование);
ВыбранноеЗначение = "";
Если СписокВыбора.ВыбратьЗначение(ВыбранноеЗначение, "Выберите сотрудника") = 1 Тогда
// В переменной ВыбранноеЗначение находится ссылка на физлицо
КонецЕсли;
Если вам необходим сложный выбор с расширенной фильтрацией, поиском и красивым визуальным оформлением, лучшим решением будет создание отдельной вспомогательной обработки (например, "ВыборИзТаблицы"). Вызов такой формы происходит модально:
// Передаем подготовленную таблицу значений в качестве контекста в форму выбора
ОткрытьФормуМодально("Обработка.ВыборИзТЗ", ТЗ);
Внутри этой обработки вы можете разместить полноценную визуальную таблицу значений на форме, настроить обработку двойного клика мыши по строке и передавать выбранную строку обратно в вызывающую процедуру через параметр закрытия формы.
Мы детально разобрали механизмы последовательной работы с таблицами значений в среде 1С 7.7. Для успешного решения задачи достаточно объявить два отдельных программных объекта с уникальными именами переменных или корректно использовать метод Очистить() при работе с одной таблицей. Выбирайте тот метод, который наилучшим образом отвечает требованиям вашего интерфейса и обеспечивает максимальное удобство для конечного пользователя.