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

Программист 1С v8.3 (Обычные формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

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

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

Причины ошибок и различия моделей данных

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

В управляемых формах клиентский контекст работает с коллекцией элементов данных формы, где строки имеют строковые или целочисленные идентификаторы. Метод получения данных по идентификатору является штатным для управляемого интерфейса, однако в модели обычных форм у элемента управления ТабличноеПоле таких методов нет.

Вторая распространенная ошибка — попытка прочитать свойство НомерСтроки. Если источником данных табличного поля является стандартная табличная часть объекта (справочника или документа), строка имеет тип СтрокаТабличнойЧасти и действительно содержит свойство НомерСтроки. Однако если источником данных выступает реквизит формы типа ТаблицаЗначений, ее строки имеют тип СтрокаТаблицыЗначений. У объекта СтрокаТаблицыЗначений нет встроенного свойства НомерСтроки. Порядковый номер строки в этом случае определяется исключительно ее индексом в родительской таблице значений.

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

Проблема с окрашиванием целого столбца вызвана путаницей между статическими свойствами колонок элемента управления и динамическим оформлением ячеек. Если разработчик устанавливает цвет фона у объекта КолонкаТабличногоПоля, платформа применяет этот цвет ко всем ячейкам данной колонки во всех строках. Точечное визуальное выделение отдельной ячейки на пересечении конкретной строки и колонки должно производиться только через специализированные события отрисовки табличного поля.

Определение текущих координат ячейки

Чтобы корректно определить координаты активной ячейки, необходимо запросить у табличного поля два свойства: текущую строку и текущую колонку:


ТекСтрока = ЭлементыФормы.ГрафикРаботыМенеджеров.ТекущаяСтрока;
ТекКолонка = ЭлементыФормы.ГрафикРаботыМенеджеров.ТекущаяКолонка;

Если ТекСтрока = Неопределено Или ТекКолонка = Неопределено Тогда
    Возврат;
КонецЕсли;

Переменная ТекСтрока уже содержит конкретную строку таблицы значений, в которую пользователь нажал мышью или спозиционировался с клавиатуры. Если по логике алгоритма требуется узнать целочисленный индекс строки (начиная с нуля), его получают через метод Индекс() самой таблицы значений:


ИндексСтроки = ГрафикРаботыМенеджеров.Индекс(ТекСтрока);
НомерСтрокиДляПользователя = ИндексСтроки + 1;

Алгоритм навигации к соседней ячейке

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

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

Пример универсальной процедуры для смещения фокуса и копирования данных:


Процедура СдвинутьИЗаполнитьЯчейку(СмещениеВправо = Истина)
    
    ТабличноеПоле = ЭлементыФормы.ГрафикРаботыМенеджеров;
    ТекСтрока = ТабличноеПоле.ТекущаяСтрока;
    ТекКолонка = ТабличноеПоле.ТекущаяКолонка;
    
    Если ТекСтрока = Неопределено Или ТекКолонка = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    ВсеКолонки = ТабличноеПоле.Колонки;
    ТекИндексКолонки = ВсеКолонки.Индекс(ТекКолонка);
    
    Если СмещениеВправо Тогда
        ЦелевойИндекс = ТекИндексКолонки + 1;
    Иначе
        ЦелевойИндекс = ТекИндексКолонки - 1;
    КонецЕсли;
    
    // Проверка выхода за границы диапазона колонок
    Если ЦелевойИндекс < 0 Или ЦелевойИндекс >= ВсеКолонки.Количество() Тогда
        Возврат;
    КонецЕсли;
    
    ЦелеваяКолонка = ВсеКолонки[ЦелевойИндекс];
    
    // Исключаем перемещение на фиксированную колонку продавца
    Если ЦелеваяКолонка.Имя = "Продавец" Тогда
        Возврат;
    КонецЕсли;
    
    // Перенос значения из активной ячейки в целевую
    ТекСтрока[ЦелеваяКолонка.Имя] = ТекСтрока[ТекКолонка.Имя];
    
    // Установка активности на новую ячейку
    ТабличноеПоле.ТекущаяКолонка = ЦелеваяКолонка;
    ТабличноеПоле.ТекущаяСтрока = ТекСтрока;
    
КонецПроцедуры

Назначив на горячие клавиши F6 и F8 вызов данной процедуры с параметрами Ложь и Истина соответственно, пользователь получает быстрое заполнение с корректным перемещением фокуса ввода без срыва на первую строку.

Адресная раскраска ячеек через события табличного поля

Чтобы раскрашивать только конкретные ячейки, а не целые столбцы или строки, в обычных формах 1С применяются обработчики динамического оформления табличного поля: ПриВыводеСтроки или ПриПолученииДанных.

В событии ПриВыводеСтроки доступен параметр ОформлениеСтроки типа ОформлениеСтроки, который предоставляет доступ к свойствам всей строки и к коллекции отдельных ячеек ОформлениеСтроки.Ячейки. Обращение к оформлению конкретной ячейки выполняется по имени соответствующей колонки:


Процедура ГрафикРаботыМенеджеровПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
    
    Если ДанныеСтроки = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Обход колонок с датами для проверки условий
    Для Каждого Колонка Из Элемент.Колонки Цикл
        
        Если Колонка.Имя = "Продавец" Тогда
            Продолжить;
        КонецЕсли;
        
        ЗначениеЯчейки = ДанныеСтроки[Колонка.Имя];
        ОформлениеЯчейки = ОформлениеСтроки.Ячейки[Колонка.Имя];
        
        // Пример условия: подсветка выходных или специальных статусов
        Если ЗначениеЯчейки = "В" Тогда
            ОформлениеЯчейки.ЦветФона = Новый Цвет(255, 230, 230);
            ОформлениеЯчейки.ЦветТекста = Новый Цвет(180, 0, 0);
        ИначеЕсли ЗначениеЯчейки = "Я" Тогда
            ОформлениеЯчейки.ЦветФона = Новый Цвет(230, 255, 230);
            ОформлениеЯчейки.ЦветТекста = Новый Цвет(0, 100, 0);
        ИначеЕсли ПустаяСтрока(ЗначениеЯчейки) Тогда
            ОформлениеЯчейки.ЦветФона = WebЦвета.Белый;
        КонецЕсли;
        
    КонецЦикла;
    
КонецПроцедуры

Оптимизация производительности: ПриВыводеСтроки против ПриПолученииДанных

Выбор правильного события оформления критически важен для быстродействия формы:

Пример реализации аналогичного оформления через событие ПриПолученииДанных:


Процедура ГрафикРаботыМенеджеровПриПолученииДанных(Элемент, ОформленияСтрок)
    
    Для Каждого ОформлениеСтроки Из ОформленияСтрок Цикл
        
        СтрокаДанных = ОформлениеСтроки.ДанныеСтроки;
        Если СтрокаДанных = Неопределено Тогда
            Продолжить;
        КонецЕсли;
        
        Для Каждого Колонка Из Элемент.Колонки Цикл
            Если Колонка.Имя = "Продавец" Тогда
                Продолжить;
            КонецЕсли;
            
            ТекЗначение = СтрокаДанных[Колонка.Имя];
            
            Если ТекЗначение = "В" Тогда
                ОформлениеСтроки.Ячейки[Колонка.Имя].ЦветФона = Новый Цвет(255, 220, 220);
            КонецЕсли;
        КонецЦикла;
        
    КонецЦикла;
    
КонецПроцедуры

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

Для стабильной работы интерфейса на обычных формах рекомендуется придерживаться следующих правил:

← На главную