gifts2017

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

Опубликовал Дмитрий Д (profiprog1c) в раздел Программирование - Практика программирования

Как создать произвольную таблицу значений на форме в управляемом приложении программным способом
Приветствую всех читателям infostart’a. Данная статья будет посвящена вопросу создания произвольной таблицы значений на форме управляемого приложения программным способом.

Особенности задачи.

Каждый, кто программировал в обычном приложении, часто сталкивался с задачей получения произвольной таблицы значений на форме. Под произвольной таблицей значений понимается таблица, количество и тип колонок которой наперед не известно. То есть колонок может быть 3, а может 6, а может 8. В обычном приложении все просто: можно было на форме обработки разместить элемент «ТаблицаЗначений»,и затем передать в этот элемент созданную таблицу значений программным способом. Потом простой командой:


	ЭлементыФормы.ТабличноеПоле.СоздатьКолонки();


получить готовую таблицу значений на форме. Казалось бы, что может быть проще.

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

Решение задачи.

Первое, что мы должны сделать, это определить, как таблица появится на форме. Главное, что никакого элемента формы в обработке создавать не нужно. Мы его создадим программным способом, как и всю таблицу. То есть таблица будет описана, и создаваться в момент открытия формы или с помощью кнопки – это кому как нужно.


Создание таблицы на форме происходит через описание таблицы значений как реквизита:

	
МассивТипаВыбора = Новый Массив;

МассивТипаВыбора.Добавить(Тип("ТаблицаЗначений"));

ОписаниеТипаВыбора = Новый ОписаниеТипов(МассивТипаВыбора);

МассивРеквизитов = Новый Массив;

МассивРеквизитов.Добавить(Новый РеквизитФормы("ТаблицаРасписания", ОписаниеТипаВыбора, "", "ТЗН"));
Теперь мы должны создать программную таблицу значений, которая содержит данные. Если таблица значений будет получена из запроса, то все более - менее порядок. Если таблица создается вручную, то значение колонок, которые будут содержать числа или даты могут быть созданы через «ОписаниеТипов». Суть в том, что колонки в таблице значений обязательно должны иметь какой-то тип. Если, например,предполагается, что пользователь будет заполнять данные в этих колонках интерактивно, то нельзя добавлять колонку таблицы значений просто с именем, она должна иметь тип. Имейте ввиду – это очень важно т.к. эти типы мы передадим в таблицу на форме.

Создаем таблицу, которая содержит несколько колонок:

	
КД = Новый КвалификаторыДаты(ЧастиДаты.Время);            

МассивКД = Новый Массив;
МассивКД.Добавить(Тип("Дата"));
ОписаниеТиповВремя = Новый ОписаниеТипов(МассивКД, , ,КД);

	
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("С", ОписаниеТиповВремя);
ТЗ.Колонки.Добавить("До", ОписаниеТиповВремя);
ТЗ.Колонки.Добавить("ФИО");
ТЗ.Колонки.Добавить("Примечание");//ФИО и Примечание - строки


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

	
Для Каждого Колонка Из ТЗ.Колонки Цикл

	МассивРеквизитов.Добавить(Новый РеквизитФормы(Колонка.Имя, Колонка.ТипЗначения,"ТаблицаРасписания"));
	
КонецЦикла;
ИзменитьРеквизиты(МассивРеквизитов);      
ТаблицаПолейВыбора = Элементы.Добавить("ТЗН", Тип("ТаблицаФормы"));
ТаблицаПолейВыбора.ПутьКДанным = "ТаблицаРасписания";
ТаблицаПолейВыбора.Отображение = ОтображениеТаблицы.Список;

Вот такая нехитрая комбинация и наша таблица готова.

Далее укажем путь к данным и, например, можем установить ширину колонок:

Для Каждого Колонка Из ТЗ.Колонки Цикл

НовыйЭлемент = Элементы.Добавить(Колонка.Имя, Тип("ПолеФормы"), ТаблицаПолейВыбора);       
НовыйЭлемент.Вид = ВидПоляФормы.ПолеВвода;
НовыйЭлемент.ПутьКДанным = "ТаблицаРасписания." + Колонка.Имя;
НовыйЭлемент.Ширина = 10;
КонецЦикла;

Условное оформление, если нам нужно мы также пишем вручную,командное меню – вручную. Обработчики таблицы также пишутся руками. Например,что бы добавить обработчик события таблицы «Выбор»:

	ТаблицаПолейВыбора.УстановитьДействие("Выбор","ТЗНВыбор");

Для обработки данного события в форме процедуры прописывается отдельная процедура:

&НаКлиенте
Процедура ТЗНВыбор(ТЗ, ВыбраннаяСтрока, Поле, СтандартнаяОбработка)
//команды обработчика

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

Обратите внимание, что обработчики таблицы срабатывают на клиенте и поэтому должны иметь команду указатель компилятора

	&НаКлиенте

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

	ЗначениеВРеквизитФормы(ТЗ, "ТаблицаРасписания");

Вот что имеем в результате:

А вот обработка события "Выбор":


Послесловие.

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

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

Скачать файлы

Наименование Файл Версия Размер
ПроизвольнаяТаблицаЗначенийУправляемаяФорма.epf 108
.epf 6,94Kb
13.08.14
108
.epf 6,94Kb Скачать

См. также

Подписаться Добавить вознаграждение

Комментарии

1. Сергей (seermak) 14.08.14 13:37
(0) Все просто - формируем через СКД нужные данные и выгружаем их реквизит формы "табличный документ" Расшифровку передаем через временное хранилище. Если надо предусмотреть параметры колонок или еще что-то делаем это в СКД
2. Дмитрий Д (profiprog1c) 14.08.14 18:56
(1) seermak,
Это все да, а если Ваша таблица должна получится путем сложных вычислений. Например Запрос - Обработка запроса - Еще Запрос - Обработка запроса, совмещение и расчет данных программно, тогда как?
3. Сергей (seermak) 14.08.14 19:47
(2) Вы еще про перебор справочников вспомните) Все Ваши "Запрос - Обработка запроса - Еще Запрос - Обработка запроса" (если Вам нравится туда-сюда)загоняете в таблицу и используете, как внешние данные СКД
4. Дмитрий Д (profiprog1c) 14.08.14 21:12
(3) seermak, Ну при чем тут перебор справочника. Я так понял, что Вы привыкли получать таблицы значений одним запросом. А я Вам говорю о том, что есть таблицы которые получаются вычислениями вне запросов и при чем тут СКД? И кстати, по поводу перебора справочника, иногда выгоднее сделать перебор, чем делать запрос.
5. Яков Коган (Yashazz) 18.08.14 16:24
А ещё можно посмотреть, как эта задача давным-давно решена в УТ11 и БП3, и не изобретать велосипед.
Статья неплохая, но опоздала года на полтора.
6. Дмитрий Д (profiprog1c) 18.08.14 22:30
(5) Yashazz, С таким успехом можно все везде посмотреть. Статья предназначена для тех, кто столкнулся с такой задачей и не хочет где-то искать, а хочет сразу готовое. Каждому свое.
u_n_k_n_o_w_n; myr4ik07; Templ; link_l; kitaevay; Veduin; mammadov.zaur.77; +7 Ответить
7. Zaur Mammadov (mammadov.zaur.77) 31.12.14 17:26
profiprog1c
Спосибо.
Мне очень помогло.
А как Избавится от командного панеля.
Например я хочу импортиромат из .тхт.
В этом случе мне не нужно Командный панел таблицы.
Заране спосибо.
8. Дмитрий Д (profiprog1c) 02.01.15 22:27
(7) mammadov.zaur.77,

В процедуре СформироватьТаблицуЗначений()
В коде, где создаем объект "ТаблицаПолейВыбора" размещаем строку:

ТаблицаПолейВыбора.ПоложениеКоманднойПанели = ПоложениеКоманднойПанелиЭлементаФормы.Нет;

Командная панель будет не видна на форме после этого.
mammadov.zaur.77; +1 Ответить
9. Василий Пупкин (Cyberhawk) 17.01.15 10:07
У формы стоит АвтоматическоеСохранениеДанныхВНастройках = Истина.
Вопрос: можно ли программно создать реквизит с галочкой "Сохранение"? Не путать со свойством "Сохраняемые данные", Я веду речь о галочке в таблице реквизитов формы в конструкторе (приложил картинку).
Просто хочется, чтобы значения программно добавляемых реквизитов сохранялись средствами платформы при закрытии формы (ну, восстанавливать их придется уже самому, это понятно), не хочется писать это самостоятельно. Не нашел такой возможности ни в конструкторе, ни через точку.
Прикрепленные файлы:
10. Василий Пупкин (Cyberhawk) 17.01.15 19:20
+(9) в общем, средствами платформы сохранять значения программно созданных реквизитов нельзя.
Решение следующее: при открытии / перед закрытием / где удобно взводить свойство формы
СохраняемыеВНастройкахДанныеМодифицированы = Истина;

Тогда обработчик ПриСохраненииДанныхВНастройкахНаСервере() будет гарантированно вызван при закрытии формы - там и сохранять в настройках можно все, что душе угодно (вручную).
12. Денис Храпов (denxp2009) 23.04.15 09:32
Автору огромное спасибо!!! Статья пошла в избранное :)
13. Андрей Зырянов (AndreykO) 27.04.15 11:51
Интересная технология. Вот только у меня одна из колонок типа "ЛюбаяСсылка" и не взлетает...((
14. Дмитрий Д (profiprog1c) 27.04.15 17:12
(13) AndreykO,

В статье я отмечал, что колонка таблицы значений должна иметь явный, конкретный тип, а вот "ЛюбаяСсылка" не является конкретным типом.
mammadov.zaur.77; +1 Ответить
15. Антон Паскаль (platon_) 30.04.15 11:54
Интересная статья, хотелось бы ещё посмотреть создание таблицы с числами, и возможностью последующего вывода итога в подвал.
16. Антон Китаев (kitaevay) 15.05.15 19:41
Пример рабочего кода на тему, на основе примера выше, ТЗ выгружается по результату запроса, Колонки автоматически создаются из колонок ТЗ
Таблица на форме при этом получает колонку с флажком и остальные колонки нормально типизированы

		МассивТипаВыбора = Новый Массив;
		МассивТипаВыбора.Добавить(Тип("ТаблицаЗначений"));
		ОписаниеТипаВыбора = Новый ОписаниеТипов(МассивТипаВыбора);
		МассивРеквизитов = Новый Массив;
		ИмяТЗ = "ТаблицаСегментов"; ЗаголовокТЗ = "Сегменты";
		МассивРеквизитов.Добавить(Новый РеквизитФормы(ИмяТЗ, ОписаниеТипаВыбора, "", ЗаголовокТЗ));

		Запрос = Новый Запрос;
		Запрос.Текст = 
		"ВЫБРАТЬ
		|	ЛОЖЬ КАК Выб,
		|	СегментыНоменклатуры.Ссылка КАК Сегмент
		|ИЗ
		|	Справочник.СегментыНоменклатуры КАК СегментыНоменклатуры
		|ГДЕ
		|	НЕ СегментыНоменклатуры.ПометкаУдаления
		|
		|УПОРЯДОЧИТЬ ПО
		|	СегментыНоменклатуры.Наименование";
		
		РезультатЗапроса = Запрос.Выполнить();
		ТЗ = РезультатЗапроса.Выгрузить();
		
		Для Каждого Колонка Из ТЗ.Колонки Цикл
			ТипыЗначений = Новый Массив;
			Для каждого тТип из Колонка.ТипЗначения.Типы() Цикл
				Если тТип <> Тип("Null") Тогда
					ТипыЗначений.Добавить(тТип);
				КонецЕсли;
			КонецЦикла;
			МассивРеквизитов.Добавить(Новый РеквизитФормы(Колонка.Имя, Новый ОписаниеТипов(ТипыЗначений), ИмяТЗ));
		КонецЦикла;

		ЭтаФорма.ИзменитьРеквизиты(МассивРеквизитов);      
		эТаблица = Элементы.Добавить(ЗаголовокТЗ, Тип("ТаблицаФормы"), Элементы.ГруппаТовары);
		эТаблица.ПутьКДанным = ИмяТЗ;
		эТаблица.Отображение = ОтображениеТаблицы.Список;
		эТаблица.ПоложениеКоманднойПанели = ПоложениеКоманднойПанелиЭлементаФормы.Нет;
		эТаблица.ИзменятьСоставСтрок = Ложь;	

		Для Каждого Колонка Из ТЗ.Колонки Цикл
			НовыйЭлемент = Элементы.Добавить(Колонка.Имя, Тип("ПолеФормы"), эТаблица);
			НовыйЭлемент.ПутьКДанным = ИмяТЗ + "." + Колонка.Имя;
			Если Колонка.Имя = "Выб" Тогда
				НовыйЭлемент.Вид = ВидПоляФормы.ПолеФлажка;
			Иначе
				НовыйЭлемент.Вид = ВидПоляФормы.ПолеВвода;
				НовыйЭлемент.КнопкаОчистки = Ложь;
				НовыйЭлемент.КнопкаВыбора = Ложь;
				НовыйЭлемент.РедактированиеТекста = Ложь;
				НовыйЭлемент.КнопкаОткрытия = Истина;
			КонецЕсли;
		КонецЦикла;
		
		ЭтаФорма.ЗначениеВРеквизитФормы(ТЗ, ИмяТЗ);
...Показать Скрыть
Silenser; surr; semario; myr4ik07; test_mode; dour-dead; +6 Ответить 4
17. Дмитрий Д (profiprog1c) 10.06.15 14:21
(16) kitaevay,

Не вводите никого в заблуждение, вы типы присваиваете каждой колонке. И логично, что если вы из запроса грузите данные в ТЗ, то колонки ТЗ будут типизированы, а если они не типизированы вы им пытаетесь присвоить тип. А в моем примере речь шла о колонах в ТЗ, которые создаются руками.
18. Яков Коган (Yashazz) 16.06.15 15:07
(17) profiprog1c, да можно и не типизировать. Вы тут поднагнали пурги, мол, обязательно... Может, в старых релизах и было обязательно, да только всё меняется)

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

Функция ПолучитьПустоеОписаниеТипов() Экспорт
	мТипов=Новый Массив;
	квЧисла=Новый КвалификаторыЧисла(0,0);
	квСтроки=Новый КвалификаторыСтроки(0);
	квДаты=Новый КвалификаторыДаты(ЧастиДаты.ДатаВремя);
	Возврат Новый ОписаниеТипов(мТипов,квЧисла,квСтроки,квДаты);
КонецФункции

МойРеквизит=Новый РеквизитФормы("МойТест",ПолучитьПустоеОписаниеТипов());
...Показать Скрыть


Именно таким образом можно сделать динамически реквизит, в т.ч. колонку таблицы значений, которая будет вести себя как имеющая "Произвольный" тип. Только что проверено на 8.3.6.2014

Так что не зря я ворчал, публикация не вполне точна в своих утверждениях.
19. Дмитрий Д (profiprog1c) 16.06.15 17:22
(18) Yashazz,

А где у вас в вашем куске кода Произвольный тип???
От того что вы свою функцию назвали ПолучитьПустоеОписаниеТипов(), она пустой не стала.
В вашем коде я вижу мультитип, число, строка, дата - это да, но пустого в упор не заметил.
20. Яков Коган (Yashazz) 17.06.15 11:18
(19) Повторяю - именно такое описание типов и даёт эффект работы с реквизитом, как будто он произвольного типа. Собственно, в понятиях 1С именно приведённое мной описание типов и есть произвольный тип. Вы создайте на форме реквизит произвольного типа и посмотрите на него, хоть в отладчике, хоть как. Всё просто.
21. Дмитрий Д (profiprog1c) 17.06.15 11:29
(20) Yashazz,

Причем тут эффект работы, не играйте словами. Вы колонку тоже задаете как параметр.
В обычном приложении можно создать было колонку:
ТЗ.Колонки.Добавить("Контрагент") и все - колонка готова.
В вашем примере такое есть? Нету.
И в моем примере идет параметризация и в вашем примере тоже. Только в моем, я задаю конкретный тип, а вы мультитип, все по сути одно и тоже, без разницы.
22. Яков Коган (Yashazz) 17.06.15 12:56
(21) profiprog1c, а, так вы о том, чтобы вообще ничего не писать... Тогда пардон, неверно вас понял. Я всего лишь к тому, что эффект одинаковый - что ничего писать не надо, что мой вариант писать надо - в итоге результат тот же. А мы ведь на результат работаем, верно?
23. Дмитрий Д (profiprog1c) 17.06.15 16:39
(22) Yashazz,

Результат верен, но неверна терминология.
Я в статье пишу, что в управляемом приложении как в обычном приложении просто задать колонку не получится.
А нужно ее параметризировать, по сути описать. Присвоить колонке пустышку, просто имя, без параметра, как в обычном приложении, нельзя.
Если 8.3.6 есть возможность задать мультипараметр в колонку, да без проблем, но его тоже надо задать, сам он не появляется.
Это все вопросы вкуса программирования конкретного программиста, но пустышку задать нельзя, как это было в обычном.
24. Novichok (Novichok777) 10.07.15 11:25
Все хорошо, но код на 8.3.6.2014 выдает ошибку в строке "НовыйЭлемент = Элементы.Добавить(Колонка.Имя, Тип("ПолеФормы"), ТаблицаПолейВыбора);" (а у (16) в строке "НовыйЭлемент = Элементы.Добавить(Колонка.Имя, Тип("ПолеФормы"), эТаблица);".

Ошибка одна и та же: Недопустимое значение параметров!

Убил не один час, чтобы понять в каком параметре ошибка. Ответ как всегда прост.
В первом параметре НЕЛЬЗЯ указывать одно и тоже имя с реквизитом. Т.е. вот так если записать "НовыйЭлемент = Элементы.Добавить(ИмяТЗ + Колонка.Имя, Тип("ПолеФормы"), эТаблица); ", то все Ок.

Удачи. Спасибо за статью.
ASWar; DarkAn; +2 Ответить 2
25. Дмитрий Д (profiprog1c) 14.07.15 12:42
(24) Novichok777,

Моя обработка, по созданию произвольной таблицы, которую можно скачать, работает и в 8.3.6.2100, проверял.
А вот то, что тут комментаторы пишут и какие-то куски кода лепят в том же (16), я это не тестирую, и оно да, может не работать.
26. Andrew Kopeev (andrewrocker) 06.01.16 21:42
Коллеги,

Требуется создать таблицу значений с неясным количеством колонок. Т.е. делаю запрос, по запросу определяю список покупателей, создаю количество колонок с названием списка покупателей. Посмотрите, что я делаю не так:

Процедура ЗаполнитьКолонки(Элемент)

Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| ОптовыеЗаказчики.Заказчик,
| ОптовыеЗаказчики.ФормироватьСводныйЗаказ
|ИЗ
| РегистрСведений.ОптовыеЗаказчики КАК ОптовыеЗаказчики
|ГДЕ
| ОптовыеЗаказчики.ФормироватьСводныйЗаказ = ИСТИНА"
;

Результат = Запрос.Выполнить();
Обход = Результат.Выбрать();

Пока Обход.Следующий() Цикл
Таб.Колонки.Добавить(Обход.Заказчик,,Обход.Заказчик,50);
КонецЦикла;

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

В результате виртуальная таблица создается, но на форме данные не обновляются. На форме ничего не меняется, колонки не создаются.
27. Ярослав Володимирович (myr4ik07) 09.01.16 21:57
(16) kitaevay, ну, мужик! ну благодарю! То, что надо!
28. Сергей Зеленовский (zels) 03.08.16 19:03
Интересно, как сделать, чтобы по клику на заголовке колонки таблица сортировалась по этой колонке.
29. Alex Warnin (ASWar) 17.08.16 12:42
(24), подтверждаю, имена д.б. уникальными. Имя ТЗ лучше всегда добавлять в данном случае.
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа