При интерактивной работе с таблицами значений в обычных формах 1С часто возникает задача динамического удаления колонок. Однако при стандартном подходе разработчики сталкиваются с тем, что после удаления текущей колонки табличное поле теряет активность, а фокус ввода пропадает или смещается на кнопку. В результате пользователю приходится заново кликать мышью по табличному полю, чтобы продолжить работу. Разберем, почему возникает такое поведение и как реализовать корректный переход к соседней ячейке.
Проанализируем типичные ошибки, которые приводят к потере текущей ячейки при попытке удалить колонку:
СоздатьКолонки(): Вызов пересоздания колонок табличного поля полностью уничтожает текущую коллекцию элементов интерфейса и генерирует их заново. При этом сбрасываются все пользовательские настройки (ширина колонок, форматы, видимость), а свойство ТекущаяКолонка очищается в Неопределено.ТекущийЭлемент). Даже если в коде назначить свойство ТекущаяКолонка, само табличное поле останется неактивным до тех пор, пока фокус ввода не будет возвращен ему явно.КолонкаТабличногоПоля.Имя и свойство КолонкаТабличногоПоля.Данные могут различаться. Если удалять колонку из исходной таблицы значений по имени элемента интерфейса, а не по фактическому имени поля в структуре данных, это приведет к ошибке выполнения.Разберем по шагам правильный механизм управления колонками табличного поля:
ТекущаяКолонка выбрана конкретная колонка.Колонки табличного поля.Данные и удаляем колонку из таблицы значений.СоздатьКолонки().Посмотрим на пример законченной процедуры, реализующей описанную логику:
Процедура УдалитьКолонкуНажатие(Элемент)
// 1. Проверяем, выбрана ли колонка
Если ЭлементыФормы.ТабПоле.ТекущаяКолонка = Неопределено Тогда
Возврат;
КонецЕсли;
КолонкаДляУдаления = ЭлементыФормы.ТабПоле.ТекущаяКолонка;
// 2. Запоминаем текущий индекс колонки
Индекс = ЭлементыФормы.ТабПоле.Колонки.Индекс(КолонкаДляУдаления);
// 3. Получаем имя реквизита в таблице значений и удаляем его из источника
ИмяДанных = КолонкаДляУдаления.Данные;
Если ЗначениеЗаполнено(ИмяДанных) И ТЗ.Колонки.Найти(ИмяДанных) <> Неопределено Тогда
ТЗ.Колонки.Удалить(ИмяДанных);
КонецЕсли;
// 4. Удаляем колонку из интерфейсного элемента
ЭлементыФормы.ТабПоле.Колонки.Удалить(КолонкаДляУдаления);
// 5. Проверяем, остались ли колонки в табличном поле
КоличествоКолонок = ЭлементыФормы.ТабПоле.Колонки.Количество();
Если КоличествоКолонок > 0 Тогда
// Если удалили крайнюю правую колонку, смещаем индекс на новую последнюю
Если Индекс >= КоличествоКолонок Тогда
Индекс = КоличествоКолонок - 1;
КонецЕсли;
// Позиционируемся на соседнюю колонку
ЭлементыФормы.ТабПоле.ТекущаяКолонка = ЭлементыФормы.ТабПоле.Колонки[Индекс];
КонецЕсли;
// 6. Возвращаем фокус в табличное поле
ЭтаФорма.ТекущийЭлемент = ЭлементыФормы.ТабПоле;
КонецПроцедуры
Рассмотрим аналогичную задачу для позиционирования по строкам. Если требуется удалить текущую строку таблицы значений с автоматическим переходом на следующую, используется схожий принцип через свойство ТекущаяСтрока.
Посмотрим на пример удаления текущей строки:
Процедура УдалитьСтрокуНажатие(Элемент)
СтрокаДляУдаления = ЭлементыФормы.ТабПоле.ТекущаяСтрока;
Если СтрокаДляУдаления = Неопределено Тогда
Возврат;
КонецЕсли;
// Определяем индекс строки в таблице значений
ИндексСтроки = ТЗ.Индекс(СтрокаДляУдаления);
// Удаляем строку из таблицы
ТЗ.Удалить(СтрокаДляУдаления);
// Проверяем оставшееся количество строк
КоличествоСтрок = ТЗ.Количество();
Если КоличествоСтрок > 0 Тогда
Если ИндексСтроки >= КоличествоСтрок Тогда
ИндексСтроки = КоличествоСтрок - 1;
КонецЕсли;
// Активируем соседнюю строку
ЭлементыФормы.ТабПоле.ТекущаяСтрока = ТЗ[ИндексСтроки];
КонецЕсли;
// Возвращаем фокус ввода
ЭтаФорма.ТекущийЭлемент = ЭлементыФормы.ТабПоле;
КонецПроцедуры
Выясним причину, почему физическое удаление колонок не всегда оправдано. При частом динамическом изменении состава данных полное удаление полей из таблицы значений приводит к лишней нагрузке и усложняет восстановление первоначального вида таблицы.
В качестве альтернативы рассмотрим изменение видимости. В этом случае данные остаются в памяти, а колонка скрывается из интерфейса:
Процедура СкрытьКолонкуНажатие(Элемент)
Если ЭлементыФормы.ТабПоле.ТекущаяКолонка = Неопределено Тогда
Возврат;
КонецЕсли;
ТекущаяКол = ЭлементыФормы.ТабПоле.ТекущаяКолонка;
Индекс = ЭлементыФормы.ТабПоле.Колонки.Индекс(ТекущаяКол);
// Скрываем колонку
ТекущаяКол.Видимость = Ложь;
// Ищем следующую видимую колонку
НайденаКолонка = Ложь;
Для К = Индекс По ЭлементыФормы.ТабПоле.Колонки.Количество() - 1 Цикл
Если ЭлементыФормы.ТабПоле.Колонки[К].Видимость Тогда
ЭлементыФормы.ТабПоле.ТекущаяКолонка = ЭлементыФормы.ТабПоле.Колонки[К];
НайденаКолонка = Истина;
Прервать;
КонецЕсли;
КонецЦикла;
// Если справа видимых колонок не нашлось, ищем слева
Если Не НайденаКолонка Тогда
Для К = Индекс - 1 По 0 Цикл
Если ЭлементыФормы.ТабПоле.Колонки[К].Видимость Тогда
ЭлементыФормы.ТабПоле.ТекущаяКолонка = ЭлементыФормы.ТабПоле.Колонки[К];
Прервать;
КонецЕсли;
КонецЦикла;
КонецЕсли;
ЭтаФорма.ТекущийЭлемент = ЭлементыФормы.ТабПоле;
КонецПроцедуры
Таким образом, для плавного интерфейсного взаимодействия важно исключить метод СоздатьКолонки(), аккуратно контролировать границы массива при назначении свойства ТекущаяКолонка и не забывать возвращать фокус на элемент формы с помощью свойства ТекущийЭлемент.