Как восстановить фокус в ячейке таблицы и программно перейти на следующую строку в 1С?

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

При разработке управляемых форм в 1С:Предприятии 8.3 программисты часто сталкиваются с неприятным эффектом: после выполнения расчетов в таблице значений фокус с активной ячейки пропадает, а выделение строки сбрасывается. Это происходит из-за особенностей работы платформы с данными формы, особенно когда используются методы преобразования коллекций. В данной статье мы подробно разберем, почему это происходит, как оптимизировать код для сохранения стабильности интерфейса и как реализовать удобный переход на следующую строку после ввода данных.

Почему «слетает» активность ячейки?

Разберем первопричину проблемы. Когда в коде вызывается метод ЗначениеВРеквизитФормы, платформа 1С полностью обновляет содержимое объекта на форме. С точки зрения графического интерфейса это выглядит как удаление всей старой таблицы и создание на её месте новой с теми же данными. В этот момент все временные состояния элемента формы, такие как активная строка и фокус ввода, аннулируются, так как старые идентификаторы строк перестают существовать. Даже если данные выглядят идентично, для платформы это новые объекты.

Проанализируем ситуацию автора темы: для расчета итогов по колонкам он переводит таблицу в объект ТаблицаЗначений через РеквизитФормыВЗначение, выполняет циклы и возвращает её обратно. Именно этот «прыжок» между типами данных приводит к потере фокуса.

Способ 1: Оптимизация работы с ДанныеФормыКоллекция

Самый эффективный способ решить проблему потери фокуса — это вообще отказаться от использования методов РеквизитФормыВЗначение и ЗначениеВРеквизитФормы там, где это возможно. В управляемых формах реквизиты типа «Таблица значений» представлены объектом ДанныеФормыКоллекция. С ним можно работать почти так же, как с обычной таблицей значений: перебирать строки, обращаться к колонкам по имени и изменять значения.

Рассмотрим, как можно переписать расчет итогов, сохранив фокус в ячейке. Вместо выгрузки всей таблицы, мы будем работать напрямую с реквизитом ТЗ (который является частью Объект или просто реквизитом формы). Посмотрим на пример кода:


// Определяем имена колонок динамически
ИмяОрганизации = УдалитьЛишниеСимволыИзНаименования(Объект.Организация);
ИмяКолонкиОСТАТОК = "ОСТАТОК" + ИмяОрганизации;
ИмяКолонкиИТОГ = "ИТОГ" + ИмяОрганизации;

// Собираем массив колонок, по которым нужно считать сумму (склады)
МассивКолонокСоСкладами = Новый Массив;
Для Каждого ТекКолонка Из Элементы.ТЗ.ПодчиненныеЭлементы Цикл
    Если СтрНайти(ТекКолонка.Имя, "СКЛАД_") <> 0 Тогда
        МассивКолонокСоСкладами.Добавить(ТекКолонка.Имя);
    КонецЕсли;
КонецЦикла;

// Работаем напрямую с ДанныеФормыКоллекция (реквизит ТЗ на форме)
Для Каждого Стр Из ТЗ Цикл
    // Инициализируем расчетные значения
    Стр[ИмяКолонкиОСТАТОК] = Стр[ИмяОрганизации]; 
    Стр[ИмяКолонкиИТОГ] = 0;
    
    // Суммируем данные по складам
    Для Каждого ИмяСклада Из МассивКолонокСоСкладами Цикл
        Стр[ИмяКолонкиИТОГ] = Стр[ИмяКолонкиИТОГ] + Стр[ИмяСклада];
        Стр[ИмяКолонкиОСТАТОК] = Стр[ИмяКолонкиОСТАТОК] - Стр[ИмяСклада];
    КонецЦикла;
КонецЦикла;

Преимущество этого подхода: данные меняются «на лету» непосредственно в структуре формы. Платформа не перерисовывает таблицу целиком, а лишь обновляет значения в ячейках. Фокус ввода и текущая строка при этом остаются на своих местах.

Способ 2: Восстановление активности строки по идентификатору

Если специфика задачи все же требует использования ЗначениеВРеквизитФормы (например, при вызове сложных серверных процедур, работающих только с типом ТаблицаЗначений), нам необходимо научиться восстанавливать состояние таблицы вручную. Для этого используется идентификатор строки.

Выясним важный нюанс: свойство ТекущаяСтрока у элемента формы содержит не индекс и не саму строку, а внутренний числовой идентификатор. Разберем по шагам алгоритм восстановления:

  1. Перед началом расчетов сохраняем идентификатор текущей строки в переменную.
  2. Выполняем преобразование данных и расчеты.
  3. После возврата данных на форму (ЗначениеВРеквизитФормы) принудительно устанавливаем сохраненный идентификатор обратно в свойство ТекущаяСтрока.

Пример реализации:


// 1. Запоминаем текущую позицию
СохраненныйИдентификатор = Элементы.ТЗ.ТекущаяСтрока;

// 2. Выполняем действия с преобразованием данных
ТЗОбъект = РеквизитФормыВЗначение("ТЗ");
// ... какие-то расчеты в ТЗОбъект ...
ЗначениеВРеквизитФормы(ТЗОбъект, "ТЗ");

// 3. Восстанавливаем фокус
// Важно: идентификаторы строк могут измениться, если таблица была полностью пересоздана.
// Если строки те же, просто присваиваем:
Элементы.ТЗ.ТекущаяСтрока = СохраненныйИдентификатор;

Нужно учитывать, что если при обновлении данных строки удалялись или сортировались, старый идентификатор может стать недействительным. В этом случае вместо сохранения идентификатора нужно найти строку заново по ключевым полям (например, по Артикулу или Коду Номенклатуры), используя метод НайтиСтроки() у реквизита формы, и получить новый идентификатор методом ПолучитьИдентификатор().

Способ 3: Программный переход на следующую строку

Часто бизнес-процесс требует, чтобы после ввода числа в ячейку курсор автоматически прыгал на строку ниже (имитация поведения Excel). Для этого проанализируем совместное использование индекса строки и свойств активизации.

Рассмотрим алгоритм перехода:


&НаКлиенте
Процедура ТЗПриИзменении(Элемент)
    
    // Получаем текущие данные
    ТекущиеДанные = Элементы.ТЗ.ТекущиеДанные;
    Если ТекущиеДанные = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Находим индекс текущей строки в коллекции
    ТекущийИндекс = ТЗ.Индекс(ТекущиеДанные);
    
    // Проверяем, есть ли строка ниже
    Если ТекущийИндекс < ТЗ.Количество() - 1 Тогда
        // Получаем следующую строку
        СледующаяСтрока = ТЗ[ТекущийИндекс + 1];
        
        // Устанавливаем активность на следующую строку по её идентификатору
        Элементы.ТЗ.ТекущаяСтрока = СледующаяСтрока.ПолучитьИдентификатор();
        
        // Если нужно активизировать конкретную колонку (например, ту же самую)
        // Элементы.ТЗ.ТекущийЭлемент = Элементы.ТЗКоличество;
    КонецЕсли;
    
КонецПроцедуры

Важный момент: Чтобы пользователь мог сразу продолжить ввод в новой строке без лишнего клика мышкой, необходимо убедиться, что фокус находится на самом элементе таблицы. Используйте конструкцию Элементы.ТЗ.ТекущийЭлемент = Элементы.ТЗ; для принудительного возврата фокуса в таблицу.

Резюме и практические советы

Проанализировав проблему, мы можем сделать следующие выводы:

Соблюдение этих правил позволит создать интерфейс, который будет работать плавно и предсказуемо для пользователя, избавляя его от необходимости постоянно возвращать курсор в нужное место вручную.

← На главную