Представим, что в нашей конфигурации есть справочник "Товары":
![](https://static.tildacdn.com/tild3036-3036-4131-b665-613965643230/2023-06-06_16-47-57.png)
Для каждого товара нужно иметь возможность загрузить в 1С его изображение, и показывать его на форме товара:
![](https://static.tildacdn.com/tild3539-6363-4263-b336-623031396337/2023-06-06_16-50-10.png)
Задача с виду понятная и простая, но её реализация совсем неочевидная.
1. Как хранить изображение в 1С
Первое, что вы должны понимать: любой файл можно представить в виде последовательности байт, и изображение - не исключение:
![](https://static.tildacdn.com/tild3062-3966-4263-b733-616332376533/2023-06-06_17-02-50.png)
Для хранения двоичных данных в 1С используется тип данных ХранилищеЗначения:
![](https://static.tildacdn.com/tild3262-3138-4137-b763-353231666638/2023-06-06_17-04-17.png)
Для того чтобы загрузить изображение в 1С, нужно:
- получить двоичные данные изображения
- поместить двоичные данные в реквизит с типом ХранилищеЗначения
![](https://static.tildacdn.com/tild3635-3965-4032-a233-373065343639/2023-06-06_17-18-58.png)
Тогда для выгрузки изображение из 1С в файл последовательность действий будет такой:
- из реквизита с типом ХранилищеЗначения получить двоичные данные файла
- записать двоичные данные в файл
![](https://static.tildacdn.com/tild3038-3663-4430-b738-623037363232/2023-06-06_17-24-10.png)
Хранить двоичные данные файла в справочнике "Товары" не самая лучшая идея, потому что:
Рассмотрим реализацию с помощью отдельного справочника, назовём его ТоварыПрисоединенныеФайлы:
- это замедлит чтение данных из справочника: например, при программном получении данных объекта (метод ПолучитьОбъект()), или при обращении к реквизитам товара через точку (Товар.Артикул) из базы данных будут получены не только значения реквизитов справочника, но и картинка, а её размер может быть немаленьким
- кроме двоичиных данных файла важно хранить его расширение и другие сведения, например, размер, дату изменения, т.е. данные, которые напрямую к товару не имеют отношения
Рассмотрим реализацию с помощью отдельного справочника, назовём его ТоварыПрисоединенныеФайлы:
![](https://static.tildacdn.com/tild3730-3862-4235-b961-633662653831/2023-06-06_17-47-57.png)
Для этого справочника установим в качестве владельца справочник Товары:
![](https://static.tildacdn.com/tild3464-6262-4266-b263-386265623561/2023-06-06_17-49-10.png)
Теперь в справочник Товары добавим реквизит ФайлКартинки, в котором будем хранить ссылку на справочник присоединенных файлов:
![](https://static.tildacdn.com/tild3764-6238-4139-b232-653464646135/2023-06-06_18-01-59.png)
2. Как показать картинку на форме
Чтобы показать в 1С картинку на форме товара нужно:
- создать реквизит формы АдресКартинки с типом Строка
- создать элемент формы вида Поле картинки, связанный с реквизитом АдресКартинки
- описать программный код заполнения реквизита АдресКартинки: его нужно заполнить либо адресом во временном хранилище, по которому находятся двоичные данные картинки, либо навигационной ссылкой на реквизит, в котором хранятся двоичные данные картинки
![](https://static.tildacdn.com/tild3230-6561-4437-b734-336462316161/2023-06-06_17-54-17.png)
Теперь поработаем с кодом.
Обработаем событие Нажатие, связанное с полем картинки:
Обработаем событие Нажатие, связанное с полем картинки:
![](https://static.tildacdn.com/tild3864-3635-4638-a138-333830663932/2023-06-06_18-00-09.png)
При нажатии на поле картинки:
- если картинка уже выбрана, будем показывать её пользователю
- если картинка ещё не выбрана, будем показывать диалог для выбора картинки, а потом выбранную картинку помещать во временное хранилище
&НаКлиенте
Процедура АдресКартинкиНажатие(Элемент, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
Если ЗначениеЗаполнено(Объект.ФайлКартинки) Тогда
ПоказатьКартинку();
Иначе
ВыбратьКартинку();
КонецЕсли;
КонецПроцедуры
Код процедуры ВыбратьКартинку():
&НаКлиенте
Асинх Процедура ВыбратьКартинку()
ПараметрыДиалога = Новый ПараметрыДиалогаПомещенияФайлов;
ПараметрыДиалога.Заголовок = "Выберите картинку";
ПараметрыДиалога.Фильтр = "Все файлы изображений | *.jpg; *.png; *.bmp";
ОписаниеФайла = Ждать ПоместитьФайлНаСерверАсинх(,,,ПараметрыДиалога,УникальныйИдентификатор);
Если ОписаниеФайла <> Неопределено Тогда
АдресКартинки = ОписаниеФайла.Адрес;
ИнформацияОФайле = Новый Структура;
ИнформацияОФайле.Вставить("Адрес", АдресКартинки);
ИнформацияОФайле.Вставить("Имя", ОписаниеФайла.СсылкаНаФайл.Имя);
ИнформацияОФайле.Вставить("Расширение", ОписаниеФайла.СсылкаНаФайл.Расширение);
ИнформацияОФайле.Вставить("Размер", ОписаниеФайла.СсылкаНаФайл.Размер());
Объект.ФайлКартинки = СоздатьПрисоединенныйФайл(Объект.Ссылка, ИнформацияОФайле);
КонецЕсли;
КонецПроцедуры
Для помещения файла во временное хранилище с предварительным показом диалога выбора файла в приведенном выше коде используется асинхронный метод ПоместитьФайлНаСерверАсинх().
После помещения файла на сервер, адрес, по которому находятся данные картинки во временном хранилище помещается в реквизит формы АдресКартинки, а затем вызывается функция, в которой происходит создание элемента в справочнике ТоварыПрисоединенныеФайлы, ниже приведен код этой функции:
После помещения файла на сервер, адрес, по которому находятся данные картинки во временном хранилище помещается в реквизит формы АдресКартинки, а затем вызывается функция, в которой происходит создание элемента в справочнике ТоварыПрисоединенныеФайлы, ниже приведен код этой функции:
&НаСервереБезКонтекста
Функция СоздатьПрисоединенныйФайл(Товар, ИнформацияОФайле)
ХранилищеКартинки = Новый ХранилищеЗначения(ПолучитьИзВременногоХранилища(ИнформацияОФайле.Адрес),
Новый СжатиеДанных(9));
ОбъектФайла = Справочники.ТоварыПрисоединенныеФайлы.СоздатьЭлемент();
ОбъектФайла.Владелец = Товар;
ОбъектФайла.Наименование = ИнформацияОФайле.Имя;
ОбъектФайла.Расширение = ИнформацияОФайле.Расширение;
ОбъектФайла.Размер = ИнформацияОФайле.Размер;
ОбъектФайла.ДанныеФайла = ХранилищеКартинки;
ОбъектФайла.ИмяФайла = СтрЗаменить(ОбъектФайла.Наименование, ОбъектФайла.Расширение, "");
ОбъектФайла.Записать();
Возврат ОбъектФайла.Ссылка;
КонецФункции // СоздатьПрисоединенныйФайл()
Если картинка товара уже выбрана, то при нажатии на поле картинки вызывается процедура ПоказатьКартинку(), ниже её код:
&НаКлиенте
Асинх Процедура ПоказатьКартинку()
ДанныеКартинки = ПолучитьДанныеКартинки(Объект.ФайлКартинки);
ПутьКФайлу = ПолучитьИмяВременногоФайла(ДанныеКартинки.Расширение);
Ждать ПолучитьФайлССервераАсинх(ДанныеКартинки.АдресДанных, ПутьКФайлу);
Попытка
ЗапуститьПриложениеАсинх(ПутьКФайлу);
Исключение
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Не удалось открыть файл картинки по причине: " + ОписаниеОшибки();
Сообщение.Сообщить();
КонецПопытки;
КонецПроцедуры // ПоказатьКартинку()
С помощью функции ПолучитьДанныеКартинки() из базы данных выбираются сведения о картинке - Наименование, Расширение, Размер и, самое главное, Адрес во временном хранилище, по которому находятся двоичные данные файла:
&НаСервереБезКонтекста
Функция ПолучитьДанныеКартинки(ФайлКартинки)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТоварыПрисоединенныеФайлы.Наименование КАК Наименование,
| ТоварыПрисоединенныеФайлы.ДанныеФайла КАК АдресДанных,
| ТоварыПрисоединенныеФайлы.ИмяФайла КАК ИмяФайла,
| ТоварыПрисоединенныеФайлы.Расширение КАК Расширение,
| ТоварыПрисоединенныеФайлы.Размер КАК Размер
|ИЗ
| Справочник.ТоварыПрисоединенныеФайлы КАК ТоварыПрисоединенныеФайлы
|ГДЕ
| ТоварыПрисоединенныеФайлы.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", ФайлКартинки);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Выборка.Следующий();
СтруктураДанных = Новый Структура;
Для каждого Колонка Из РезультатЗапроса.Колонки Цикл
ИмяКолонки = Колонка.Имя;
Если ИмяКолонки = "АдресДанных" Тогда
ЗначениеКолонки = ПоместитьВоВременноеХранилище(Выборка[ИмяКолонки].Получить());
Иначе
ЗначениеКолонки = Выборка[ИмяКолонки];
КонецЕсли;
СтруктураДанных.Вставить(ИмяКолонки, ЗначениеКолонки);
КонецЦикла;
Возврат СтруктураДанных;
КонецФункции // ПолучитьДанныеКартинки()
Теперь мы видим на форме картинку:
![](https://static.tildacdn.com/tild3662-3634-4335-a262-636463383334/2023-06-06_18-22-20.png)
Но этого недостаточно: если теперь закрыть форму товара, а потом открыть снова, картинка пропадет:
![](https://static.tildacdn.com/tild3961-6631-4464-b061-656538643837/2023-06-06_18-23-52.png)
Это связано с тем, что при открытии формы товара реквизит АдресКартинки сейчас не заполняется. Исправим это: создадим обработчик события формы ПриЧтенииНаСервере, и в нём будем заполнять реквизит АдресКартинки навигационной ссылкой на реквизит "ДанныеФайла" справочника ТоварыПрисоединенныеФайлы:
![](https://static.tildacdn.com/tild6636-3133-4639-a630-306439396234/2023-06-06_18-26-34.png)
&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
АдресКартинки = ПолучитьНавигационнуюСсылку(ТекущийОбъект.ФайлКартинки, "ДанныеФайла");
КонецПроцедуры
Теперь при повторном открытии товара изображение на форме отображается:
![](https://static.tildacdn.com/tild3538-6330-4562-a131-636139323035/2023-06-06_18-28-21.png)
Добавим возможность удаления изображения товара. Для этого создадим команду формы УдалитьИзображение, и расположим её в контекстном меню поля картинки:
![](https://static.tildacdn.com/tild3836-6433-4265-b866-306364353065/2023-06-06_18-31-00.png)
В коде обработчика команды будем помечать на удаление элемент справочника присоединенных файлов, в котором хранятся двоичные данные изображения, а также очистить реквизит формы АдресКартинки и реквизит объекта (товара) ФайлКартинки:
&НаКлиенте
Процедура УдалитьИзображение(Команда)
ПометитьНаУдалениеПрисоединенныйФайл(Объект.ФайлКартинки);
Объект.ФайлКартинки = Неопределено;
АдресКартинки = "";
КонецПроцедуры
&НаСервереБезКонтекста
Процедура ПометитьНаУдалениеПрисоединенныйФайл(ПрисоединенныйФайл)
Если НЕ ЗначениеЗаполнено(ПрисоединенныйФайл) Тогда
Возврат;
КонецЕсли;
ПрисоединенныйФайлОбъект = ПрисоединенныйФайл.ПолучитьОбъект();
ПрисоединенныйФайлОбъект.УстановитьПометкуУдаления(Истина);
ПрисоединенныйФайлОбъект.Записать();
КонецПроцедуры
Готово, теперь пользователь может удалить изображение:
![](https://static.tildacdn.com/tild3230-6130-4235-a132-383938333335/2023-06-06_18-34-46.png)
По ссылке ниже вы можете скачать выгрузку демонстрационной информационной базы, в которой реализован пример, описанный выше: https://clck.ru/34d5vK
Присоединяйтесь к нам в Telegram:
https://t.me/ironskills_community1c
Если вы хотите разобраться во всех ключевых механизмах платформы, научиться разрабатывать собственные конфигурации 1С и дорабатывать существующие, приходите на наш комплексный курс по программированию в 1С: Узнать подробнее
https://t.me/ironskills_community1c
Если вы хотите разобраться во всех ключевых механизмах платформы, научиться разрабатывать собственные конфигурации 1С и дорабатывать существующие, приходите на наш комплексный курс по программированию в 1С: Узнать подробнее