Список значений 1С (тип СписокЗначений) — коллекция, в которой у каждого значения может быть своё представление, флажок и картинка. Встречается он постоянно: список выбора у поля формы, параметр отчёта на СКД с флажком «Доступен список значений», отбор «В списке», перечень складов с галочками в обработке, набор ссылок для параметра запроса. Ниже — как работать со списком значений программно в платформе 8.3: добавить и вставить элемент, получить значение, найти, отсортировать, вывести в управляемую форму и когда вместо него лучше взять массив.
Список хранит упорядоченный набор объектов ЭлементСпискаЗначений. Индексы начинаются с нуля, значения могут быть любого типа, в одном списке допустимы значения разных типов. Повторы платформа не запрещает — за уникальностью следите сами.
Каждый элемент списка значений 1С имеет четыре свойства:
| Свойство | Тип | Зачем нужно |
|---|---|---|
Значение | Произвольный | Сами данные: ссылка, число, строка, дата |
Представление | Строка | Текст, который видит пользователь. Если не задано, форма показывает стандартное представление значения |
Пометка | Булево | Флажок в таблице формы и в окне отметки элементов |
Картинка | Картинка | Значок рядом с текстом, обычно общая картинка из БиблиотекаКартинок |
Ещё у элемента есть метод ПолучитьИдентификатор(): он возвращает числовой идентификатор, по которому таблица формы ссылается на строку. У самого списка пригодятся свойства ТипЗначения (описание типов значений элементов, нужно, когда список редактирует пользователь) и ДоступныеЗначения (набор, из которого пользователь выбирает значения при редактировании).
Список значений доступен и на клиенте, и на сервере, его можно передать параметром в серверную процедуру и вернуть обратно. В этом его преимущество перед таблицей значений, которой на тонком клиенте нет.
Список создаётся конструктором Новый СписокЗначений. Чтобы добавить значение в список значений, вызовите Добавить(Значение, Представление, Пометка, Картинка). Обычно передают значение и представление, пометку и картинку — по необходимости. Метод возвращает созданный элемент, и его свойства можно дозаполнить сразу. Вставить делает то же самое, но первым параметром принимает индекс позиции.
Статусы = Новый СписокЗначений;
Статусы.Добавить("NEW", "Новая");
Статусы.Добавить("WORK", "В работе");
// Добавить возвращает элемент - дозаполняем его сразу
Элемент = Статусы.Добавить("DONE", "Выполнена");
Элемент.Пометка = Истина;
// Вставка в начало списка: индекс 0
Статусы.Вставить(0, "DRAFT", "Черновик");
// Значение, Представление, Пометка
Статусы.Добавить("CANCEL", "Отменена", Ложь);
// Порядок в списке: DRAFT, NEW, WORK, DONE, CANCEL
На практике заполнить список значений в 1С чаще всего нужно из запроса. Пример для формы обработки с реквизитом СписокСкладов типа СписокЗначений. Справочник Склады есть в УТ 11, КА 2, ERP 2 и БП 3.0; в другой конфигурации подставьте свой.
&НаСервере
Процедура ЗаполнитьСклады()
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Склады.Ссылка КАК Ссылка,
| Склады.Наименование КАК Наименование
|ИЗ
| Справочник.Склады КАК Склады
|ГДЕ
| НЕ Склады.ПометкаУдаления
|
|УПОРЯДОЧИТЬ ПО
| Наименование";
СписокСкладов.Очистить();
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
СписокСкладов.Добавить(Выборка.Ссылка, Выборка.Наименование);
КонецЦикла;
КонецПроцедуры
&НаСервере
Процедура ЗаполнитьСкладыИзМассива()
Запрос = Новый Запрос(
"ВЫБРАТЬ
| Склады.Ссылка КАК Ссылка
|ИЗ
| Справочник.Склады КАК Склады");
// ЗагрузитьЗначения сначала очищает список, потом добавляет элементы
МассивСсылок = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
СписокСкладов.ЗагрузитьЗначения(МассивСсылок);
КонецПроцедуры
Второй вариант короче, но представления элементов остаются пустыми — форма покажет стандартное представление ссылки, а в коде Элемент.Представление вернёт пустую строку.
К элементу обращаются по индексу через квадратные скобки или методом Получить(Индекс). Оба варианта возвращают ЭлементСпискаЗначений, а не данные. Чтобы получить значение списка значений, дописывайте .Значение. На этом спотыкаются чаще всего: сравнивают элемент со ссылкой, и условие никогда не выполняется.
ПервыйЭлемент = Статусы[0]; // ЭлементСпискаЗначений
ПервыйКод = Статусы[0].Значение; // "DRAFT"
ВтороеИмя = Статусы.Получить(1).Представление; // "Новая"
Для Каждого Элемент Из Статусы Цикл
Если Элемент.Пометка Тогда
Сообщить("Отмечен статус: " + Элемент.Представление);
КонецЕсли;
КонецЦикла;
Если Статусы.Количество() > 0 Тогда
Последний = Статусы[Статусы.Количество() - 1];
КонецЕсли;
Количество() возвращает число элементов, Индекс(Элемент) — позицию элемента в списке. Перед обращением к последнему элементу проверяйте, что список не пуст.
НайтиПоЗначению возвращает первый элемент с таким значением или Неопределено. Сравнение точное, с учётом типа: строку «1» по числу 1 не найти, ссылку по наименованию — тоже.
Элемент = Статусы.НайтиПоЗначению("WORK");
Если Элемент = Неопределено Тогда
Сообщить("Статус WORK в списке не найден");
Иначе
Элемент.Пометка = Истина;
Позиция = Статусы.Индекс(Элемент); // 2
КонецЕсли;
НайтиПоИдентификатору нужен в формах. Таблица, связанная с реквизитом-списком, хранит в свойствах ТекущаяСтрока и ВыделенныеСтроки не элементы и не индексы, а идентификаторы. По ним и ищем элемент. Чтобы пользователь мог выделить несколько строк сразу, у таблицы установите свойство РежимВыделения в значение «Множественный».
&НаКлиенте
Процедура ОткрытьТекущийСклад(Команда)
Идентификатор = Элементы.СписокСкладов.ТекущаяСтрока;
Если Идентификатор = Неопределено Тогда
Возврат;
КонецЕсли;
Элемент = СписокСкладов.НайтиПоИдентификатору(Идентификатор);
Если Элемент <> Неопределено Тогда
ПоказатьЗначение(, Элемент.Значение);
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ОтметитьВыделенные(Команда)
Для Каждого Идентификатор Из Элементы.СписокСкладов.ВыделенныеСтроки Цикл
Элемент = СписокСкладов.НайтиПоИдентификатору(Идентификатор);
Если Элемент <> Неопределено Тогда
Элемент.Пометка = Истина;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Индекс элемента после сортировки или удаления соседей меняется, а идентификатор остаётся прежним. Поэтому в обработчиках формы опирайтесь на идентификатор.
Методов сортировки два: СортироватьПоЗначению и СортироватьПоПредставлению, оба принимают необязательное НаправлениеСортировки (по умолчанию — по возрастанию). Сдвинуть(Элемент, Смещение) перемещает элемент: отрицательное смещение — вверх, положительное — вниз. Удалить принимает элемент или индекс.
Статусы.СортироватьПоПредставлению(); // по алфавиту
Статусы.СортироватьПоЗначению(НаправлениеСортировки.Убыв); // по значению, по убыванию
Элемент = Статусы.НайтиПоЗначению("DONE");
Если Элемент <> Неопределено Тогда
Статусы.Сдвинуть(Элемент, -1); // на одну позицию вверх
КонецЕсли;
Отмена = Статусы.НайтиПоЗначению("CANCEL");
Если Отмена <> Неопределено Тогда
Статусы.Удалить(Отмена); // удаление по элементу
КонецЕсли;
Если Статусы.Количество() > 0 Тогда
Статусы.Удалить(0); // удаление по индексу
КонецЕсли;
Копия = Статусы.Скопировать(); // независимая копия
Статусы.Очистить();
Для строк, чисел и дат сортировка по значению даёт ожидаемый порядок. Список ссылок по алфавиту надёжнее сортировать по представлению — при условии, что оно заполнено. Сортировки по двум признакам сразу у списка нет: для этого берите таблицу значений.
Реквизит формы типа СписокЗначений в дереве реквизитов раскрывается на поля Значение, Представление, Пометка и Картинка. Выведите реквизит на форму таблицей и добавьте колонку Пометка — у пользователя появятся флажки. Методы списка работают на клиенте, поэтому команды «Отметить все» и «Снять отметки» обходятся без серверного вызова.
Второй частый случай — список выбора у поля ввода. Элементы.ИмяПоля.СписокВыбора — тоже список значений, заполняется теми же методами. Свойство РежимВыбораИзСписка запрещает вводить значения не из списка.
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
ЗаполнитьСклады(); // процедура из примера выше, в том же модуле формы
// Приоритет - реквизит формы типа Число
СписокВыбора = Элементы.Приоритет.СписокВыбора;
СписокВыбора.Очистить();
СписокВыбора.Добавить(1, "Низкий");
СписокВыбора.Добавить(2, "Обычный");
СписокВыбора.Добавить(3, "Срочный");
Элементы.Приоритет.РежимВыбораИзСписка = Истина;
КонецПроцедуры
&НаКлиенте
Процедура ОтметитьВсе(Команда)
СписокСкладов.ЗаполнитьПометки(Истина);
КонецПроцедуры
&НаКлиенте
Процедура СнятьОтметки(Команда)
СписокСкладов.ЗаполнитьПометки(Ложь);
КонецПроцедуры
Выбрать один элемент в отдельном окне можно вообще без своей формы. В конфигурациях без модальных окон используйте ПоказатьВыборЭлемента, а для отметки нескольких элементов — ПоказатьОтметкуЭлементов. Старые ВыбратьЭлемент и ОтметитьЭлементы модальные. Ниже — выбор основного склада и передача отмеченных складов на сервер. Функция ОтмеченныеЗначения взята из общего модуля — он приведён ниже, в разделе про модуль-помощник.
&НаКлиенте
Процедура ВыбратьОсновнойСклад(Команда)
Оповещение = Новый ОписаниеОповещения("ВыбратьОсновнойСкладЗавершение", ЭтотОбъект);
СписокСкладов.ПоказатьВыборЭлемента(Оповещение, "Основной склад");
КонецПроцедуры
&НаКлиенте
Процедура ВыбратьОсновнойСкладЗавершение(ВыбранныйЭлемент, ДополнительныеПараметры) Экспорт
Если ВыбранныйЭлемент = Неопределено Тогда
Возврат; // окно закрыли без выбора
КонецЕсли;
ОсновнойСклад = ВыбранныйЭлемент.Значение; // реквизит формы
КонецПроцедуры
&НаКлиенте
Процедура Сформировать(Команда)
Склады = СпискиЗначенийКлиентСервер.ОтмеченныеЗначения(СписокСкладов);
Если Склады.Количество() = 0 Тогда
ПоказатьПредупреждение(, "Отметьте хотя бы один склад");
Возврат;
КонецЕсли;
СформироватьНаСервере(Склады);
КонецПроцедуры
&НаСервере
Процедура СформироватьНаСервере(Склады)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Склады.Ссылка КАК Склад,
| Склады.Наименование КАК Наименование
|ИЗ
| Справочник.Склады КАК Склады
|ГДЕ
| Склады.Ссылка В (&ВыбранныеСклады)";
// Параметр принимает и массив, и список значений,
// но список уйдёт целиком - вместе с неотмеченными элементами
Запрос.УстановитьПараметр("ВыбранныеСклады", Склады);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
// обработка выбранного склада
КонецЦикла;
КонецПроцедуры
Оба типа хранят упорядоченный набор значений, но задачи у них разные. Подробно про массив — в статье «Массив 1С: создание, добавление, получение по индексу».
| Массив | СписокЗначений | |
|---|---|---|
| Что хранит | Только значения | Элементы: значение, представление, пометка, картинка |
| Поиск | Найти — индекс или Неопределено | НайтиПоЗначению — элемент или Неопределено |
| Сортировка | Нет | По значению и по представлению |
| Показ пользователю | Своего вывода в форму нет | Таблица с флажками, список выбора, окно выбора |
Параметр запроса В (&Параметр) | Да | Да |
| Преобразование | В список: Список.ЗагрузитьЗначения(Массив) | В массив: Список.ВыгрузитьЗначения() |
Правило простое: если данные нужны только коду — берите массив, он легче. Если набор увидит пользователь (подписи, флажки, выбор) или нужна сортировка — список значений.
Функции ниже повторяются почти в каждой обработке, поэтому их удобно держать в общем модуле с флажками «Клиент (управляемое приложение)» и «Сервер». Тогда они вызываются из любого контекста, а на клиенте выполняются без обращения к серверу.
// Общий модуль СпискиЗначенийКлиентСервер.
// Флажки модуля: Клиент (управляемое приложение), Сервер.
// Платформа 8.3.6 и выше (используются СтрРазделить и СтрНайти).
// Возвращает массив значений отмеченных элементов списка.
Функция ОтмеченныеЗначения(Список) Экспорт
Результат = Новый Массив;
Для Каждого Элемент Из Список Цикл
Если Элемент.Пометка Тогда
Результат.Добавить(Элемент.Значение);
КонецЕсли;
КонецЦикла;
Возврат Результат;
КонецФункции
// Добавляет значение, только если его ещё нет в списке.
// Возвращает новый или уже существующий элемент.
Функция ДобавитьБезПовтора(Список, Значение, Представление = "") Экспорт
Элемент = Список.НайтиПоЗначению(Значение);
Если Элемент = Неопределено Тогда
Элемент = Список.Добавить(Значение, Представление);
КонецЕсли;
Возврат Элемент;
КонецФункции
// Возвращает представление элемента с указанным значением.
// Если элемента нет или представление не заполнено,
// возвращает строковое представление самого значения.
Функция ПредставлениеЗначения(Список, Значение) Экспорт
Элемент = Список.НайтиПоЗначению(Значение);
Если Элемент <> Неопределено Тогда
Если Не ПустаяСтрока(Элемент.Представление) Тогда
Возврат Элемент.Представление;
КонецЕсли;
КонецЕсли;
Возврат Строка(Значение);
КонецФункции
// Удаляет неотмеченные элементы. Обход идёт с конца,
// чтобы удаление не сдвигало ещё не проверенные элементы.
Процедура УдалитьНеотмеченные(Список) Экспорт
Индекс = Список.Количество() - 1;
Пока Индекс >= 0 Цикл
Если Не Список[Индекс].Пометка Тогда
Список.Удалить(Индекс);
КонецЕсли;
Индекс = Индекс - 1;
КонецЦикла;
КонецПроцедуры
// Возвращает новый отсортированный массив, исходный не меняется.
// У массива нет своей сортировки, поэтому сортируем через список.
Функция ОтсортированныйМассив(Массив, ПоУбыванию = Ложь) Экспорт
Список = Новый СписокЗначений;
Список.ЗагрузитьЗначения(Массив);
Если ПоУбыванию Тогда
Список.СортироватьПоЗначению(НаправлениеСортировки.Убыв);
Иначе
Список.СортироватьПоЗначению(НаправлениеСортировки.Возр);
КонецЕсли;
Возврат Список.ВыгрузитьЗначения();
КонецФункции
// Заполняет список из строки вида "NEW=Новая;WORK=В работе;DONE".
// Часть до "=" становится значением, после "=" - представлением.
Процедура ЗаполнитьИзСтроки(Список, СтрокаНастройки) Экспорт
Список.Очистить();
Для Каждого Пара Из СтрРазделить(СтрокаНастройки, ";", Ложь) Цикл
Позиция = СтрНайти(Пара, "=");
Если Позиция = 0 Тогда
Список.Добавить(СокрЛП(Пара));
Иначе
Список.Добавить(СокрЛП(Лев(Пара, Позиция - 1)), СокрЛП(Сред(Пара, Позиция + 1)));
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Что здесь важно:
ОтмеченныеЗначения возвращает массив: в запрос и в отбор СКД нужно передавать именно отмеченные значения, а не весь список с галочками.ДобавитьБезПовтора сначала ищет значение — сам список повторы не отсекает.УдалитьНеотмеченные идёт с конца: после удаления индексы следующих элементов сдвигаются, и прямой обход пропускал бы соседей.ОтсортированныйМассив — стандартный приём: у массива нет метода сортировки, а у списка есть. Загрузили, отсортировали, выгрузили.ЗаполнитьИзСтроки использует СтрРазделить и СтрНайти, они есть с версии 8.3.6. На более старом релизе разбирайте строку через Найти и Сред.Для Индекс = 0 По Список.Количество() без - 1 или обращение к Список[0] в пустом списке.НайтиПоЗначению вернул Неопределено, а код сразу обратился к .Значение или .Пометка. Результат поиска проверяйте всегда.ВыбратьЭлемент или ОтметитьЭлементы в конфигурации с режимом модальности «Не использовать». Замените их на ПоказатьВыборЭлемента и ПоказатьОтметкуЭлементов.В (&Склады) пометки не учитывает. Передавайте массив отмеченных значений.Список2 = Список1 не копирует данные, а даёт вторую ссылку на тот же объект. Независимая копия — Список1.Скопировать().Для Каждого. После удаления элемента обход сбивается, и часть элементов остаётся непроверенной. Удаляйте в цикле по индексу от конца к началу.Элемент.Представление вернёт пустую строку. Для текста используйте Строка(Элемент.Значение) или заполняйте представление явно.Методом ВыгрузитьЗначения() — он вернёт массив значений без представлений и пометок. Обратное преобразование — ЗагрузитьЗначения(Массив), но помните, что он сначала очищает список.
Установите вид сравнения ВидСравненияКомпоновкиДанных.ВСписке и присвойте список свойству ПравоеЗначение элемента отбора. Для параметра схемы с флажком «Доступен список значений» передайте список в УстановитьЗначениеПараметра у параметров данных настроек.
Да, список передаётся параметром серверной процедуры и возвращается из функции. Но при каждом вызове он передаётся целиком, поэтому большие списки лучше не гонять туда-обратно, а отдавать на сервер только нужные значения.
НайтиПоЗначению перед каждым добавлением подходит для десятков и сотен элементов. Для тысяч держите рядом соответствие с теми же значениями в качестве ключей и проверяйте наличие ключа в нём.
Список так не умеет. Выгрузите данные в таблицу значений с двумя колонками и вызовите Сортировать("Поле1, Поле2 Убыв").
Сам список значений — это несколько строк кода. Время уходит на то, что вокруг него: форму подбора с флажками по складам и контрагентам, отчёт на СКД с параметрами-списками, встраивание отбора в типовую конфигурацию через расширение. Такие доработки входят в услугу разработка отчётов и обработок 1С; опишите, что пользователь должен выбирать и что происходит после выбора, и разместите задание на 1c-only.ru — оценка бесплатная, ответ в течение рабочего дня.
Станьте частью сообщества!
Войдите или зарегистрируйтесь, и вы сможете участвовать в обсуждениях.