При разработке интерфейсов или формировании внешних отчетов часто возникает задача предоставить пользователю выбор цвета. Платформа 1С предлагает для этого удобный стандартный объект ДиалогВыбораЦвета. Однако разработчики часто сталкиваются с неожиданным поведением системы: если пользователь выбирает цвет не из палитры «Абсолютные», а из списка «Элементы стиля» (например, «Отрицательное число» или «Цвет текста кнопки»), то попытка получить составляющие Красный, Зеленый или Синий возвращает значение -1.
В этой статье мы разберем, почему так происходит, проанализируем структуру объекта Цвет и реализуем универсальный механизм для получения абсолютных цифровых значений RGB в любых ситуациях.
Прежде чем перейти к решению, выясним причину проблемы. В платформе 1С объект Цвет может иметь несколько видов, которые определяются перечислением ВидЦвета. Рассмотрим основные из них:
Красный, Зеленый и Синий содержат реальные данные.Для всех видов, кроме Абсолютного, платформа возвращает -1, так как значение цвета является «вычисляемым» и зависит от контекста (темы оформления, настроек ОС или версии платформы).
Рассмотрим ситуацию, когда мы пытаемся найти значение цвета через метаданные. Если ВидЦвета определен как ЭлементСтиля, можно попробовать обратиться к объекту метаданных напрямую. Рассмотрим пример кода, который часто пытаются использовать новички:
&НаСервере
Процедура ПолучитьЦветИзМетаданных(ВыбранныйЦвет)
// Попытка получить имя стиля из строкового представления
ИмяСтиля = Сред(Строка(ВыбранныйЦвет), 8);
ОбъектМетаданныхСтиля = Метаданные.ЭлементыСтиля.Найти(ИмяСтиля);
Если ОбъектМетаданныхСтиля <> Неопределено Тогда
ЗначениеЦвета = ОбъектМетаданныхСтиля.Значение;
// Но здесь нас снова может ждать неудача, если в метаданных указан другой стиль
КонецЕсли;
КонецПроцедуры
Проблема этого метода: функция Строка() возвращает локализованный синоним (например, "Стиль: Отрицательное число"), в то время как метод Найти() ожидает внутреннее имя объекта метаданных. Кроме того, этот способ совершенно не работает для системных цветов Windows или авто-цветов.
Существует проверенный временем способ заставить платформу 1С произвести вычисление цвета и преобразовать его в абсолютный формат. Этот метод основан на использовании объекта ТабличныйДокумент. При сохранении табличного документа в формат MXL7 платформа принудительно конвертирует все стили в конкретные RGB-значения для обеспечения визуальной идентичности документа.
Рассмотрим пошагово, как реализовать этот алгоритм:
ТабличныйДокумент.Абсолютный.Использование физических файлов на диске (через Записать()) может привести к ошибкам прав доступа или конфликтам при одновременной работе нескольких пользователей. Проанализируем более современный и надежный вариант с использованием объекта ПотокВПамяти, который работает полностью в оперативной памяти.
&НаСервере
Функция ПолучитьАбсолютныйЦвет(ИсходныйЦвет) Экспорт
// Если цвет уже абсолютный, возвращаем его без лишних вычислений
Если ИсходныйЦвет.Вид = ВидЦвета.Абсолютный Тогда
Возврат ИсходныйЦвет;
КонецЕсли;
// Инициализируем объекты для трансформации
Поток = Новый ПотокВПамяти;
ТабличныйДокумент = Новый ТабличныйДокумент;
// Помещаем цвет в ячейку R1C1
Ячейка = ТабличныйДокумент.Область("R1C1");
Ячейка.ЦветФона = ИсходныйЦвет;
// Магия преобразования: запись в формат MXL7 принудительно вычисляет RGB
ТабличныйДокумент.Записать(Поток, ТипФайлаТабличногоДокумента.MXL7);
// Получаем данные из потока для чтения
ДвоичныеДанныеДокумента = Поток.ЗакрытьИПолучитьДвоичныеДанные();
ЧтениеПотока = ДвоичныеДанныеДокумента.ОткрытьПотокДляЧтения();
// Читаем документ обратно
ТабличныйДокумент.Прочитать(ЧтениеПотока);
ЧтениеПотока.Закрыть();
// Теперь цвет в ячейке стал абсолютным
АбсолютныйЦвет = ТабличныйДокумент.Область("R1C1").ЦветФона;
Возврат АбсолютныйЦвет;
КонецФункции
После того как мы получили абсолютный цвет, мы можем легко перевести его в нужный нам строковый формат, например "255,0,0". Разберем вспомогательную функцию для форматирования:
&НаКлиенте
Процедура ПолучитьЦифрыЦвета()
Диалог = Новый ДиалогВыбораЦвета;
Если Диалог.Выбрать() Тогда
// Вызываем серверную функцию преобразования
АЦвет = ПолучитьАбсолютныйЦвет(Диалог.Цвет);
// Формируем итоговую строку
СтрокаRGB = СтрШаблон("%1,%2,%3",
Формат(АЦвет.Красный, "ЧГ=0"),
Формат(АЦвет.Зеленый, "ЧГ=0"),
Формат(АЦвет.Синий, "ЧГ=0"));
Сообщить("Выбранный цвет в формате RGB: " + СтрокаRGB);
КонецЕсли;
КонецПроцедуры
При использовании данного метода стоит учитывать следующие моменты:
Соответствие, где ключом будет исходный цвет-стиль, а значением — его абсолютный эквивалент.ТабличныйДокумент вернет те RGB-значения, которые актуальны для текущего сеанса пользователя в данный момент.ПотокВПамяти и расширенные методы работы с ТабличнымДокументом доступны преимущественно на стороне сервера. Поэтому процедуру преобразования лучше всегда выносить в &НаСервере или в общий модуль.Таким образом, использование временного табличного документа является наиболее надежным способом получения честных RGB-компонентов из абстрактных стилей 1С. Мы рассмотрели и реализовали оптимальный вариант этого решения, исключающий работу с файловой системой и гарантирующий корректный результат независимо от сложности выбранного стиля.