Как установить жирный шрифт для строк первого уровня в дереве значений на обычных формах 1С?

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

Приветствуем вас, коллеги! Сегодня мы подробно разберем, как применить жирный шрифт к строкам первого уровня в табличном поле типа "Дерево значений" на обычных формах 1С. Эта задача является классической для разработки на обычных формах и требует понимания работы с событиями табличного поля и структурой объекта "Дерево значений". Мы выясним причины распространенных ошибок и рассмотрим надежные методы решения.

Понимание проблемы и контекста

Представим ситуацию: у нас есть обычная форма, на которой размещено табличное поле, отображающее данные из реквизита формы типа "Дерево значений". Наша цель — визуально выделить все строки, которые находятся на верхнем уровне иерархии, установив для них жирный шрифт. При обходе строк дерева значений, как было замечено, у объекта СтрокаДереваЗначений доступны методы и свойства, такие как Владелец, Получить, Родитель, Строки, Уровень, Установить. Именно эти свойства помогут нам идентифицировать строки первого уровня. Почему эта задача может вызвать сложности? Как показывает практика, часто возникают две основные проблемы: 1. События табличного поля, предназначенные для оформления строк, могут не срабатывать. 2. Даже при срабатывании событий, определение "строки первого уровня" может работать некорректно, что приводит к применению жирного шрифта ко всем строкам или, наоборот, ни к одной. Давайте пошагово разберем, как правильно реализовать эту функциональность и избежать типичных ошибок.

Основной механизм оформления: Событие ПриПолученииДанных

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

Как работает событие ПриПолученииДанных?

Когда табличное поле собирается отобразить данные, оно вызывает обработчик события ПриПолученииДанных. В этот обработчик передаются два ключевых параметра: * Элемент: Ссылка на само табличное поле, вызвавшее событие. * ОформленияСтрок: Это коллекция объектов ОформлениеСтроки. Каждый объект ОформлениеСтроки представляет собой набор свойств для оформления одной видимой строки табличного поля. Внутри цикла по коллекции ОформленияСтрок мы получаем доступ к объекту ДанныеСтроки, который является ссылкой на фактическую строку нашего дерева значений. Именно через ДанныеСтроки мы будем проверять уровень вложенности.


Процедура МоеДеревоЗначПриПолученииДанных(Элемент, ОформленияСтрок)
    Для Каждого ОформлениеСтроки Из ОформленияСтрок Цикл
        ДанныеСтроки = ОформлениеСтроки.ДанныеСтроки;
        // Здесь будет логика определения уровня и применения шрифта
    КонецЦикла;
КонецПроцедуры

Идентификация строк первого уровня

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

Метод 1: Проверка свойства Родитель

Самый естественный и правильный способ определить корневую строку в ДеревеЗначений — это проверить ее свойство Родитель. У строк первого уровня (корневых) это свойство будет равно Неопределено, поскольку у них нет родителя. У всех остальных строк (подчиненных) свойство Родитель будет указывать на родительскую строку.


Процедура МоеДеревоЗначПриПолученииДанных(Элемент, ОформленияСтрок)
    Для Каждого ОформлениеСтроки Из ОформленияСтрок Цикл
        ДанныеСтроки = ОформлениеСтроки.ДанныеСтроки;
        
        // Проверяем, является ли строка строкой верхнего уровня
        Если ДанныеСтроки.Родитель = Неопределено Тогда 
            // Устанавливаем жирный шрифт
            ОформлениеСтроки.Шрифт = Новый Шрифт(ОформлениеСтроки.Шрифт, , , Истина);
        Иначе
            // Для всех остальных строк устанавливаем обычный шрифт (если нужно отменить предыдущие оформления)
            ОформлениеСтроки.Шрифт = Новый Шрифт(ОформлениеСтроки.Шрифт, , , Ложь);
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Важный нюанс, выявленный на форуме: Наш коллега столкнулся с проблемой, когда свойство Родитель почему-то было равно Неопределено *у всех строк*, даже у подчиненных. Это критический момент! Такое поведение абсолютно нетипично для правильно построенного ДереваЗначений. Если вы наблюдаете такую картину, это практически всегда означает, что ваше ДеревоЗначений было заполнено некорректно.

Как правильно строить иерархическое Дерево значений?

Чтобы свойство Родитель работало корректно, подчиненные строки должны быть добавлены не напрямую в коллекцию ДеревоЗначений.Строки, а в коллекцию Строки *родительской строки*. Представим, что у нас есть `ДеревоЗначений` по имени `МоеДерево`.


// Создаем колонки в дереве
МоеДерево.Колонки.Добавить("Наименование");
МоеДерево.Колонки.Добавить("Код");

// Добавляем строки верхнего уровня
СтрокаВерхнегоУровня1 = МоеДерево.Строки.Добавить();
СтрокаВерхнегоУровня1.Наименование = "Раздел 1";
СтрокаВерхнегоУровня1.Код = "001";

СтрокаВерхнегоУровня2 = МоеДерево.Строки.Добавить();
СтрокаВерхнегоУровня2.Наименование = "Раздел 2";
СтрокаВерхнегоУровня2.Код = "002";

// Добавляем подчиненные строки к СтрокаВерхнегоУровня1
СтрокаПодчиненная1_1 = СтрокаВерхнегоУровня1.Строки.Добавить(); // Важно! Добавляем через СтрокаВерхнегоУровня1.Строки
СтрокаПодчиненная1_1.Наименование = "Элемент 1.1";
СтрокаПодчиненная1_1.Код = "001.1";

СтрокаПодчиненная1_2 = СтрокаВерхнегоУровня1.Строки.Добавить();
СтрокаПодчиненная1_2.Наименование = "Элемент 1.2";
СтрокаПодчиненная1_2.Код = "001.2";

// Добавляем подчиненные строки к СтрокаВерхнегоУровня2
СтрокаПодчиненная2_1 = СтрокаВерхнегоУровня2.Строки.Добавить();
СтрокаПодчиненная2_1.Наименование = "Элемент 2.1";
СтрокаПодчиненная2_1.Код = "002.1";

Если вы добавляете все строки напрямую в МоеДерево.Строки.Добавить(), то все они будут считаться корневыми, и свойство Родитель у них действительно будет Неопределено. В таком случае табличное поле просто отобразит плоский список, даже если вы ожидали иерархию.

Метод 2: Использование метода Уровень()

Если по какой-то причине (например, из-за особенностей построения данных или их источника) вы не можете гарантировать корректное заполнение свойства Родитель, можно использовать метод Уровень() объекта СтрокаДереваЗначений. Этот метод возвращает числовое значение, обозначающее глубину вложенности строки. Для строк первого уровня (корневых) Уровень() всегда возвращает 0.


Процедура МоеДеревоЗначПриПолученииДанных(Элемент, ОформленияСтрок)
    Для Каждого ОформлениеСтроки Из ОформленияСтрок Цикл
        ДанныеСтроки = ОформлениеСтроки.ДанныеСтроки;
        
        // Проверяем уровень вложенности строки
        Если ДанныеСтроки.Уровень() = 0 Тогда 
            // Устанавливаем жирный шрифт
            ОформлениеСтроки.Шрифт = Новый Шрифт(ОформлениеСтроки.Шрифт, , , Истина);
        Иначе
            // Отменяем жирный шрифт для подчиненных строк
            ОформлениеСтроки.Шрифт = Новый Шрифт(ОформлениеСтроки.Шрифт, , , Ложь);
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

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

Метод 3 (Страховочный): Дополнительная колонка для уровня

Если же вы столкнулись с ситуацией, когда и Родитель всегда Неопределено, и метод Уровень() также не дает ожидаемого результата (что очень маловероятно при правильном добавлении строк, но все же), или если вы просто хотите иметь более явный контроль, вы можете добавить в само ДеревоЗначений дополнительную колонку, например, ЭтоВерхнийУровень булевого типа. При заполнении дерева вы будете самостоятельно устанавливать значение этой колонки: Истина для строк первого уровня и Ложь для подчиненных.


// Добавление колонки в дерево значений
МоеДерево.Колонки.Добавить("ЭтоВерхнийУровень", Тип("Булево"));

// Пример заполнения дерева с новой колонкой
СтрокаВерхнегоУровня1 = МоеДерево.Строки.Добавить();
СтрокаВерхнегоУровня1.Наименование = "Раздел 1";
СтрокаВерхнегоУровня1.ЭтоВерхнийУровень = Истина; // Помечаем как верхний уровень

СтрокаПодчиненная1_1 = СтрокаВерхнегоУровня1.Строки.Добавить();
СтрокаПодчиненная1_1.Наименование = "Элемент 1.1";
СтрокаПодчиненная1_1.ЭтоВерхнийУровень = Ложь; // Помечаем как не верхний уровень

Затем в событии ПриПолученииДанных вы проверяете значение этой колонки:


Процедура МоеДеревоЗначПриПолученииДанных(Элемент, ОформленияСтрок)
    Для Каждого ОформлениеСтроки Из ОформленияСтрок Цикл
        ДанныеСтроки = ОформлениеСтроки.ДанныеСтроки;
        
        // Проверяем значение нашей пользовательской колонки
        Если ДанныеСтроки.ЭтоВерхнийУровень Тогда 
            // Устанавливаем жирный шрифт
            ОформлениеСтроки.Шрифт = Новый Шрифт(ОформлениеСтроки.Шрифт, , , Истина);
        Иначе
            // Отменяем жирный шрифт
            ОформлениеСтроки.Шрифт = Новый Шрифт(ОформлениеСтроки.Шрифт, , , Ложь);
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Этот метод требует чуть больше усилий при заполнении дерева, но дает полный контроль и является отказоустойчивым, если стандартные свойства дерева почему-то не работают так, как ожидалось.

Применение жирного шрифта с помощью объекта Шрифт

Независимо от того, какой метод идентификации строк первого уровня мы выбрали, для применения жирного шрифта мы будем использовать объект Шрифт. Объект ОформлениеСтроки содержит свойство Шрифт, которое ссылается на текущий шрифт строки. Чтобы изменить этот шрифт, мы должны создать *новый* объект Шрифт, основываясь на текущем, и указать желаемое изменение (в нашем случае — жирность). Конструктор объекта Шрифт выглядит следующим образом: Новый Шрифт(<СуществующийШрифт>, <Размер>, <Начертание>, <Жирный>, <Курсив>, <Подчеркивание>, <Зачеркивание>) Где: * <СуществующийШрифт>: Объект Шрифт, на основе которого создается новый. Мы берем его из ОформлениеСтроки.Шрифт. * <Размер>: Размер шрифта. Если не указан, берется из `СуществующийШрифт`. * <Начертание>: Тип начертания. Если не указан, берется из `СуществующийШрифт`. * <Жирный>: Булево. Истина для жирного, Ложь для обычного. Это то, что мы меняем. * <Курсив>, <Подчеркивание>, <Зачеркивание>: Булевы. Если не указаны, берутся из `СуществующийШрифт`. Таким образом, строка ОформлениеСтроки.Шрифт = Новый Шрифт(ОформлениеСтроки.Шрифт, , , Истина); создает новый объект шрифта, который является копией текущего, но с установленной жирностью (Истина). Все остальные параметры шрифта (размер, начертание, курсив и т.д.) при этом сохраняются.

Решение проблем: Событие ПриПолученииДанных не срабатывает

Как было упомянуто в форуме, иногда возникает ситуация, когда событие ПриПолученииДанных, несмотря на правильное написание кода, просто не отрабатывает. Давайте разберем основные причины и способы их устранения: 1. Событие не привязано к табличному полю в конфигураторе: * Убедитесь, что в свойствах вашего табличного поля на форме (в конфигураторе) для события ПриПолученииДанных выбран ваш обработчик (например, МоеДеревоЗначПриПолученииДанных). Если поле пустое или содержит другое имя, событие не будет вызываться. 2. Данные не отображаются или не обновляются: * После программного заполнения ДереваЗначений, которое является источником данных для табличного поля, необходимо убедиться, что табличное поле "знает" об изменениях и перерисовывается. Для этого можно использовать методы обновления табличного поля: * ЭлементыФормы.МоеДеревоЗнач.Обновить(); – обновит данные и вызовет событие ПриПолученииДанных. * ЭлементыФормы.МоеДеревоЗнач.Перечитать(); – полностью перечитает данные из источника и перерисует табличное поле, также вызывая ПриПолученииДанных. * Вызывайте эти методы после того, как ваше `ДеревоЗначений` будет полностью заполнено. 3. Табличное поле не привязано к реквизиту формы: * Проверьте, что в свойствах табличного поля `ПутьКДанным` указывает на ваш реквизит формы типа `ДеревоЗначений` (например, `МоеДеревоЗнач`).

Отмена жирного шрифта для подчиненных строк

Важно отметить, что если мы устанавливаем жирный шрифт для строк первого уровня, то для всех остальных строк (подчиненных) мы должны явно установить обычный шрифт (Истина в Новый Шрифт() меняем на Ложь). Это необходимо, чтобы "сбросить" оформление, которое могло быть применено ранее или по умолчанию. Если этого не сделать, и событие ПриПолученииДанных будет вызываться повторно (например, при прокрутке), то предыдущее оформление может сохраниться некорректно.


Процедура МоеДеревоЗначПриПолученииДанных(Элемент, ОформленияСтрок)
    Для Каждого ОформлениеСтроки Из ОформленияСтрок Цикл
        ДанныеСтроки = ОформлениеСтроки.ДанныеСтроки;
        
        Если ДанныеСтроки.Родитель = Неопределено Тогда // или ДанныеСтроки.Уровень() = 0
            ОформлениеСтроки.Шрифт = Новый Шрифт(ОформлениеСтроки.Шрифт, , , Истина); // Жирный
        Иначе
            ОформлениеСтроки.Шрифт = Новый Шрифт(ОформлениеСтроки.Шрифт, , , Ложь); // Обычный
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Особенности работы с обычными формами

Напоследок, давайте еще раз подчеркнем, что все вышеописанные подходы актуальны именно для обычных форм. В управляемых формах для подобных задач обычно используется механизм условного оформления, который предоставляет более декларативный и визуальный способ настройки внешнего вида элементов, не требуя написания кода в событиях ПриПолученииДанных или ПриВыводеСтроки. Однако, поскольку наша задача касается обычных форм, условное оформление здесь неприменимо.

Заключение

Мы рассмотрели подробный алгоритм установки жирного шрифта для строк первого уровня в табличном поле типа "Дерево значений" на обычных формах 1С. Ключевыми шагами являются: 1. Правильная привязка и обработка события ПриПолученииДанных табличного поля. 2. Надежная идентификация строк первого уровня с помощью свойства Родитель или метода Уровень(). 3. Корректное создание нового объекта Шрифт для изменения только свойства жирности. 4. Диагностика и устранение проблем с некорректным построением иерархии ДереваЗначений, а также с несрабатыванием событий. Придерживаясь этих рекомендаций, вы сможете успешно реализовать данную функциональность в своих обычных формах, обеспечивая удобство и наглядность для пользователей. Удачи в разработке!

← На главную