При разработке интерфейсов на обычных формах (толстый клиент) часто создаются интерактивные рабочие места с матричной структурой данных, такие как графики выходов сотрудников, табели учета рабочего времени или шахматки распределения ресурсов. В таких интерфейсах табличное поле на форме связывается не с табличной частью документа, а с динамически создаваемой таблицей значений, где колонки соответствуют отдельным датам периода.
Для ускорения ввода информации пользователи часто запрашивают возможность пакетного или пошагового заполнения данных с клавиатуры: например, по нажатию горячих клавиш значение текущей ячейки копируется в соседнюю ячейку слева или справа, а курсор автоматически переходит на заполненную ячейку. При реализации такого сценария разработчики нередко сталкиваются с двумя типичными проблемами:
Корни этих затруднений лежат в переносе подходов разработки управляемых форм на обычные формы, а также в различиях между табличной частью прикладного объекта и универсальной коллекцией значений.
В управляемых формах клиентский контекст работает с коллекцией элементов данных формы, где строки имеют строковые или целочисленные идентификаторы. Метод получения данных по идентификатору является штатным для управляемого интерфейса, однако в модели обычных форм у элемента управления ТабличноеПоле таких методов нет.
Вторая распространенная ошибка — попытка прочитать свойство НомерСтроки. Если источником данных табличного поля является стандартная табличная часть объекта (справочника или документа), строка имеет тип СтрокаТабличнойЧасти и действительно содержит свойство НомерСтроки. Однако если источником данных выступает реквизит формы типа ТаблицаЗначений, ее строки имеют тип СтрокаТаблицыЗначений. У объекта СтрокаТаблицыЗначений нет встроенного свойства НомерСтроки. Порядковый номер строки в этом случае определяется исключительно ее индексом в родительской таблице значений.
Кроме того, в обычном табличном поле свойство ТекущаяСтрока возвращает не числовой индекс и не идентификатор, а непосредственно саму ссылку на объект строки источника данных. Если свойству ТекущаяСтрока ошибочно присвоить число, табличное поле не сможет сопоставить его со строкой таблицы значений и сбросит позицию курсора на первую строку диапазона.
Проблема с окрашиванием целого столбца вызвана путаницей между статическими свойствами колонок элемента управления и динамическим оформлением ячеек. Если разработчик устанавливает цвет фона у объекта КолонкаТабличногоПоля, платформа применяет этот цвет ко всем ячейкам данной колонки во всех строках. Точечное визуальное выделение отдельной ячейки на пересечении конкретной строки и колонки должно производиться только через специализированные события отрисовки табличного поля.
Чтобы корректно определить координаты активной ячейки, необходимо запросить у табличного поля два свойства: текущую строку и текущую колонку:
ТекСтрока = ЭлементыФормы.ГрафикРаботыМенеджеров.ТекущаяСтрока;
ТекКолонка = ЭлементыФормы.ГрафикРаботыМенеджеров.ТекущаяКолонка;
Если ТекСтрока = Неопределено Или ТекКолонка = Неопределено Тогда
Возврат;
КонецЕсли;
Переменная ТекСтрока уже содержит конкретную строку таблицы значений, в которую пользователь нажал мышью или спозиционировался с клавиатуры. Если по логике алгоритма требуется узнать целочисленный индекс строки (начиная с нуля), его получают через метод Индекс() самой таблицы значений:
ИндексСтроки = ГрафикРаботыМенеджеров.Индекс(ТекСтрока);
НомерСтрокиДляПользователя = ИндексСтроки + 1;
Перемещение по горизонтали требует вычисления колонки, стоящей слева или справа от текущей, записи данных в строку и последующего позиционирования фокуса. Процесс состоит из следующих шагов:
Неопределено.ЭлементыФормы.ГрафикРаботыМенеджеров.Колонки позволяет узнать порядковый номер колонки с помощью метода Индекс(ТекКолонка).Колонки.Количество() - 1.ТекСтрока[ЦелеваяКолонка.Имя] = Значение;.ТекущаяКолонка присваивается целевая колонка, а свойству ТекущаяСтрока повторно подтверждается исходная строка ТекСтрока.Пример универсальной процедуры для смещения фокуса и копирования данных:
Процедура СдвинутьИЗаполнитьЯчейку(СмещениеВправо = Истина)
ТабличноеПоле = ЭлементыФормы.ГрафикРаботыМенеджеров;
ТекСтрока = ТабличноеПоле.ТекущаяСтрока;
ТекКолонка = ТабличноеПоле.ТекущаяКолонка;
Если ТекСтрока = Неопределено Или ТекКолонка = Неопределено Тогда
Возврат;
КонецЕсли;
ВсеКолонки = ТабличноеПоле.Колонки;
ТекИндексКолонки = ВсеКолонки.Индекс(ТекКолонка);
Если СмещениеВправо Тогда
ЦелевойИндекс = ТекИндексКолонки + 1;
Иначе
ЦелевойИндекс = ТекИндексКолонки - 1;
КонецЕсли;
// Проверка выхода за границы диапазона колонок
Если ЦелевойИндекс < 0 Или ЦелевойИндекс >= ВсеКолонки.Количество() Тогда
Возврат;
КонецЕсли;
ЦелеваяКолонка = ВсеКолонки[ЦелевойИндекс];
// Исключаем перемещение на фиксированную колонку продавца
Если ЦелеваяКолонка.Имя = "Продавец" Тогда
Возврат;
КонецЕсли;
// Перенос значения из активной ячейки в целевую
ТекСтрока[ЦелеваяКолонка.Имя] = ТекСтрока[ТекКолонка.Имя];
// Установка активности на новую ячейку
ТабличноеПоле.ТекущаяКолонка = ЦелеваяКолонка;
ТабличноеПоле.ТекущаяСтрока = ТекСтрока;
КонецПроцедуры
Назначив на горячие клавиши F6 и F8 вызов данной процедуры с параметрами Ложь и Истина соответственно, пользователь получает быстрое заполнение с корректным перемещением фокуса ввода без срыва на первую строку.
Чтобы раскрашивать только конкретные ячейки, а не целые столбцы или строки, в обычных формах 1С применяются обработчики динамического оформления табличного поля: ПриВыводеСтроки или ПриПолученииДанных.
В событии ПриВыводеСтроки доступен параметр ОформлениеСтроки типа ОформлениеСтроки, который предоставляет доступ к свойствам всей строки и к коллекции отдельных ячеек ОформлениеСтроки.Ячейки. Обращение к оформлению конкретной ячейки выполняется по имени соответствующей колонки:
Процедура ГрафикРаботыМенеджеровПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
Если ДанныеСтроки = Неопределено Тогда
Возврат;
КонецЕсли;
// Обход колонок с датами для проверки условий
Для Каждого Колонка Из Элемент.Колонки Цикл
Если Колонка.Имя = "Продавец" Тогда
Продолжить;
КонецЕсли;
ЗначениеЯчейки = ДанныеСтроки[Колонка.Имя];
ОформлениеЯчейки = ОформлениеСтроки.Ячейки[Колонка.Имя];
// Пример условия: подсветка выходных или специальных статусов
Если ЗначениеЯчейки = "В" Тогда
ОформлениеЯчейки.ЦветФона = Новый Цвет(255, 230, 230);
ОформлениеЯчейки.ЦветТекста = Новый Цвет(180, 0, 0);
ИначеЕсли ЗначениеЯчейки = "Я" Тогда
ОформлениеЯчейки.ЦветФона = Новый Цвет(230, 255, 230);
ОформлениеЯчейки.ЦветТекста = Новый Цвет(0, 100, 0);
ИначеЕсли ПустаяСтрока(ЗначениеЯчейки) Тогда
ОформлениеЯчейки.ЦветФона = WebЦвета.Белый;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Выбор правильного события оформления критически важен для быстродействия формы:
ОформленияСтрок, содержащий массив объектов ОформлениеСтроки. Это позволяет заранее сгруппировать необходимые данные и пакетно оформить видимую область без задержек при прокрутке.Пример реализации аналогичного оформления через событие ПриПолученииДанных:
Процедура ГрафикРаботыМенеджеровПриПолученииДанных(Элемент, ОформленияСтрок)
Для Каждого ОформлениеСтроки Из ОформленияСтрок Цикл
СтрокаДанных = ОформлениеСтроки.ДанныеСтроки;
Если СтрокаДанных = Неопределено Тогда
Продолжить;
КонецЕсли;
Для Каждого Колонка Из Элемент.Колонки Цикл
Если Колонка.Имя = "Продавец" Тогда
Продолжить;
КонецЕсли;
ТекЗначение = СтрокаДанных[Колонка.Имя];
Если ТекЗначение = "В" Тогда
ОформлениеСтроки.Ячейки[Колонка.Имя].ЦветФона = Новый Цвет(255, 220, 220);
КонецЕсли;
КонецЦикла;
КонецЦикла;
КонецПроцедуры
Для стабильной работы интерфейса на обычных формах рекомендуется придерживаться следующих правил:
СтрокаТаблицыЗначений), а не через числовые идентификаторы.ЭлементыФормы.ТабличноеПоле.ОбновитьСтроки() или ЭлементыФормы.ТабличноеПоле.Освежить(). Метод ОбновитьСтроки() перерисовывает только текущий видимый диапазон строк, что работает значительно быстрее полного перестроения таблицы.Видимость колонки табличного поля. Если колонка скрыта пользователем или программно, переключение на нее может приводить к некорректному визуальному поведению фокуса ввода.Элемент.Колонки.ИмяКолонки.ЦветФона, если требуется избирательная раскраска ячеек. Свойства объекта КолонкаТабличногоПоля служат только для задания общего статического стиля всей колонки.