В этой статье мы подробно рассмотрим, как реализовать удобный и интуитивно понятный механизм множественного выбора элементов в стандартных или доработанных формах 1С, исключив при этом необходимость использования клавиш Ctrl и Shift. Вместо стандартного выделения строк мы добавим специальную колонку с флажками, позволяющую пользователям легко отмечать нужные строки одним кликом.
Давайте разберем ситуацию, с которой столкнулся автор темы. В базе 1С:Комплексная автоматизация 2.4 (КА 2.4) имеется доработка, которая открывает форму выбора из реализаций, предоставляя возможность множественного выбора. Однако, стандартный функционал требует зажимания клавиш Ctrl или Shift для выделения нескольких строк, что, как показывает практика, не всегда удобно для пользователей.
Исходный код, который используется для открытия формы выбора реализаций, выглядит следующим образом:
Процедура ПодобратьТоварыПоРеализациям(Команда)
ПараметрыВыбора_Р = Новый Структура("РежимВыбора,МножественныйВыбор,ЗакрыватьПриВыборе", Истина, Истина, Истина);
ОбработкаВыбора = Новый ОписаниеОповещения("ПриЗакрытииФормыВыбораРеализаций", ЭтаФорма);
ОткрытьФорму("Документ.РеализацияТоваровУслуг.ФормаВыбора", ПараметрыВыбора_Р, ЭтаФорма, , , , ОбработкаВыбора);
КонецПроцедуры
Наша главная цель — модифицировать поведение этой формы или создать альтернативную таким образом, чтобы вместо стандартного механизма выделения появилась отдельная колонка, содержащая флажки для каждой строки, что позволит пользователю просто отмечать нужные ему реализации.
Для реализации такого функционала нам потребуется вмешательство в структуру и логику формы выбора. Мы можем выделить два основных подхода к решению этой задачи:
Документ.РеализацияТоваровУслуг.ФормаВыбора) и программно добавляем в нее необходимые элементы и логику. Этот путь может быть более трудоемким и сопряжен с некоторыми сложностями при обновлении конфигурации, но он оправдан, если большая часть функционала стандартной формы нас устраивает, и требуется лишь незначительная доработка механизма выбора.Автор темы склоняется ко второму подходу, используя метод ПолучитьФорму, что позволяет получить объект формы и программно внести в него изменения. Мы подробно рассмотрим именно этот путь, используя механизм расширений или непосредственного изменения формы (для собственной формы).
Первым делом, вместо прямого открытия формы через ОткрытьФорму, нам необходимо получить ее программный объект. Это позволит нам манипулировать ее элементами и реквизитами. Для типовых форм, если мы не хотим создавать свою, будем работать через расширение, добавляя необходимые элементы и логику в расширяемую форму.
Для хранения состояния флажка каждой строки, нам потребуется добавить новый реквизит в форму. Этот реквизит будет иметь тип "Булево" и будет связан с колонкой флажков. Обычно это делается в обработчике ПриСозданииНаСервере для новой формы или формы, которую мы хотим модифицировать через расширение. Если мы модифицируем стандартную форму выбора документа, то добавляем реквизит именно в эту форму (через расширение).
Давайте посмотрим, как можно добавить такой реквизит. Мы будем хранить ссылки на выбранные объекты в реквизите формы типа СписокЗначений, как было предложено в обсуждении на форуме.
// Пример добавления реквизита "ВыбранныеЭлементы" в форму.
// Это можно сделать в модуле формы, например, в обработчике ПриСозданииНаСервере.
// Если работаем через расширение, то добавляем реквизит расширяемой формы.
// Допустим, мы находимся в модуле формы, которую хотим модифицировать.
// Для того чтобы динамически добавлять реквизиты, они должны быть описаны в метаданных
// или быть временными, если добавляются как поля динамического списка.
// Для хранения списка выбранных ссылок, удобно использовать реквизит формы типа СписокЗначений.
// Добавляем реквизит формы, если его еще нет.
// Этот код будет актуален, если мы создаем свою форму или добавляем реквизит через расширение.
// Для стандартных форм, если мы не можем добавить реквизит, придется хранить
// выбранные элементы в отдельной глобальной переменной или передавать через параметры.
// Однако, для корректной работы с формой, реквизит формы предпочтителен.
// В процедуре ПриСозданииНаСервере(Отказ, СтандартнаяОбработка) формы:
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Вызываем стандартный обработчик, если это расширение
СтандартнаяОбработка = Истина;
// Проверяем, существует ли уже реквизит "ВыбранныеЭлементы".
// Если его нет, добавляем его.
Если ЭтаФорма.Реквизиты.Найти("ВыбранныеЭлементы") = Неопределено Тогда
ЭтаФорма.ДобавитьРеквизит("ВыбранныеЭлементы", Новый ОписаниеТипов("СписокЗначений"));
// Инициализируем его пустым списком
ЭтаФорма.ВыбранныеЭлементы = Новый СписокЗначений();
КонецЕсли;
// Если мы передаем уже выбранные элементы для инициализации формы,
// например, из параметров открытия формы, можно заполнить СписокЗначений.
Если Параметры.Свойство("ИсходноВыбранныеЭлементы") Тогда
ЭтаФорма.ВыбранныеЭлементы.ЗагрузитьЗначения(Параметры.ИсходноВыбранныеЭлементы.ВыгрузитьЗначения());
КонецЕсли;
// ... дальнейшая логика добавления элементов управления ...
КонецПроцедуры
В случае с динамическим списком, если вы создаете свою форму или имеете возможность модифицировать запрос, вы можете добавить булево поле прямо в запрос динамического списка. Это значительно упростит привязку колонки-флажка к данным.
// Пример запроса для динамического списка с полем для флажка
ВЫБРАТЬ
РеализацияТоваровУслуг.Ссылка,
РеализацияТоваровУслуг.Дата,
РеализацияТоваровУслуг.Номер,
ЛОЖЬ КАК ПометкаВыбора // Наше булево поле для флажка, изначально false
ИЗ
Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
// ... другие условия и связи ...
После того как мы подготовили реквизит формы для хранения состояния выбора или добавили соответствующее поле в запрос динамического списка, мы можем программно добавить колонку в табличное поле формы.
Добавление элемента формы всегда происходит на стороне сервера, и наиболее подходящим местом для этого является процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка) формы. Давайте разберем шаги:
Список или Таблица.Элементы.Добавить(), указав уникальное имя для новой колонки и тип ПолеФормы.Вид для нового элемента как ВидПоляФормы.ПолеФлажка.Редактировать = Истина, чтобы пользователь мог изменять состояние флажка.ПутьКДанным мы укажем, откуда колонка будет брать и куда записывать свое состояние.
// Продолжение ПриСозданииНаСервере(Отказ, СтандартнаяОбработка) формы:
// Получаем табличное поле, куда хотим добавить колонку.
// Предположим, имя табличного поля, отображающего список документов, "Список".
ЭлементСписка = Элементы.Найти("Список");
Если ЭлементСписка = Неопределено Тогда
// Возможно, имя списка другое или его нет. Необходимо найти корректное имя.
Возврат;
КонецЕсли;
// Создаем новый элемент - поле формы для флажка.
// Расположим его перед первой существующей колонкой для удобства.
НоваяКолонкаФлажок = Элементы.Добавить("КолонкаВыбораРеализаций", Тип("ПолеФормы"), ЭлементСписка, ЭлементСписка.Элементы.Количество());
// Устанавливаем свойства новой колонки.
НоваяКолонкаФлажок.Вид = ВидПоляФормы.ПолеФлажка;
НоваяКолонкаФлажок.Заголовок = ""; // Или "Выбор", "Отметить" и т.д.
НоваяКолонкаФлажок.Ширина = 3; // Оптимальная ширина для флажка
НоваяКолонкаФлажок.Редактировать = Истина; // Флажок должен быть интерактивным
НоваяКолонкаФлажок.Доступность = Истина; // Убедимся, что колонка доступна
НоваяКолонкаФлажок.Видимость = Истина; // Убедимся, что колонка видима
// Связываем колонку с данными.
// Если мы добавили поле "ПометкаВыбора" в запрос динамического списка:
НоваяКолонкаФлажок.ПутьКДанным = "Список.ПометкаВыбора";
// Если мы не можем изменить запрос динамического списка,
// или если это ТаблицаЗначений, привязанная к реквизиту формы,
// и мы хотим управлять состоянием флажка полностью вручную через событие ПриВыводеСтроки,
// то ПутьКДанным может быть пустым или указывать на несуществующее поле.
// В этом случае состояние флажка будет устанавливаться программно.
// Для более надежного управления, рекомендуется все же иметь поле в данных (хоть и временное).
// Если список - ДинамическийСписок, убедимся, что в его запросе есть "ПометкаВыбора"
// и его путь к данным указан верно.
// Если динамический список имеет произвольный запрос, то добавление "ПометкаВыбора" в запрос - оптимальный путь.
// Если список основан на объекте (например, табличная часть объекта), то необходимо добавить
// реквизит в саму табличную часть или использовать внешнее хранение состояния.
// Для динамических списков, когда ПутьКДанным ведет на поле из запроса,
// платформа сама будет управлять состоянием флажка при редактировании пользователем,
// но нам все равно потребуется обрабатывать изменения для синхронизации с ВыбранныеЭлементы.
// Подписываемся на события табличного поля для обработки выбора.
// Для динамического списка с колонкой-флажком, можно использовать событие Выбор.
// или ПриИзменении флажка, если это элемент формы, связанный с данными.
ЭлементСписка.УстановитьДействие("ПриИзменении", "СписокПриИзменении"); // Или "Выбор"
ЭлементСписка.УстановитьДействие("ПриВыводеСтроки", "СписокПриВыводеСтроки");
Это один из самых ответственных и сложных этапов, поскольку именно здесь мы реализуем логику добавления и удаления элементов из списка выбора, а также обеспечиваем корректное отображение состояния флажков.
Как мы уже определили, для хранения ссылок на выбранные объекты мы будем использовать реквизит формы типа СписокЗначений. Каждый элемент этого списка будет содержать ссылку на выбранный документ (в нашем случае, Документ.РеализацияТоваровУслуг). Этот список будет нашим источником истины о том, какие элементы выбраны.
ПриВыводеСтроки)Для корректного отображения состояния флажков при прокрутке списка и инициализации формы, мы обязательно используем обработчик события ПриВыводеСтроки табличного поля. В этом обработчике мы проверяем, содержится ли ссылка на текущий элемент строки в нашем СписокЗначений выбранных элементов. Если да, то программно устанавливаем флажок для соответствующей ячейки; если нет – снимаем его.
// В модуле формы создаем процедуру обработчика события ПриВыводеСтроки:
Процедура СписокПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
// Получаем ссылку на текущий объект из данных строки.
// Для динамического списка это обычно ДанныеСтроки.Ссылка.
// Если это ТаблицаЗначений, то ДанныеСтроки может быть строкой этой таблицы.
Если ДанныеСтроки = Неопределено Тогда
Возврат;
КонецЕсли;
ТекущийОбъектСсылка = Неопределено;
Попытка
ТекущийОбъектСсылка = ДанныеСтроки.Ссылка;
Исключение
// Если поле "Ссылка" отсутствует, возможно это другая структура данных.
// Нужно адаптировать получение ссылки к вашей структуре.
// Например, для ТаблицыЗначений, если колонка со ссылкой называется "Реализация":
// ТекущийОбъектСсылка = ДанныеСтроки.Реализация;
Возврат; // Выходим, если не смогли получить ссылку
КонецПопытки;
// Находим ячейку, соответствующую нашей колонке флажка
Если ОформлениеСтроки.Ячейки.Найти("КолонкаВыбораРеализаций") Тогда
ЯчейкаФлажок = ОформлениеСтроки.Ячейки.КолонкаВыбораРеализаций;
// Проверяем, содержится ли текущий объект в списке выбранных элементов
// Если реквизит формы "ВыбранныеЭлементы" был успешно добавлен
Если ЭтаФорма.ВыбранныеЭлементы.СодержитЗначение(ТекущийОбъектСсылка) Тогда
ЯчейкаФлажок.УстановитьФлажок = Истина;
Иначе
ЯчейкаФлажок.УстановитьФлажок = Ложь;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
ПриИзменении / Выбор)Для обработки действий пользователя с флажком нам потребуется использовать одно из событий табличного поля. Выбор события зависит от того, как связана колонка и как мы хотим обрабатывать изменения:
Список.ПометкаВыбора) или с колонкой таблицы значений, можно использовать событие табличного поля ПриИзменении или ПриИзмененииСтроки. Внутри этого обработчика мы будем добавлять или удалять ссылку на текущий элемент из нашего СписокЗначений.ПолеФлажка), логика выбора может обрабатываться в событии Выбор табличного поля. Мы проверяем, какая именно колонка была нажата.ПередНачаломИзменения табличного поля можно определить, была ли нажата колонка с флажком, и, при необходимости, отменить стандартную обработку (например, чтобы при клике на флажок не открывался документ). После этого, вручную меняем состояние флажка и обновляем СписокЗначений.Рассмотрим пример обработчика события Выбор, так как он часто используется для контроля над поведением при клике на ячейку:
// В модуле формы создаем процедуру обработчика события Выбор для табличного поля:
Процедура СписокВыбор(Элемент, ВыбраннаяСтрока, Поле, СтандартнаяОбработка)
// Отменим стандартную обработку, чтобы клик на флажок не открывал документ
СтандартнаяОбработка = Ложь;
// Проверяем, что нажатие произошло именно на нашу колонку с флажком
Если Поле.Имя = "КолонкаВыбораРеализаций" Тогда
// Получаем текущие данные строки, на которой произошел клик
ТекущиеДанные = Элемент.ТекущиеДанные;
Если ТекущиеДанные = Неопределено Тогда
Возврат;
КонецЕсли;
// Получаем ссылку на объект из текущих данных
ТекущийОбъектСсылка = Неопределено;
Попытка
ТекущийОбъектСсылка = ТекущиеДанные.Ссылка;
Исключение
Возврат; // Выходим, если не удалось получить ссылку
КонецПопытки;
// Определяем текущее состояние флажка, проверяя его наличие в нашем списке
Если ЭтаФорма.ВыбранныеЭлементы.СодержитЗначение(ТекущийОбъектСсылка) Тогда
// Если объект уже выбран, удаляем его из списка
ЭтаФорма.ВыбранныеЭлементы.Удалить(ТекущийОбъектСсылка);
// Если колонка привязана к полю "ПометкаВыбора" в динамическом списке,
// также обновим значение этого поля (необходимо, чтобы изменения были видны сразу)
Если ТекущиеДанные.Свойство("ПометкаВыбора") Тогда
ТекущиеДанные.ПометкаВыбора = Ложь;
КонецЕсли;
Иначе
// Если объект не выбран, добавляем его в список
ЭтаФорма.ВыбранныеЭлементы.Добавить(ТекущийОбъектСсылка);
// Обновляем значение поля "ПометкаВыбора" в динамическом списке
Если ТекущиеДанные.Свойство("ПометкаВыбора") Тогда
ТекущиеДанные.ПометкаВыбора = Истина;
КонецЕсли;
КонецЕсли;
// Обновляем отображение текущей строки, чтобы флажок поменял свое состояние.
// Для динамического списка часто достаточно Элемент.ОбновитьСтроки()
// или Элемент.ОбновитьОтображение().
// Однако, если мы уже модифицировали ТекущиеДанные.ПометкаВыбора,
// платформа может сама обновить визуальное представление.
// Если это не происходит, можно принудительно обновить:
// Элемент.ОбновитьОтображение(); // Обновит только видимые строки
// Или если нужно обновить всю таблицу (может быть медленно для больших списков):
// Элемент.ОбновитьСтроки();
КонецЕсли;
КонецПроцедуры
После того как пользователь завершил выбор и закрыл форму, необходимо передать список выбранных элементов в вызывающую форму. Для этого в 1С используется механизм оповещений.
В исходном коде автора уже используется ОписаниеОповещения("ПриЗакрытииФормыВыбораРеализаций", ЭтаФорма). Это означает, что когда наша форма выбора будет закрыта, будет вызвана процедура ПриЗакрытииФормыВыбораРеализаций в вызывающей форме. Мы должны передать наш СписокЗначений выбранных элементов через параметры закрытия формы.
// В форме выбора, перед ее закрытием (например, в обработчике команды "Выбрать" или "ОК"):
// Передаем наш СписокЗначений через ПараметрыЗакрытия.
// В данном случае, сам реквизит формы "ВыбранныеЭлементы" является СписокЗначений.
Закрыть(ЭтаФорма.ВыбранныеЭлементы);
// Если кнопка "Отмена" или закрытие крестиком, можно передать Неопределено.
// Например:
// Процедура КнопкаОтменаНажатие(Элемент)
// Закрыть(Неопределено);
// КонецПроцедуры
// В вызывающей форме (процедура-обработчик оповещения):
Процедура ПриЗакрытииФормыВыбораРеализаций(ВыбранныеЭлементы, ДополнительныеПараметры) Экспорт
// Проверяем, что нам действительно пришел СписокЗначений
Если ТипЗнч(ВыбранныеЭлементы) = Тип("СписокЗначений") Тогда
Если ВыбранныеЭлементы.Количество() > 0 Тогда
Сообщить("Выбрано " + ВыбранныеЭлементы.Количество() + " реализаций:");
Для Каждого ВыбранныйЭлемент Из ВыбранныеЭлементы Цикл
// Здесь мы можем обработать каждый выбранный элемент,
// например, добавить его в табличную часть или вывести информацию.
Сообщить(" - " + ВыбранныйЭлемент.Значение);
КонецЦикла;
Иначе
Сообщить("Ничего не выбрано.");
КонецЕсли;
Иначе
Сообщить("Выбор отменен или произошла ошибка.");
КонецЕсли;
КонецПроцедуры
При реализации данного функционала необходимо учитывать несколько дополнительных моментов, которые помогут сделать решение более надежным и эффективным:
ЛОЖЬ КАК ПометкаВыбора). Это позволит напрямую связать колонку-флажок с данными списка через свойство ПутьКДанным, что упростит управление состоянием флажка.ПриПолученииДанныхНаСервере: В более новых версиях платформы 1С (начиная с 8.3.10.2168) для динамического списка доступно событие ПриПолученииДанныхНаСервере. Оно предоставляет расширенные возможности для работы с данными, позволяя модифицировать их перед отображением. Вы можете использовать его для инициализации поля ПометкаВыбора на основе ранее сохраненных выбранных элементов, что полезно, если форма открывается с уже предвыбранными значениями.ВидПоляФормы.ПолеФлажка, для создания колонки-флажка используют элемент формы с видом "Поле картинки". В этом случае вы задаете разные картинки для отмеченного и неотмеченного состояния, а логика изменения состояния и добавления/удаления элементов из СписокЗначений обрабатывается в событии Выбор табличного поля. Такой подход дает больше контроля над внешним видом, но требует больше кода для управления.ПриВыводеСтроки и хранения выбранных ссылок в отдельном СписокЗначений как раз решает эту проблему. При каждом отображении строки (в том числе при прокрутке) флажок перерисовывается в соответствии с актуальным состоянием, хранящимся в вашем списке.ЭлементСписка.ПолучитьДанные() или выполняя отдельный запрос) и добавлять их ссылки в ВыбранныеЭлементы, а затем обновлять отображение списка.Реализация множественного выбора с флажками требует внимательной и методичной работы с реквизитами формы, элементами управления и их событиями. Следуя этим подробным шагам и учитывая особенности платформы 1С, вы сможете значительно улучшить удобство использования форм выбора, сделав их более интуитивными и эффективными для конечного пользователя.