Описание проблемы и предпосылки
Периодически приходится решать задачи удобного ввода информации пользователем по образу Excel, например, самый простой "План продаж" по месяцам, в котором горизонтально по колонкам расположены месяцы, а вертикально - некая аналитика. Раньше в типовых конфигурациях 1С данная задача не была решена вообще никак. Пользователю предлагалось заполнить обычную табличную часть вручную, добавляя строки и заполняя их датами и необходимой аналитикой. Весь ужас такого ввода объяснять не нужно. Потом разработчики отраслевых решений в "доэскадэшную" эпоху догадались использовать всю мощь макета табличного документа и в "Подрядчик строительства" от "Импульс ИВЦ" уже можно было наблюдать весьма недурное решение в блоке Бюджетирование. Но код был неуниверсальный, сложный и крайне тяжело переносился на другие похожие задачи. В данной статье я постараюсь показать, как решить эту задачу быстро, красиво и с минимальными затратами по времени. Также код, который вы напишете, используя этот пример, вы сможете легко переносить на другие свои решения.
Реализация задачи
Описана для обычных форм, но обработка содержит и УФ без использования модальности.
Нам понадобится: сам объект редактирования (в данном случае табличная часть), макет СКД, компоновщик настроек компоновки данных, элемент управления "поле табличного документа", обработчик "Обработка расшифровки".
Макет СКД представляет собой соединение двух наборов данных, каждый из которых имеет тип "Набор данных - объект":
Настройки вывода просты и примитивны - это обычная таблица с итогами:
В форме необходимо разместить следующие реквизиты:
Основная идея:
В обработчике расшифровки должен быть размещен отказ от стандартной обработки, а также описание набора действий, которые необходимо совершить, когда пользователь кликает по ячейке двойным кликом.
Данный код позволяет определить по какой именно ячейке кликнул пользователь. Далее, зная значение Номенклатуры и Периода можно найти соответствующую строку в табличной части и присвоить в ней реквизиту "Сумма" нужное значение, после можно программно нажать на кнопку "Обновить".
СтандартнаяОбработка = Ложь;
ОбработкаРасшифровки = Новый ОбработкаРасшифровкиКомпоновкиДанных(ДанныеРасшифровки, Новый ИсточникДоступныхНастроекКомпоновкиДанных(СхемаСКД));
СтруктураРасшифровки = Новый Структура("Номенклатура, Период");
НастройкиКомпоновкиДанных = ОбработкаРасшифровки.Расшифровать(Расшифровка, Новый ПолеКомпоновкиДанных("Номенклатура"));
ЭлементыОтбора = НастройкиКомпоновкиДанных.Отбор.Элементы;
Для Каждого ЭлементОтбора Из ЭлементыОтбора Цикл
Если ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Номенклатура") Тогда
СтруктураРасшифровки.Номенклатура = ЭлементОтбора.ПравоеЗначение;
КонецЕсли;
Если ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Период") Тогда
СтруктураРасшифровки.Период = ЭлементОтбора.ПравоеЗначение;
КонецЕсли;
КонецЦикла;
Производительность
Существует 2 способа непосредственного ввода значения при двойном клике по ячейки:
1) Через диалоговое окно методами ВвестиЗначение() или ВвестиЧисло()
- этот способ применен в данном примере.
Преимущества: не усложняет код, высокая производительность.
Недостатки: вылетает дополнительное окно ввода.
При таком способе ввода в каждой ячейке, как и при формировании обычного отчета на СКД, содержится лишь некий объект типа "ИдентификаторРасшифровкиКомпоновкиДанных", который по сути представляет собой число.
2) Непосредственно в ячейку, как в Excel.
Данный способ с применением СКД можно увидеть в ERP 2.0.
Преимущества: очень красиво, у неискушенных вызывает мгновенный вау-эффект, окон не вылетает.
Недостатки: низкая производительность, усложняет код. Нужно понимать, что при таком способе ввода в каждую ячейку придется помещать элемент управления "Поле ввода". Ячеек в поле табличного документа может быть несколько тысяч, т.е. несколько тысяч полей ввода. Вывод этого всего в поле табличного документа не будет быстрым даже в толстом клиенте.
Особенности работы в тонком клиенте без использования режима модальности.
Для работы в тонком клиенте необходимо помещать схему СКД и Данные расшифровки во временное хранилище. Хранить полученные адреса удобно в реквизитах формы.
Записываем адреса хранилищ в обработчике ПриСозданииНаСервере()
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
//Фрагмент обработчика
АдреcМакетСКД = ПоместитьВоВременноеХранилище(РеквизитФормыВЗначение("Объект").ПолучитьМакет("Макет"), УникальныйИдентификатор);;
ДанныеРасшифровки = Неопределено;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаСКД, КомпоновщикНастроек.Настройки, ДанныеРасшифровки, , Тип("ГенераторМакетаКомпоновкиДанных"));
ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновки, ВнешнийНаборДанных, ДанныеРасшифровки);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ПолеТабличногоДокументаПредставление);
ПроцессорВывода.Вывести(ПроцессорКомпоновкиДанных);
АдресДанныеРасшифровки = ПоместитьВоВременноеХранилище(ДанныеРасшифровки, Новый УникальныйИдентификатор);
КонецПроцедуры
Обработчики событий Поля табличного документа и асинхронные вызовы
Обратите внимание, что во все конструкторы объектов СКД передаются сохраненные адреса АдресДанныеРасшифровки, АдреcМакетСКД. И почти все процедуры работают на клиенте. Но к сожалению не только лишь все могут работать на клиенте на клиенте реализованы не все объекты СКД. Иногда придется нырнуть на сервер, например для работы с объектом типа ДанныеРасшифровкиКомпоновкиДанных.
Обработчик ПолеТабличногоДокументаПредставлениеПриАктивизацииОбласти необходим для того, чтобы редактировать число(показатель) можно было непосредственно в ячейке, без использования дополнительных диалоговых окон.
&НаКлиенте
Процедура ПолеТабличногоДокументаПредставлениеОбработкаРасшифровки(Элемент, Расшифровка, СтандартнаяОбработка)
//Фрагмент обработчика
ОбработкаРасшифровки = Новый ОбработкаРасшифровкиКомпоновкиДанных(АдресДанныеРасшифровки, Новый ИсточникДоступныхНастроекКомпоновкиДанных(АдреcМакетСКД));
ПредметРедактирования = ПолучитьИмяТекущегоПоляРедактирования(Расшифровка, АдресДанныеРасшифровки); //ПолучитьПредметРедактирования
ОбработкаРасшифровки.ПоказатьВыборДействия(
Новый ОписаниеОповещения("ОбработкаРасшифровкиПоказатьВыборДействияЗавершение", ЭтотОбъект, ДополнительныеПараметры),
Расшифровка,
ДоступныеДействия,
ДополнительныеПунктыМеню,,);
КонецПроцедуры
&НаКлиенте
Процедура ПолеТабличногоДокументаПредставлениеПриИзмененииСодержимогоОбласти(Элемент, Область)
//Фрагмент обработчика
Область = Элемент.ТекущаяОбласть;
Если Область.Расшифровка = Неопределено Тогда
Возврат;
КонецЕсли;
ОбработкаРасшифровки = Новый ОбработкаРасшифровкиКомпоновкиДанных(АдресДанныеРасшифровки, Новый ИсточникДоступныхНастроекКомпоновкиДанных(АдреcМакетСКД));
КонецПроцедуры
&НаКлиенте
Процедура ПолеТабличногоДокументаПредставлениеПриАктивизацииОбласти(Элемент)
//Фрагмент обработчика
ОбработкаРасшифровки = Новый ОбработкаРасшифровкиКомпоновкиДанных(АдресДанныеРасшифровки, Новый ИсточникДоступныхНастроекКомпоновкиДанных(АдреcМакетСКД));
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПолучитьИмяТекущегоПоляРедактирования(Расшифровка, АдресДанныеРасшифровки)
//тип ДанныеРасшифровкиКомпоновкиДанных // Сервер, толстый клиент, внешнее соединение
ДанныеРасшифровки = ПолучитьИзВременногоХранилища(АдресДанныеРасшифровки); //ДанныеРасшифровкиКомпоновкиДанных // Сервер, толстый клиент, внешнее соединение
ЗначенияПолейРасшифровки = ДанныеРасшифровки.Элементы[Расшифровка].ПолучитьПоля();
Если ЗначенияПолейРасшифровки.Количество() = 0 ИЛИ ЗначенияПолейРасшифровки[0].Значение = NULL Тогда
Возврат "";
КонецЕсли;
ИмяПоля = ЗначенияПолейРасшифровки[0].Поле;
Возврат ИмяПоля;
КонецФункции // ()
Что еще?
UPD 07.07.2021 Добавлена реализация для тонкого клиента на управляемой форме без использования модальности.
1) Никто не запрещает размещать на форме стандартные настройки компоновщика настроек.
2) Можно добавлять в схему СКД любую другую информацию (с помощью других наборов данных), которая не содержится в табличной части редактируемого объекта, но которая необходима для принятия решения при вводе данных (например свойства номенклатуры).
3) Группировка данных в таблице также может быть сколь угодно сложной, в зависимости от решаемой задачи.
4) Можно и нужно использовать всю мощь СКД и возможностей условного оформления.