Приветствуем вас, уважаемые коллеги! Сегодня мы детально разберем одну из классических проблем, с которой часто сталкиваются разработчики при работе с обычными формами в среде 1С:Предприятие 8 (начиная от версии 8.0 и заканчивая современными релизами 8.3 в режиме обычного приложения). Речь пойдет о поведении элемента управления Табличное поле, когда колонка с типом Булево настроена как флажок (галочка), но при клике на нее и последующем переходе на другую строку отмеченное значение таинственным образом сбрасывается или исчезает.
Мы проанализируем причины такого поведения платформы, разберем физику процесса взаимодействия интерфейса с данными и рассмотрим несколько надежных способов решения этой задачи на практических примерах кода.
Для начала давайте разберемся, как устроено отображение данных в 1С. Элемент управления Табличное поле на форме — это лишь визуальное окно (представление), которое само по себе не хранит данные. Оно жестко связано с источником данных, в роли которого в нашем случае выступает Таблица значений (ТЗ).
Когда вы нажимаете на флажок на форме, интерфейс пытается записать новое значение (Истина или Ложь) в соответствующую строку и колонку источника данных. Если в самом источнике данных (в нашей таблице значений) отсутствует колонка, куда можно сохранить это состояние, происходят следующие процессы:
Очень часто такая ситуация возникает, когда табличное поле заполняется результатом запроса напрямую с помощью метода Выгрузить(). Если в самом запросе не было заложено булево поле для отметки, то и в выгруженной таблице значений его физически не будет, сколько бы мы ни настраивали свойства колонки на форме.
Давайте рассмотрим детальные варианты решения этой проблемы.
Если ваша таблица значений формируется динамически с помощью запроса, самый простой и изящный способ — сразу объявить колонку под флажок в самом тексте запроса. Это избавит вас от необходимости программно дописывать структуру таблицы после её выгрузки.
Рассмотрим пример реализации такого подхода:
// Формируем текст запроса, где сразу создаем пустое булево поле
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЛОЖЬ КАК Пометка, // Создаем колонку с типом Булево и значением по умолчанию
| Номенклатура.Ссылка КАК Номенклатура,
| Номенклатура.Код КАК Код
|ИЗ
| Справочник.Номенклатура КАК Номенклатура";
// Выгружаем результат в Таблицу Значений
ТабДанных = Запрос.Выполнить().Выгрузить();
// Связываем полученную таблицу с элементом формы
ЭлементыФормы.Таб.Значение = ТабДанных;
ЭлементыФормы.Таб.СоздатьКолонки();
При таком подходе в таблице значений гарантированно создается колонка Пометка с типом Булево, инициализированная значением Ложь. Теперь платформе будет куда записывать состояние флажка при изменении строки.
Что делать, если текст запроса формируется в другой части системы, изменить его напрямую нельзя или таблица значений заполняется из внешнего источника (например, из файла Excel или XML)? В этом случае мы можем программно расширить структуру таблицы значений перед тем, как вывести её на форму.
Давайте разберем по шагам, как это сделать:
// Предположим, мы получили таблицу значений из внешнего источника
ТабДанных = ПолучитьТаблицуИзЗапросаИлиФайла();
// Проверяем, существует ли уже колонка "Пометка", чтобы избежать ошибок
Если ТабДанных.Колонки.Найти("Пометка") = Неопределено Тогда
// Добавляем колонку с явным указанием типа Булево
ТабДанных.Колонки.Добавить("Пометка", Новый ОписаниеТипов("Булево"));
КонецЕсли;
// Заполняем новую колонку значением по умолчанию (Ложь), чтобы в ячейках не было значения Неопределено
ТабДанных.ЗаполнитьЗначения(Ложь, "Пометка");
// Отображаем данные на форме
ЭлементыФормы.Таб.Значение = ТабДанных;
ЭлементыФормы.Таб.СоздатьКолонки();
Использование метода ЗаполнитьЗначения крайне важно, так как по умолчанию новые строки в добавленной колонке будут иметь значение Неопределено, что может привести к некорректному отображению флажков на форме.
После того как мы обеспечили наличие физической колонки в источнике данных, нам необходимо правильно настроить свойства самой колонки элемента управления Табличное поле. Часто разработчики допускают ошибку, указывая имя колонки и в свойстве Данные, и в свойстве ДанныеФлажка одновременно. Это приводит к конфликту отображения текста и галочки.
Проанализируем правильные настройки свойств колонки (их можно выполнить как в конфигураторе, так и программно):
"Пометка").РежимРедактированияКолонки.Непосредственно. Это позволит пользователю менять состояние флажка в один клик мыши без перехода строки в режим редактирования.Ложь, иначе редактирование будет заблокировано.Посмотрим на пример программной настройки колонок после инициализации табличного поля:
// Очищаем и заново создаем колонки табличного поля на форме
ЭлементыФормы.Tab.СоздатьКолонки();
// Получаем ссылку на созданную колонку "Пометка"
КолонкаПометка = ЭлементыФормы.Tab.Колонки.Пометка;
// Применяем правильные настройки свойств
КолонкаПометка.Данные = ""; // Обязательно очищаем текстовые данные!
КолонкаПометка.ДанныеФлажка = "Пометка"; // Привязываем к булевой колонке в ТЗ
КолонкаПометка.РежимРедактирования = РежимРедактированияКолонки.Непосредственно;
КолонкаПометка.Ширина = 3;
КолонкаПометка.ТекстШапки = "";
Иногда даже при очищенном свойстве Данные платформа продолжает выводить текстовое сопровождение рядом с галочкой. Чтобы избавиться от этого визуального шума и оставить только чистый флажок по центру, мы можем использовать два метода.
Способ А: Использование свойства Формат
Самый простой бескодовый вариант — настроить формат отображения логических величин в колонке:
КолонкаПометка = ЭлементыФормы.Tab.Колонки.Пометка;
КолонкаПометка.Формат = "БЛ=; БИ="; // Указываем пустые строки для лжи и истины
Способ Б: Управление отображением через событие ПриВыводеСтроки
Если вам требуется более гибкое управление, можно задействовать стандартное событие табличного поля ПриВыводеСтроки. В обработчике этого события мы можем явно указать системе, что текст выводить не нужно, а флажок выводить обязательно.
Процедура ТабПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
// Отключаем отображение любого текста в ячейке "Пометка"
ОформлениеСтроки.Ячейки.Пометка.ОтображатьТекст = Ложь;
// Включаем отображение флажка
ОформлениеСтроки.Ячейки.Пометка.ОтображатьФлажок = Истина;
КонецПроцедуры
Рассмотрим продвинутый сценарий. Бывают ситуации, когда таблица значений содержит сотни тысяч строк, и добавление дополнительной колонки в память нежелательно, либо структура таблицы строго зафиксирована и защищена от изменений на уровне ядра системы. Как быть в таком случае?
Мы можем хранить информацию о том, какие строки отмечены пользователем, в отдельной коллекции на форме — например, в объекте Соответствие или СписокЗначений. При этом колонка табличного поля останется чисто виртуальной.
Давайте реализуем этот алгоритм по шагам:
Шаг 1. Объявим переменную для хранения выбранных строк в модуле формы:
Перем ОтмеченныеСтроки; // Переменная модуля формы
Шаг 2. Инициализируем коллекцию при открытии формы:
Процедура ПриОткрытии()
ОтмеченныеСтроки = Новый Соответствие;
КонецПроцедуры
Шаг 3. Настроим визуализацию флажков в обработчике события ПриВыводеСтроки табличного поля. Наша виртуальная колонка на форме пусть называется "ВиртПометка" (при этом свойства Данные и ДанныеФлажка у нее должны быть абсолютно пустыми):
Процедура ТабПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
Ячейка = ОформлениеСтроки.Ячейки.ВиртПометка;
Ячейка.ОтображатьФлажок = Истина;
Ячейка.ОтображатьТекст = Ложь;
// Проверяем, содержится ли текущая строка данных в нашем соответствии отмеченных строк
ЕстьОтметка = (ОтмеченныеСтроки.Получить(ДанныеСтроки) <> Неопределено);
Ячейка.Флажок = ЕстьОтметка;
КонецПроцедуры
Шаг 4. Обработаем изменение состояния флажка пользователем через событие табличного поля ПриИзмененииФлажка:
Процедура ТабПриИзмененииФлажка(Элемент, Колонка)
Если Колонка.Имя = "ВиртПометка" Тогда
// Получаем строку, на которой кликнули по флажку
ТекСтрока = Элемент.ТекущиеДанные;
Если ТекСтрока <> Неопределено Тогда
// Проверяем текущее состояние в соответствии
Если ОтмеченныеСтроки.Получить(ТекСтрока) = Неопределено Тогда
// Если строки нет в списке отмеченных — добавляем
ОтмеченныеСтроки.Вставить(ТекСтрока, Истина);
Иначе
// Если строка уже была отмечена — снимаем выделение (удаляем из списка)
ОтмеченныеСтроки.Удалить(ТекСтрока);
КонецЕсли;
КонецЕсли;
// Принудительно обновляем визуальное состояние строки на экране
Элемент.ОбновитьСтроки(ТекСтрока);
КонецЕсли;
КонецПроцедуры
Этот способ крайне эффективен. Во-первых, вы не меняете исходную структуру данных. Во-вторых, вы получаете полный контроль над процессом отметки строк программным путем, а выбранные строки всегда легко выгрузить в массив для дальнейшей обработки.
Мы подробно разобрали все грани этой интерфейсной проблемы. Применяйте описанные методики в своей повседневной разработке, и ваши интерфейсы на обычных формах будут работать стабильно и отзывчиво!