Как ограничить выбор элементов справочника в табличной части обработки на обычных формах 1С?

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

При разработке интерфейсов в конфигурациях на 1С:Предприятии 8 (особенно на обычных формах в толстом клиенте) часто возникает задача обеспечения удобного и безошибочного ввода данных для оператора. Типичный сценарий: в табличной части внешней или внутренней обработки пользователю нужно выбрать элемент справочника Номенклатура. При этом доступный для выбора список номенклатуры должен быть строго ограничен элементами, которые привязаны к другому справочнику (например, Номенклатура_Доб), выбранному в соседней колонке той же строки.

В этой статье мы подробно разберем несколько практических способов реализации этой задачи: от простого метода, предложенного разработчиками на форуме, до более сложных, красивых и стандартных механизмов платформы 1С.

Постановка задачи и анализ исходных данных

Рассмотрим исходную структуру метаданных:

  1. Существует стандартный справочник Номенклатура.
  2. В систему добавлен вспомогательный справочник Номенклатура_Доб.
  3. В справочнике Номенклатура_Доб создана табличная часть (назовем ее ДоступнаяНоменклатура) с реквизитом Номенклатура (ссылка на основной справочник). Здесь задается соответствие «один ко многим».
  4. На форме обработки есть табличная часть с колонками Номенклатура_Доб и Номенклатура.

Наша цель — сделать так, чтобы при нажатии на кнопку выбора в колонке Номенклатура пользователь видел не весь огромный массив справочника, а только те позиции, которые прописаны в табличной части выбранного элемента Номенклатура_Доб.

---

Вариант 1. Использование метода ВыбратьСтроку() для Таблицы Значений

Это решение, которое непосредственно обсуждалось на форуме. Суть метода заключается в том, что при начале выбора мы программно считываем данные из табличной части связанного справочника, выгружаем их во временную таблицу значений и выводим эту таблицу пользователю в виде модального окна для выбора строки.

Рассмотрим программную реализацию этого метода по шагам:

  1. Создадим обработчик события НачалоВыбора для колонки «Номенклатура» в нашей табличной части.
  2. Отключим стандартное поведение платформы с помощью флага СтандартнаяОбработка = Ложь.
  3. Прочитаем строки из табличной части выбранного справочника Номенклатура_Доб.
  4. Заполним ими временную Таблицу Значений и вызовем ее метод ВыбратьСтроку().

Посмотрим на пример кода, реализующий этот алгоритм:


Процедура ТабличнаяЧастьНоменклатураНачалоВыбора(Элемент, СтандартнаяОбработка)
    
    // Отменяем стандартное открытие формы выбора справочника
    СтандартнаяОбработка = Ложь;
    
    // Получаем текущую строку табличного поля обработки
    ТекущаяСтрока = Элемент.ТекущиеДанные;
    
    // Проверяем, заполнено ли ключевое поле связи
    Если Не ЗначениеЗаполнено(ТекущаяСтрока.Номенклатура_Доб) Тогда
        Предупреждение("Сначала необходимо выбрать значение в колонке 'Номенклатура_Доб'!");
        Возврат;
    КонецЕсли;
    
    // Создаем временную таблицу значений для вывода пользователю
    ТЗДляВыбора = Новый ТаблицаЗначений;
    ТЗДляВыбора.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"), "Выберите номенклатуру");
    
    // Заполняем ТЗ данными из подчиненной табличной части справочника Номенклатура_Доб
    Для Каждого СтрокаТЧ Из ТекущаяСтрока.Номенклатура_Доб.ДоступнаяНоменклатура Цикл
        НоваяСтрокаТЗ = ТЗДляВыбора.Добавить();
        НоваяСтрокаТЗ.Номенклатура = СтрокаТЧ.Номенклатура;
    КонецЦикла;
    
    // Открываем модальное окно выбора строки из созданной ТЗ
    ВыбраннаяСтрокаТЗ = ТЗДляВыбора.ВыбратьСтроку("Доступные варианты для выбора:");
    
    // Если пользователь сделал выбор, записываем значение в ячейку
    Если ВыбраннаяСтрокаТЗ <> Неопределено Тогда
        ТекущаяСтрока.Номенклатура = ВыбраннаяСтрокаТЗ.Номенклатура;
    КонецЕсли;

КонецПроцедуры

Преимущества метода: крайне простая реализация, код пишется буквально за 5 минут, работает безотказно.

Недостатки метода: интерфейс выглядит устаревшим. Открывается полноценное отдельное модальное окно со стандартной таблицей значений, которое перекрывает рабочую область. Как справедливо заметил автор темы на форуме, это выглядит «не кузяво».

---

Вариант 2. Всплывающее меню через ВыбратьИзСписка()

Более элегантный и визуально привлекательный способ для обычных форм — использование метода ВыбратьИзСписка(). Вместо открытия тяжелого модального окна система выведет компактный выпадающий список прямо под ячейкой, в которой пользователь нажал кнопку выбора.

Проанализируем ситуацию реализации данного подхода:


Процедура ТабличнаяЧастьНоменклатураНачалоВыбора(Элемент, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь;
    ТекущаяСтрока = Элемент.ТекущиеДанные;
    
    Если Не ЗначениеЗаполнено(ТекущаяСтрока.Номенклатура_Доб) Тогда
        Предупреждение("Пожалуйста, сначала выберите Номенклатуру_Доб!");
        Возврат;
    КонецЕсли;
    
    // Формируем аккуратный список значений
    СписокВыбора = Новый СписокЗначений;
    
    Для Каждого СтрокаТЧ Из ТекущаяСтрока.Номенклатура_Доб.ДоступнаяНоменклатура Цикл
        // Добавляем элемент справочника в список для интерактивного выбора
        СписокВыбора.Добавить(СтрокаТЧ.Номенклатура);
    КонецЦикла;
    
    // Проверяем, есть ли вообще данные для выбора
    Если СписокВыбора.Количество() = 0 Тогда
        Предупреждение("Для выбранной Номенклатуры_Доб не сопоставлено ни одного значения Номенклатуры!");
        Возврат;
    КонецЕсли;
    
    // Показываем компактное контекстное меню выбора у элемента формы (ячейки)
    ВыбранныйЭлементСписка = ВыбратьИзСписка(СписокВыбора, Элемент);
    
    Если ВыбранныйЭлементСписка <> Неопределено Тогда
        ТекущаяСтрока.Номенклатура = ВыбранныйЭлементСписка.Значение;
    КонецЕсли;

КонецПроцедуры

Преимущества метода: современный интерфейс без лишних окон. Идеально подходит, если количество сопоставленных элементов невелико (до 15-20 позиций).

Недостатки метода: в выпадающем списке отсутствует стандартный функционал поиска по строке, иерархия групп и возможность просмотра детальных реквизитов справочника.

---

Вариант 3. Программный отбор «В Списке» в стандартной форме выбора справочника

Если сопоставленных элементов в табличной части справочника Номенклатура_Доб может быть много (десятки или сотни), оператору обязательно понадобится полноценная форма выбора с поиском, группировкой по папкам и сортировкой. В этом случае правильным решением будет открыть стандартную форму выбора справочника Номенклатура, предварительно наложив жесткий программный фильтр.

Разберем этот метод подробно по шагам:

  1. Перехватываем событие НачалоВыбора и отключаем стандартное открытие формы.
  2. Собираем все доступные ссылки на номенклатуру из табличной части связанного объекта в массив или СписокЗначений.
  3. Программным образом получаем форму выбора справочника с помощью метода ПолучитьФормуВыбора(). При этом крайне важно передать текущий элемент управления в качестве владельца формы. Это позволит платформе автоматически вернуть выбранное значение в нужную ячейку табличного поля без написания дополнительного кода в событии ОбработкаВыбора.
  4. Находим в форме выбора отбор по ссылке и устанавливаем вид сравнения ВСписке.
  5. Открываем настроенную форму.

Посмотрим на пример кода:


Процедура ТабличнаяЧастьНоменклатураНачалоВыбора(Элемент, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь;
    ТекущаяСтрока = Элемент.ТекущиеДанные;
    
    Если Не ЗначениеЗаполнено(ТекущаяСтрока.Номенклатура_Доб) Тогда
        Предупреждение("Сначала заполните поле Номенклатура_Доб!");
        Возврат;
    КонецЕсли;
    
    // Заполняем массив разрешенных элементов
    МассивРазрешенных = Новый Массив;
    Для Каждого СтрокаТЧ Из ТекущаяСтрока.Номенклатура_Доб.ДоступнаяНоменклатура Цикл
        МассивРазрешенных.Добавить(СтрокаТЧ.Номенклатура);
    КонецЦикла;
    
    // Получаем стандартную форму выбора справочника. 
    // Передаем параметр 'Элемент' в качестве владельца формы для автоматического возврата значения.
    ФормаВыбора = Справочники.Номенклатура.ПолучитьФормуВыбора("ФормаВыбора", Элемент);
    
    // Настраиваем жесткий отбор по списку ссылок
    ОтборСсылка = ФормаВыбора.СправочникСписок.Отбор.Ссылка;
    ОтборСсылка.ВидСравнения = ВидСравнения.ВСписке;
    ОтборСсылка.Значение = Новый СписокЗначений;
    ОтборСсылка.Значение.ЗагрузитьЗначения(МассивРазрешенных);
    ОтборСсылка.Использование = Истина;
    
    // Для удобства пользователя можно отключить иерархический просмотр,
    // чтобы сразу отображался плоский список доступных позиций
    ФормаВыбора.ЭлементыФормы.СправочникСписок.ИерархическийПросмотр = Ложь;
    
    // Открываем подготовленную форму выбора
    ФормаВыбора.Открыть();

КонецПроцедуры

Преимущества метода: наиболее профессиональное и стандартное решение для обычных форм. Пользователь работает в привычной среде поиска и выбора справочника, но видит только разрешенные записи.

---

Вариант 4. Ограничение через свойство ячейки «ДоступныеЗначения»

Малоизвестный, но крайне мощный стандартный механизм обычных форм 1С — это использование свойства ячейки табличного поля ДоступныеЗначения. Если у конкретной ячейки установлено это свойство, платформа автоматически ограничивает интерактивный выбор пользователя (как при вводе текста, так и при нажатии на кнопку выбора) данным списком.

При таком подходе логику ограничения следует перенести в событие изменения первой колонки (Номенклатура_Доб):


Процедура ТабличнаяЧастьНоменклатураДобПриИзменении(Элемент)
    
    СтрокаТП = ЭлементыФормы.ТабличнаяЧасть.ТекущаяСтрока;
    
    // Если поле очистили, сбрасываем ограничения
    Если Не ЗначениеЗаполнено(СтрокаТП.Номенклатура_Доб) Тогда
        ЭлементыФормы.ТабличнаяЧасть.Колонки.Номенклатура.ЭлементУправления.ДоступныеЗначения = Неопределено;
        Возврат;
    КонецЕсли;
    
    // Заполняем список доступных значений
    СписокДоступных = Новый СписокЗначений;
    Для Каждого СтрокаТЧ Из СтрокаТП.Номенклатура_Доб.ДоступнаяНоменклатура Цикл
        СписокДоступных.Добавить(СтрокаТЧ.Номенклатура);
    КонецЦикла;
    
    // Накладываем ограничение непосредственно на элемент управления в текущей строке
    // Обратите внимание: для динамического изменения в табличном поле 
    // лучше использовать событие ПриВыводеСтроки или ПриАктивизацииСтроки
    ЭлементыФормы.ТабличнаяЧасть.Колонки.Номенклатура.ЭлементУправления.ДоступныеЗначения = СписокДоступных;

КонецПроцедуры

Преимущества метода: работает на уровне платформы. Не нужно переопределять событие НачалоВыбора и прописывать логику открытия форм вручную.

---

Резюме

Мы подробно проанализировали четыре способа решения задачи ограничения выбора в табличном поле на обычных формах 1С 8.3:

← На главную