Как обновить картинку на форме в 1С 7.7 без перезапуска формы?

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

При разработке интерфейсов в среде 1С:Предприятие 7.7 программисты часто сталкиваются с необходимостью динамического отображения графической информации. Классический сценарий — вывод фотографии номенклатуры в форме элемента справочника. Мы загружаем файл на диск, привязываем его к коду товара, но сталкиваемся с неприятным поведением платформы: картинка на форме обновляется только после закрытия и повторного открытия окна. Вызовы стандартных методов перерисовки, таких как Форма.Обновить(), не приносят желаемого результата.

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

Анализ исходного кода и поиск скрытой ошибки

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


Процедура _ЗагрузитьКартинку() 
    DefIMG = _глПутьКартинок+"def.jpg";  
    ИмяФайла = _глПутьКартинок+Строка(СокрЛП(Код)+".jpg");  
    Карт = СоздатьОбъект("Картинка"); 
    Карт.УстановитьКартинку(КР); 
    Карт.РежимРисования(3);
    Если ФС.СуществуетФайл(ИмяФайла)=1 Тогда 
        Карт.Загрузить(ИмяФайла);
    Иначе
        Карт.Загрузить(DefIMG);    
    КонецЕсли;
КонецПроцедуры

Выясним причину, по которой этот алгоритм не работает при повторном вызове. Главная проблема кроется в непонимании принципов взаимодействия элементов формы и объектов встроенного языка в 1С 7.7.

На форме элемента справочника уже размещен элемент диалога типа «Картинка» с идентификатором КР. В контексте формы этот идентификатор сам по себе является готовым объектом. Когда мы пишем строку Карт = СоздатьОбъект("Картинка"), мы создаем в оперативной памяти абсолютно новый, независимый и пустой объект графики.

Затем выполняется команда Карт.УстановитьКартинку(КР). Метод УстановитьКартинку() копирует данные из источника (параметра) в объект, для которого он вызван. В этот момент мы скопировали текущее состояние картинки с формы КР в локальную переменную Карт. Связь между ними после этого разрывается — это не ссылка на элемент формы, а независимая копия данных.

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

Решение 1. Прямая загрузка в элемент формы (оптимальный вариант)

Поскольку элемент диалога КР уже сам по себе является объектом типа «Картинка», нам вообще не требуется создавать промежуточный объект в памяти через функцию СоздатьОбъект(). Мы можем загрузить файл напрямую в элемент управления формы. Разберем этот лаконичный и правильный вариант:


Процедура _ЗагрузитьКартинку() 
    DefIMG = _глПутьКартинок + "def.jpg";  
    ИмяФайла = _глПутьКартинок + Строка(СокрЛП(Код) + ".jpg");  
    
    // Работаем напрямую с элементом формы КР
    Если ФС.СуществуетФайл(ИмяФайла) = 1 Тогда 
        КР.Загрузить(ИмяФайла);
    Иначе
        КР.Загрузить(DefIMG);    
    КонецЕсли;
    
    КР.РежимРисования(3); // Устанавливаем режим масштабирования
КонецПроцедуры

В данном случае метод Загрузить() применяется непосредственно к элементу формы. Картинка мгновенно считывается с диска и помещается в элемент интерфейса.

Решение 2. Возврат картинки на форму (если нужен временный объект)

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


Процедура _ЗагрузитьКартинку() 
    DefIMG = _глПутьКартинок + "def.jpg";  
    ИмяФайла = _глПутьКартинок + Строка(СокрЛП(Код) + ".jpg");  
    
    ВремКарт = СоздатьОбъект("Картинка"); 
    
    Если ФС.СуществуетФайл(ИмяФайла) = 1 Тогда 
        ВремКарт.Загрузить(ИмяФайла);
    Иначе
        ВремКарт.Загрузить(DefIMG);    
    КонецЕсли;
    
    // Переносим изображение из памяти на элемент диалога формы
    КР.УстановитьКартинку(ВремКарт);
    КР.РежимРисования(3);
КонецПроцедуры

Здесь ключевым действием является вызов КР.УстановитьКартинку(ВремКарт). Мы берем подготовленный в памяти объект ВремКарт и проецируем его содержимое на экранный элемент КР.

Важные нюансы и хитрости при работе с графикой в 1С 7.7

Даже при использовании правильного кода разработчики часто сталкиваются с техническими особенностями старой платформы 1С 7.7, из-за которых картинка все равно может визуально не обновиться или обновиться некорректно. Рассмотрим три важные проблемы и способы их решения.

  1. Принудительная перерисовка элемента (Трюк с видимостью)

    Штатный механизм отрисовки интерфейса Windows в 1С 7.7 иногда «ленится» обновлять графические области, считая, что элемент формы не изменил своих границ. Метод Форма.Обновить() часто игнорирует графические объекты. Чтобы заставить операционную систему мгновенно перерисовать картинку, используют проверенную хитрость — быстрое переключение видимости элемента:

    
    Форма.КР.Видимость(0);
    Форма.КР.Видимость(1);
    

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

  2. Борьба с агрессивным кэшированием графики

    Платформа 1С 7.7 оптимизирует работу с памятью и кэширует однажды загруженные файлы. Если пользователь заменяет файл картинки на диске (например, загружает новую фотографию поверх старой с сохранением того же имени файла), программа может проигнорировать изменения и продолжить показывать старую картинку из своего внутреннего кэша.

    Чтобы гарантированно очистить кэш перед выводом нового изображения, рекомендуется сначала «обнулить» элемент формы, загрузив в него пустой объект:

    
    ПустаяКарт = СоздатьОбъект("Картинка"); 
    КР.УстановитьКартинку(ПустаяКарт); // Очищаем форму от старых данных
    КР.Загрузить(ИмяФайла);            // Загружаем обновленный файл
    
  3. Проблема совместного доступа при копировании файлов

    Если в вашей конфигурации процесс устроен так, что пользователь выбирает файл на компьютере, система копирует его в сетевой каталог под именем кода номенклатуры, и затем сразу вызывается процедура _ЗагрузитьКартинку(), может возникнуть конфликт доступа. Копирование файла средствами операционной системы происходит асинхронно и занимает некоторое время.

    Если 1С попытается вызвать метод Загрузить() в микросекунду, когда файл еще копируется и заблокирован Windows, произойдет ошибка чтения, и картинка не обновится. Перед загрузкой рекомендуется убедиться, что файл полностью доступен:

    
    // Пример простой паузы или проверки доступности файла
    Для НомерПопытки = 1 По 5 Цикл
        Попытка
            // Пробуем открыть файл в эксклюзивном режиме для проверки готовности
            ФС.КопироватьФайл(ИмяФайла, ИмяФайла, 0); 
            Прервать; // Если ошибки нет, файл готов
        Исключение
            // Ждем долю секунды, если файл еще занят копированием
            Предупреждение("Ожидание готовности файла...", 1);
        КонецПопытки;
    КонецЦикла;
    

Применяя данные подходы в совокупности, мы получаем отказоустойчивый и быстрый механизм динамической работы с изображениями. Использование прямой адресации к элементам диалога формы КР.Загрузить() в сочетании с быстрым переключением видимости решает проблему обновления формы раз и навсегда.

← На главную