В разработке на платформе 1С:Предприятие 8 (особенно в режиме Обычных форм) программисты часто сталкиваются с тем, что стандартные элементы управления имеют жесткие ограничения. Одной из таких проблем является работа с выделением ячеек в объекте ТабличноеПоле. В отличие от современных управляемых форм или офисных приложений, здесь нет прямого доступа к коллекции выбранных элементов, если речь идет не о строках целиком, а об отдельных ячейках.
В этой статье мы подробно разберем, почему стандартный подход не работает, проанализируем ограничения платформы и рассмотрим несколько эффективных способов решения задачи: от использования альтернативных элементов управления до эмуляции выделения «вручную».
Начнем с того, что выясним причину затруднений. У объекта ТабличноеПоле (ТП) есть свойство РежимВыделения, которое можно установить в значение Интервал, Множественный или Единичный. Однако эти режимы в основном ориентированы на работу со строками. Если же установить свойство СпособВыбораЯчейки или попытаться работать в режиме выделения ячеек, мы столкнемся со следующими фактами:
ВыделенныеСтроки возвращает массив строк, но не дает информации о том, какие именно колонки в этих строках были выделены пользователем.ТекущаяЯчейка всегда содержит только один объект, на котором в данный момент установлен фокус.ВыделенныеЯчейки.Рассмотрим подробнее, как можно обойти это ограничение, используя программные механизмы платформы.
Если ваша задача предполагает сложную работу с ячейками (например, как в Excel: выделение диапазонов, объединение, произвольная раскраска), наиболее правильным решением будет замена ТабличногоПоля на ПолеТабличногоДокумента.
В ПолеТабличногоДокумента работа с выделением реализована полноценно. Мы можем использовать свойство ВыделенныеОбласти, которое возвращает коллекцию всех выбранных пользователем диапазонов. Проанализируем пример кода для получения данных из выделенных ячеек:
Для Каждого Область Из ЭлементыФормы.ПолеТабличногоДокумента1.ВыделенныеОбласти Цикл
Для НомерСтроки = Область.Верх По Область.Низ Цикл
Для НомерКолонки = Область.Лево По Область.Право Цикл
Значение = ПолеТабличногоДокумента1.Область(НомерСтроки, НомерКолонки).Текст;
// Выполняем действия со значением
КонецЦикла;
КонецЦикла;
КонецЦикла;
Однако этот метод требует переработки логики вывода данных, так как ТабличныйДокумент не связан напрямую с источником данных (например, с ТаблицейЗначений) так же тесно, как ТабличноеПоле.
Если замена элемента управления невозможна, мы можем реализовать собственную логику «запоминания» выделенных ячеек. Идея заключается в том, чтобы фиксировать координаты каждой ячейки (строка + колонка) при клике пользователя, удерживающего определенную клавишу.
Разберем этот процесс по шагам:
Шаг 1. Подготовка структуры хранения. Создадим в модуле формы переменную (например, СоответствиеВыделенныхЯчеек), где ключом будет уникальный идентификатор строки, а значением — массив имен колонок.
Шаг 2. Обработка клика. В событии ПриАктивизацииЯчейки мы будем проверять, нужно ли добавить текущую ячейку в наш список. Поскольку в 1С 8.2 нет прямого метода проверки зажатого Ctrl, пользователи часто используют выделение через «двойной клик» или простое переключение состояния при каждом заходе в ячейку.
Процедура ТабличноеПоле1ПриАктивизацииЯчейки(Элемент)
ТекущаяСтрока = Элемент.ТекущаяСтрока;
ТекущаяКолонка = Элемент.ТекущаяКолонка.Имя;
// Проверяем, есть ли уже эта строка в нашем списке
Если СоответствиеВыделенныхЯчеек.Получить(ТекущаяСтрока) = Неопределено Тогда
МассивКолонок = Новый Массив;
МассивКолонок.Добавить(ТекущаяКолонка);
СоответствиеВыделенныхЯчеек.Вставить(ТекущаяСтрока, МассивКолонок);
Иначе
МассивКолонок = СоответствиеВыделенныхЯчеек.Получить(ТекущаяСтрока);
Индекс = МассивКолонок.Найти(ТекущаяКолонка);
Если Индекс = Неопределено Тогда
МассивКолонок.Добавить(ТекущаяКолонка);
Иначе
МассивКолонок.Удалить(Индекс); // Повторный клик снимает выделение
КонецЕсли;
КонецЕсли;
// Обновляем визуальное отображение
ЭлементыФормы.ТабличноеПоле1.ОбновитьСтроки();
КонецПроцедуры
Шаг 3. Визуализация. Чтобы пользователь видел, какие ячейки он выбрал, необходимо использовать событие ПриВыводеСтроки. Мы будем менять цвет фона ячеек, которые присутствуют в нашем соответствии.
Процедура ТабличноеПоле1ПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
МассивКолонок = СоответствиеВыделенныхЯчеек.Получить(ДанныеСтроки);
Если МассивКолонок <> Неопределено Тогда
Для Каждого ИмяКолонки Из МассивКолонок Цикл
ОформлениеСтроки.Ячейки[ИмяКолонки].ЦветФона = ЦветаСтиля.ВыделениеЯчейки;
КонецЦикла;
КонецЕсли;
КонецПроцедуры
Как отмечалось в обсуждении на форуме, иногда задачу можно упростить. Если пользователю нужно выделить только ячейки в одной колонке, идущие подряд, можно фиксировать только две точки: начальную и конечную.
Проанализируем ситуацию: пользователь выбирает первую ячейку, затем (например, с зажатым Shift или через специальную кнопку) выбирает вторую. Программно мы можем вычислить все строки, находящиеся между этими двумя индексами в ТаблицеЗначений, которая является источником данных для ТП.
Выясним причину, по которой этот метод удобен: он не требует хранения каждой отдельной координаты, достаточно знать два индекса строк. Однако это решение ограничено только одной колонкой и непрерывным диапазоном.
При реализации выделения «протягиванием мыши» (Drag-select) в обычном приложении вы столкнетесь с тем, что событие ПриАктивизацииЯчейки не всегда срабатывает корректно при быстром движении мыши. Платформа 1С v8 (обычные формы) не предоставляет низкоуровневого доступа к событиям движения мыши с зажатой кнопкой внутри ТабличногоПоля.
Рекомендация: Если ваша бизнес-логика критически зависит от выбора множества разрозненных ячеек, рассмотрите возможность добавления в таблицу специальной логической колонки (флажка) Выбрано для каждой значимой колонки данных. Это сделает интерфейс более понятным для пользователя 1С и значительно упростит программный код.
Таким образом, хотя штатного способа получить список выделенных ячеек не существует, комбинация событий ПриАктивизацииЯчейки, ПриВыводеСтроки и использование Соответствия позволяет полностью имитировать этот функционал, обеспечивая пользователю необходимый уровень комфорта при работе с данными.