При разработке интерактивных интерфейсов в 1С:Предприятие часто возникает задача упростить работу конечного пользователя. Типичный сценарий: оператор заполняет первую таблицу на форме, затем нажимает кнопку, система автоматически обрабатывает данные, переносит их во вторую таблицу, переключает пользователя на следующую вкладку панели и устанавливает фокус ввода на новую таблицу для продолжения работы.
Реализация такого алгоритма у начинающих разработчиков часто вызывает трудности. Возникают ошибки компиляции, путаница в коллекциях элементов управления и непонимание разницы между данными формы и их визуальным представлением. В этой статье мы подробно разберем, как правильно реализовать данный сценарий, проанализируем частые ошибки из практики и рассмотрим готовые решения для обычного и управляемого приложений.
Прежде чем перейти к написанию кода, давайте разберем логическую цепочку действий, которую нам необходимо выполнить по нажатию кнопки:
Теперь проанализируем типичные технические ошибки, с которыми сталкиваются разработчики при реализации этой задачи.
В процессе обсуждения подобных задач на форумах часто всплывают стандартные ошибки. Давайте детально разберем их причины, чтобы не допускать их в своей практике.
Эта ошибка возникает, когда разработчик пытается применить методы управляемого приложения в обычной форме (Толстый клиент). В управляемом интерфейсе все элементы формы доступны через коллекцию Элементы. Однако в обычных формах (до версии 8.2 и в режиме совместимости) для этого используется коллекция ЭлементыФормы.
Попытка вызвать Элементы.ИмяТаблицы в обычном приложении вызовет ошибку компиляции:
{Документ.Циклы.Форма.ФормаДокумента.Форма(50,28)}: Переменная не определена (Элементы)
Решение: В обычном приложении всегда обращаемся к элементам через коллекцию ЭлементыФормы.
Часто в обработчике нажатия кнопки разработчики пишут код вида:
Этаформа.ТекущийЭлемент = Элемент.Таблица1Исп;
Это приводит к ошибке Поле объекта не обнаружено (Таблица1Исп). Выясним причину. В процедуре-обработчике нажатия кнопки Кнопка1Нажатие(Элемент) переменная Элемент — это ссылка на сам объект кнопки, который инициировал событие (то есть на кнопку, по которой кликнули). Естественно, внутри кнопки нет никакой подчиненной таблицы.
Решение: Для поиска таблицы на форме нужно обращаться не к параметру кнопки Элемент, а к коллекции элементов формы: ЭлементыФормы.Таблица1Исп (для обычных форм) или Элементы.Таблица1Исп (для управляемых).
Еще одна классическая ошибка начинающих связана с непониманием разницы между данными (реквизитами) и элементами формы (визуальным интерфейсом):
Этаформа.ТекущийЭлемент = Таблица1Исп; // Ошибка: Недопустимое значение
Свойство формы ТекущийЭлемент отвечает за то, какой именно визуальный элемент управления сейчас активен (куда направлен фокус ввода). Оно ожидает получить именно элемент формы (тип ТабличноеПоле, ПолеВвода и т.д.), но разработчик пытается присвоить ему реквизит данных (тип ТабличнаяЧасть или ТаблицаЗначений).
Сам реквизит данных не является визуальным объектом, поэтому платформа выдает ошибку о недопустимом значении.
Решение: Передавать в ТекущийЭлемент визуальный элемент управления из соответствующей коллекции.
Рассмотрим по шагам правильную реализацию задачи для обычного приложения. Предположим, у нас есть панель закладок с именем ОсновнаяПанель. На первой вкладке расположена таблица-источник ТаблицаТЦ, на второй вкладке — таблица-приемник Таблица1Исп (имя страницы панели — СтраницаТаблица1).
Для оптимизации процесса копирования мы откажемся от ручного присвоения каждого поля и используем эффективную встроенную функцию 1С — ЗаполнитьЗначенияСвойств(). Она автоматически сопоставляет колонки источника и приемника по их именам и переносит значения.
Вот как выглядит профессионально написанный обработчик нажатия кнопки:
Процедура Кнопка1Нажатие(Элемент)
// Шаг 1. Очищаем таблицу-получатель во избежание дублирования данных
Таблица1Исп.Очистить();
// Шаг 2. Переносим данные из источника в получатель
Для Каждого СтрокаИсточника Из ТаблицаТЦ Цикл
// Добавляем новую строку в таблицу-приемник
СтрокаПриемника = Таблица1Исп.Добавить();
// Быстро копируем совпадающие колонки (ИсполняемыйПродукт, Количество и т.д.)
ЗаполнитьЗначенияСвойств(СтрокаПриемника, СтрокаИсточника);
// Если имена колонок отличаются, их можно сопоставить вручную:
// СтрокаПриемника.НоменклатураПриемник = СтрокаИсточника.НоменклатураИсточник;
КонецЦикла;
// Шаг 3. Программное переключение вкладки панели
// Обращаемся к нашей панели закладок через коллекцию "ЭлементыФормы"
ЭлементыФормы.ОсновнаяПанель.ТекущаяСтраница = ЭлементыФормы.ОсновнаяПанель.Страницы.СтраницаТаблица1;
// Шаг 4. Установка фокуса ввода на заполненную таблицу
ЭтаФорма.ТекущийЭлемент = ЭлементыФормы.Таблица1Исп;
КонецПроцедуры
Если вы ведете разработку на современном интерфейсе "Такси" или просто используете управляемые формы, подход к архитектуре кода меняется. В управляемом приложении строго разделяются клиентский контекст (где работает интерфейс) и серверный контекст (где обрабатываются данные).
Процедура нажатия кнопки выполняется на клиенте (&НаКлиенте), но перебор строк табличной части и заполнение данных должны происходить на сервере (&НаСервере) для обеспечения максимального быстродействия. Переключение закладок и фокуса — это чисто клиентские операции.
Давайте проанализируем пример кода для управляемой формы. Здесь коллекция страниц формы объединена в группу с видом "Страницы" (например, ГруппаСтраницы), а сама вкладка представлена группой с видом "Страница" (например, СтраницаТаблица1Исп).
&НаКлиенте
Процедура Кнопка1Нажатие(Команда)
// Шаг 1. Вызываем серверную процедуру для заполнения данных
ЗаполнитьТабличнуюЧастьНаСервере();
// Шаг 2. Программное переключение вкладки на клиенте
Элементы.ГруппаСтраницы.ТекущаяСтраница = Элементы.СтраницаТаблица1Исп;
// Шаг 3. Установка фокуса на таблицу-приемник
ЭтаФорма.ТекущийЭлемент = Элементы.Таблица1Исп;
КонецПроцедуры
&НаСервере
Процедура ЗаполнитьТабличнуюЧастьНаСервере()
// Очищаем коллекцию данных на сервере
Объект.Таблица1Исп.Очистить();
// Обходим строки исходной таблицы
Для Каждого СтрокаИсточника Из Объект.ТаблицаТЦ Цикл
СтрокаПриемника = Объект.Таблица1Исп.Добавить();
// Копируем данные по совпадающим именам реквизитов
ЗаполнитьЗначенияСвойств(СтрокаПриемника, СтрокаИсточника);
КонецЦикла;
КонецПроцедуры
Использование метода ЗаполнитьЗначенияСвойств вместо ручного присвоения параметров (типа Приемник.Поле = Источник.Поле) дает разработчику сразу несколько преимуществ:
Таким образом, мы детально разобрали, как реализовать удобный сквозной процесс переноса данных между таблицами с автоматическим переключением внимания оператора на следующий шаг. Понимание принципов работы с элементами формы и реквизитами данных убережет вас от распространенных ошибок и позволит создавать качественные и интуитивно понятные интерфейсы в 1С.