Динамический вывод таблицы значений на форму

Вывести на форму таблицу значений, а потом на её место другую, третью, четвёртую? Не вопрос.

Возможно, это уже где-то было, но мне не попалось.

Появилась необходимость выводить на форму таблицу значений в зависимости от загруженных данных, с различным количеством и названиями полей. На эту тему статей хватает. Но большинство из них касается только создания, а надо было не только создавать элементы, но ещё и удалять их при выводе туда же другой ТЗ с другими полями. А с этим пришлось немного повозиться.

В итоге получилась такая штука, в которую можно раз за разом пихать разные ТЗ, и она будет их показывать.

В реквизитах формы в конфигураторе заранее создаётся таблица значений ТабРеквизит и вытаскивается на форму на необходимое место под именем ТабЭлементФормы (если имя совпадает с ТабРеквизит, как обычно и бывает, в параметрах процедуры его можно не указывать).

Процедура удаляет (если они были) уже имеющиеся программно созданные (возможно, этой же процедурой) элементы формы из ТабЭлементФормы  с реквизитами, в которых хранились выводимые значения. На основании переданной ТаблицаЗначений формируются новые реквизиты, которые в последнем цикле привязываются к вновь создаваемым элементам формы. Осталось заполнить ТабРеквизит данными из ТаблицаЗначений ,что и происходит в предпоследней строчке. На этом всё. Готово. Конец процедуры.


&НаСервере
Процедура ВывестиТаблицуЗначенияВТаблицуНаФорме(ТаблицаЗначений, ТабРеквизит, ТабЭлементФормы = Неопределено)
Если ТабЭлементФормы = Неопределено Тогда
ТабЭлементФормы = ТабРеквизит;
КонецЕсли;

// Собирается инофрмация по добавленным ранее элементам формы и реквизитам, на которые элементы формы ссылаются.
УдаляемыеРеквизиты = Новый Массив;
УдаляемыеЭлементы = Новый Массив;
Для каждого Эл Из Элементы[ТабЭлементФормы].ПодчиненныеЭлементы Цикл
УдаляемыеРеквизиты.Добавить(Эл.ПутьКДанным);
УдаляемыеЭлементы.Добавить(Эл);
КонецЦикла;
Для каждого Эл Из УдаляемыеЭлементы Цикл
Элементы.Удалить(Эл);
КонецЦикла;

// Добавляются колонки из ТаблицыЗначений в реквизит таблицы ТабРеквизит
НовыеРеквизиты = Новый Массив;
Для Каждого Колонка Из ТаблицаЗначений.Колонки Цикл
НовыйРеквизит = Новый РеквизитФормы(Колонка.Имя, Колонка.ТипЗначения, ТабРеквизит, Колонка.Заголовок);
НовыеРеквизиты.Добавить(НовыйРеквизит);
КонецЦикла;

//Удаляются старые и устанавливаются новые реквизиты
ИзменитьРеквизиты(НовыеРеквизиты, УдаляемыеРеквизиты);

// Добавляются колонки из ТаблицыЗначений в элементы ТабЭлементФормы со ссылкой на колонки в ТабРеквизит
Для Каждого Колонка Из ТаблицаЗначений.Колонки Цикл
НовыйЭлемент = Элементы.Добавить( ТабРеквизит + "_" + Колонка.Имя, Тип("ПолеФормы"), Элементы[ТабЭлементФормы]);
НовыйЭлемент.Вид = ВидПоляФормы.ПолеНадписи; //Или ПолеВвода, или что-то другое;
НовыйЭлемент.ПутьКДанным = ТабРеквизит + "." + Колонка.Имя;
КонецЦикла;

// В созданный реквизит загружается ТЗ
ЭтаФорма[ТабРеквизит].Загрузить(ТаблицаЗначений);
КонецПроцедуры

 

30 Comments

  1. AnderWonder

    А зачем ИзменитьРеквизиты вызывается два раза, если можно один?

    ИзменитьРеквизиты(НовыеРеквизиты, УдаляемыеРеквизиты)

    Reply
  2. Vlad1917

    Чтоб не получилось, что я одновременно и удаляю, и добавляю аналогичный реквизит. Например, при выводе ТЗ одинаковой структуры с предыдущей.

    Reply
  3. starik-2005

    О, это было много раз! Давай ышо!

    Reply
  4. azhilichev

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

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

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

    Внимание! Действия добавления и удаления выполняются за один вызов. Следует учитывать, что операция изменения состава реквизитов является ресуркоемкой, поэтому операции изменения состава реквизитов формы выполняются пакетным образом.
    Reply
  5. vitkhv

    (2) Вообще-то ИзменитьРеквизиты очень дорогая операция, поэтому вызывать ее два раза совсем не комильфо.

    Reply
  6. Vlad1917

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

    Reply
  7. Vlad1917

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

    А если получится дать МНОГО таких ссылок на Инфостарт (согласен считать что две — это много), то готов под Н-ным (по количеству приведённых ссылок) количеством Ваших постов написать — «да, этот человек знает, о чём говорит!». 😉

    Reply
  8. Vlad1917

    (4) Из Вашего же пруфа: «Такими сценариями могут быть, например, отображение в форме имеющихся типовых операций или характеристик объектов. То есть той информации, которая содержится в базе данных и структура которой неизвестна на этапе конфигурирования. Ее можно узнать только уже в процессе функционирования прикладного решения, в режиме 1С:Предприятие. Поэтому для ее отображения в форме и требуется ее программное изменение.»

    Нужно было выводить и обрабатывать загружаемые xls файлы, в которых верхняя строка — название колонок, остальные строки — данные. Количество колонок, название и смысловая информация различные в различных файлах. Думаю, это тот самый случай. 🙂

    Reply
  9. starik-2005

    (7)

    где подробно написано про удаление старых и создание новых элементов и реквизитов ТЗ

    Фактически, искомая инфа есть во втором комментарии здесь: https://infostart.ru/public/574802/

    Reply
  10. Vlad1917

    (9) Несомненно, Ваша фраза из второго комментария к Вашей статье «лучше полностью сносить таблицу и создавать новую, чем заморачиваться изменениями колонок — пользы чуть, а геморроя — масса.» гораздо полнее и лучше раскрывает решение вопроса, который стоял передо мной (и, возможно, возникнет у кого-то ещё), чем способ, который я предложил. Вероятно, мне стоит согласиться с тем, что в статье, написанной мною, вместо кучи бессмысленного текста было бы достаточно привести ссылку на Вашу всеобъемлющую статью.

    Но всё же я так не думаю.

    Хотя спасибо Вам. Начинаю гордиться собой. Меньше, чем 30 строчек кода, оказывается, не только могут вывести разные ТЗ на форму, но и справиться с «массой геморроя»! 🙂

    Reply
  11. starik-2005

    (10)

    Меньше, чем 30 строчек кода, оказывается, не только могут вывести разные ТЗ на форму, но и справиться с «массой геморроя»!

    В девстве, помню, консоль запросов делал на УФ — ровно 30 строк занял вывод результата запроса в форму (с учетом изменившихся реквизитов). Но это по-молодости. Сейчас все в 10 строк умещается.

    Reply
  12. Vlad1917

    (11) Вот вырасту, и у меня вывод ТЗ будет занимать пару строчек. А пока ещё маленький, так что мне 30 простительно. 🙂

    Reply
  13. azhilichev

    (8) Основной посыл: динамическое создание реквизитов и элементов формы — дорогая операция.

    Reply
  14. PerlAmutor

    (0)

    НовыйРеквизит = Новый РеквизитФормы(Колонка.Имя, Колонка.ТипЗначения, ТабРеквизит, Колонка.Заголовок);
    

    Эту строку нужно доработать. Уже столкнулся с этим на практике. Есть типы полей, которые приемлемы в ТЗ, но никак не в реквизите формы. Например Null или МоментВремени. В первом случае у вас будет платформа выдавать странную ошибку при попытке поиска чего-либо в такой таблице. Во втором — платформа сразу выдаст ошибку при добавлении. Ошибки такого рода коварны тем, что в какой-то момент начинаешь готовый код по отображению ТЗ на форме переносить в другие задачи, где таблицы значений могут быть самыми разнообразными и потом удивляться почему все перестало работать.

    Reply
  15. json

    Почитал комментарии, многие написали, что ИзменитьРеквизиты() — это дорогая операция.

    Понятно, что это взято из документации, и многие даже не задумывались, что это значит.

    Мне бы хотелось узнать мнение практиков, а не теоретиков. В чем именно выражается эта дороговизна?

    Я в нескольких проектах использовал этот метод. Всегда все работало быстро. Никаких задержек не ощущалось.

    При каких условиях начинает проявляться эта дороговизна? Было бы интересно прочитать подробности из личного опыта

    Reply
  16. Vlad1917

    (13) Хорошо, не буду спорить.

    Посоветуйте, пожалуйста, как задёшево решить эту часть задания заказчика, в котором надо выводить на форму ТЗ, с учётом того, что структура её и данных заранее неизвестна. Вариант «убедить заказчика, что ему это не надо» не предлагать. 🙂

    Reply
  17. Vlad1917

    (15)

    Экселевская таблица 5.200 строк 22 колонки. Её загрузка и первичная обработка занимает порядка минуты, включая и процесс засовывания в ТЗ и вывода этой ТЗ на экран (внизу скрина как раз оно).

    Непосредственно процедура, которую я привёл, занимает, если верить замеру производительности… ммм… нисколько. 🙂

    Т. е. на фоне всего остального — ни о чём.



    Reply
  18. Vlad1917

    (14)Спасибо. Надо будет подумать, как учесть это.

    Reply
  19. azhilichev

    (16) Используйте табличный документ.

    Reply
  20. azhilichev

    (15) Когда эта операция выполняется у бОльшего количества пользователей. В моей практике > 100.

    В чем именно выражается эта дороговизна?

    Отрисовка формы. Нагрузка на сервер.

    Reply
  21. json

    (20) Ну если больше 100 пользователей, то там могут быть любые причины торможения. Как определили, что причина именно в методе ИзменитьРеквизиты()?

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

    Изменение реквизитов делается менее чем за секунду. Это нужно, чтобы ваши 100 пользователей очень часто выполняли эту операцию. Причем замедление возможно было при динамическом изменении ЭЛЕМЕНТОВ формы, а не РЕКВИЗИТОВ.

    Reply
  22. azhilichev

    (21) Счетчики, замер производительности, технологический журнал. Все по-взрослому.

    Reply
  23. json

    (22) ну по счетчикам вы это не определите, т.к. они только показывают серверные вызовы. Ведь и так понятно, что эта операция выполняется на сервере.

    В замере тоже очень мало вероятно, чтобы эта операция вылезла в топ. Если только она не выполнялась в цикле по 50 раз.

    По поводу тех. журнала — ответ расплывчатый.

    Ну да ладно…

    Reply
  24. azhilichev

    (23)

    ну по счетчикам вы это не определите, т.к. они только показывают серверные вызовы.

    Программные счетчики.

    По поводу тех. журнала — ответ расплывчатый.

    Устанавливаете стек ELK и анализируете тех. журнал.

    В замере тоже очень мало вероятно, чтобы эта операция вылезла в топ.

    Почему маловероятно? Просто представьте, что документ не делает движений.

    Reply
  25. json

    (24)

    Вы пытаетесь меня уличить?

    нет

    Программные счетчики.

    для себя интересно — можно поподробнее? Не в контексте нашего вопроса

    Reply
  26. json

    (24) (25)

    понял, наверное программные счетчики типа этого:

    НачВремя = ТекущаяДата();
    ДолгаяПроцедура();
    КонВремя = ТекущаяДата();
    ЗафиксироватьЗамерКудаНадо(НачВремя, КонВремя, «ДолгаяПроцедура»);
    

    и вопрос:

    в БСП же ИзменитьРеквизиты() на каждом шагу, вроде. Они там доп. реквизиты добавляют.

    Удалось с этим что-нибудь сделать?

    Reply
  27. lev6975

    Люди, а, подскажите, пжлста, такую вещь:

    1) Создал таблицу значений «ТаблицаНаФорме» в реквизите управляемой формы

    2)Перетащил ее в элементы

    3) На сервере формирую ТЗ и гружу ее в таблицу формы:



    ТаблицаНаФорме.Очистить();

    ТаблицаНаФорме.Загрузить(ТЗ);


    Допустим, в ТЗ было 20 строк

    После этого при даблклике на какую — нить строчку срабатывает событие»Выбор»:

    Процедура ТаблицаНаФормеВыбор(Элемент, ВыбраннаяСтрока, Поле, СтандартнаяОбработка)



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

    Все хорошо… Но, только, при первой загрузке…

    Если еще раз произвести:

    ТаблицаНаФорме.Очистить();

    ТаблицаНаФорме.Загрузить(ТЗ);

    То, метод ТаблицаНаФорме.Количество() возвращает число 20, а, в событии номер выбранной строки уже 21, 22, 23… То есть поле таблицы при каждой загрузке инкрементирует номера строк и не сбрасывает пока не закроешь форму

    Элементы.ТаблицаНаФорме.Обновить() не помогает!!!!!!!!!!!!!!

    Как скинуть этот счетчик строк?????

    Reply
  28. SlavaKron

    (27) В событии Выбор таблицы формы, связанной с таблицей значений, параметр ВыбраннаяСтрока – это идентификатор выбранной строки. Строго говоря, он может быть каким угодно и его фактическое значение нас интересовать не должно, потому что, чтобы получить данные выбранной строки, нужно использовать ТаблицаНаФорме.НайтиПоИдентификатору(ВыбраннаяСтрока) или Элемент.ТекущиеДанные.

    Reply
  29. lev6975

    (28) Мне важно не данные, а, именно, номер строки, по нему ищутся данные в другом объекте — в массиве структур который перегоняется с клиента на сервер и обратно, поскольку непосредственно таблицу значений для работы с данными на клиенте использовать невозможно — ее можно только рисовать на форме со стороны сервера.

    В общем, добавил колонку дополнительную, к таблице, где уникальный номер каждой строки, который совпадает с номером массива и по нему только получается позиционироваться, вообще, странно, что в 1С не предусмотрено позиционирование по номеру кликнутой строки

    Reply
  30. lev6975

    (28) Можно еще так, как Вы и написали, только:

    НомерСтроки = ТаблицаНаФорме.Индекс(ТаблицаНаФорме.НайтиПоИдентификатору(ВыбраннаяСтрока));

    Вчера не додумался…

    Но, поздно, я уже колонку с номерами добавил, ленива переделывать)))

    Спасибо за помощь!

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *