При разработке интерфейсов в 1С часто возникает необходимость в тесной взаимосвязи между элементами формы. Одной из таких сложных задач является синхронизация не только данных, но и их визуального положения в разных табличных полях. Мы рассмотрим ситуацию, когда необходимо, чтобы при выделении строки в одной таблице, соответствующая ей строка во второй таблице занимала аналогичную визуальную позицию (например, вторая строка снизу видимой области).
Задача кажется простой на первый взгляд, но платформа 1С для управляемых форм предоставляет весьма ограниченные возможности для прямого управления прокруткой и точным позиционированием строк в табличных полях. Давайте разберем, почему это так, и какие подходы можно рассмотреть для частичного решения этой проблемы.
Первоначальный вопрос, который мы поставили, был связан с возможностью узнать номер видимой строки в таблице формы. То есть, если таблица содержит 100 строк, а на экране мы видим только строки с 20 по 40, и выделена третья строка сверху (что соответствует индексу 23 в полной таблице), нам нужен был номер 3. Однако, в платформе 1С для управляемых форм нет прямого программного доступа к индексу первой видимой строки или к функции, которая позволяла бы прокручивать таблицу таким образом, чтобы определенная строка оказалась на заданной визуальной позиции (например, в центре или внизу видимой области).
Основной механизм работы с выделенными строками — свойство ТекущаяСтрока. Если мы устанавливаем это свойство для элемента табличного поля, система гарантирует, что указанная строка станет видимой на экране. Например:
&НаКлиенте
Процедура Таблица1ПриАктивизацииСтроки(Элемент)
// Получаем данные текущей строки из первой таблицы
ТекущиеДанныеТаблицы1 = Элементы.Таблица1.ТекущиеДанные;
Если ТекущиеДанныеТаблицы1 <> Неопределено Тогда
// Находим соответствующую строку во второй таблице по ключу
НайденнаяСтрокаТаблицы2 = Таблица2.Найти(ТекущиеДанныеТаблицы1.Ключ, "Ключ");
Если НайденнаяСтрокаТаблицы2 <> Неопределено Тогда
// Устанавливаем найденную строку как текущую во второй таблице
Элементы.Таблица2.ТекущаяСтрока = НайденнаяСтрокаТаблицы2;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Этот код делает строку видимой и активной во второй таблице, но ее визуальное положение в отображаемой области (сверху, снизу, в середине) остается непредсказуемым. Именно это и было главной проблемой, которую мы пытались решить – нам нужно было не просто сделать строку видимой, а разместить ее "друг напротив друга" или на аналогичной относительной позиции.
Сдвинуть()В ходе обсуждения был предложен метод Сдвинуть(), который присутствует у коллекций объектов, таких как ТабличнаяЧасть или ТаблицаЗначений. Предполагалось, что этот метод может помочь в позиционировании строк. Давайте рассмотрим его подробнее.
Метод Сдвинуть() предназначен для физического перемещения строки внутри коллекции данных, меняя ее индекс. Например, если у нас есть ТаблицаЗначений, и мы хотим переместить строку с индексом X на позицию Y, мы можем использовать этот метод. Пример из обсуждения выглядел так:
// Предполагаемые переменные:
// таб1 - элемент табличного поля первой таблицы
// таб2 - элемент табличного поля второй таблицы
// ТекущиеДанные1 - текущая строка первой таблицы
текданные1 = таб1.ТекущиеДанные;
строкатаб2 = таб2.Найти(текданные1.Ключ, "Ключ"); // Находим строку по ключу
// таб2.Сдвинуть(строкатаб2, таб1.Индекс(текданные1) - таб2.Индекс(строкатаб2));
// Этот код предполагает перемещение строки в коллекции данных, а не скроллинг
// Также необходимо установить текущую строку:
таб2.ТекущаяСтрока = строкатаб2;
Однако, как было верно отмечено, такой подход изменяет логический порядок строк в коллекции данных, а не управляет их визуальным отображением путем прокрутки табличного поля. Автор темы ясно дал понять, что изменение индекса строк недопустимо, так как это нарушит смысл данных. Следовательно, метод Сдвинуть() не подходит для решения задачи визуальной синхронизации без изменения порядка данных.
Еще одним серьезным ограничением, которое мы выявили, является отсутствие стандартных событий на прокрутку табличного поля (например, колесиком мыши). Это означает, что мы не можем отслеживать, когда пользователь прокручивает одну таблицу, и автоматически синхронизировать прокрутку другой. Отсутствие такого события сильно усложняет задачу полной синхронизации прокрутки.
Идея о том, чтобы "активировать нужную строку, и она проскролит" является базовой, но не дает нужного эффекта точного позиционирования. Если строка уже видна, установка ТекущаяСтрока на нее, скорее всего, не изменит ее визуальное положение. Если же строка не видна, она появится где-то в пределах видимости, но ее точное местоположение (например, в центре или вторая снизу) не гарантируется.
В идеале, для эмуляции точного скролла нам потребовались бы следующие возможности:
Некоторые разработчики пытаются использовать косвенный метод для эмуляции скролла, многократно устанавливая ТекущаяСтрока на соседние элементы, чтобы сместить видимую область. Однако это не обеспечивает точного позиционирования, выглядит "дергано" и крайне неэффективно. Для попытки центрирования строки (как вариант, предложенный в обсуждении) можно было бы попробовать такой алгоритм, но без гарантии стабильного результата:
ЦелевойИндекс - КоличествоВидимыхСтрок / 2).ТекущаяСтрока на вычисленный индекс.ТекущаяСтрока на исходную целевую строку.Этот подход может привести к тому, что целевая строка окажется в середине, но нет гарантии, что это будет работать стабильно или даст нужный эффект при наличии иерархии или строк разной высоты.
Одной из причин, почему автор использовал две таблицы, было наличие иерархии в одной из них, в то время как вторая представляла плоский список данных. Если бы не было необходимости в визуальном представлении иерархии (дерева), наиболее простым решением стало бы объединение данных в одну таблицу. Если таблицы имеют одинаковое количество строк и могут быть связаны по ключу, мы можем создать одну динамическую таблицу или таблицу значений, содержащую колонки из обеих исходных таблиц. При этом иерархическое представление пришлось бы пожертвовать или реализовать его в первой колонке объединенной таблицы, что, как отметил автор, не всегда выглядит так, как требуется.
Если же объединение в одну таблицу невозможно из-за специфики визуализации (например, дерева в одной из них), то возникает необходимость в более сложных обходных путях, которые, к сожалению, не обеспечивают полного контроля.
Учитывая выявленные ограничения платформы, мы можем рассмотреть альтернативные подходы, которые не требуют прямого управления скроллом, но обеспечивают удобство работы с двумя связанными таблицами:
ТекущаяСтрока в нужной таблице.
&НаКлиенте
Процедура Таблица1ПриАктивизацииСтроки(Элемент)
// Получаем данные текущей строки из первой таблицы
ТекущиеДанныеТаблицы1 = Элементы.Таблица1.ТекущиеДанные;
Если ТекущиеДанныеТаблицы1 <> Неопределено Тогда
// Устанавливаем отбор для динамического списка, связанного со второй таблицей
Отбор = Элементы.Таблица2.Отбор.Элементы;
Отбор.Очистить();
Если ТекущиеДанныеТаблицы1.Ключ <> Неопределено Тогда
НовыйЭлементОтбора = Отбор.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
НовыйЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Ключ"); // Имя поля, по которому ищем
НовыйЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
НовыйЭлементОтбора.ПравоеЗначение = ТекущиеДанныеТаблицы1.Ключ;
НовыйЭлементОтбора.Использование = Истина;
КонецЕсли;
Элементы.Таблица2.Обновить(); // Обновляем данные второй таблицы
КонецЕсли;
КонецПроцедуры
Данный подход делает вторую таблицу динамичной и отображает только релевантные данные, что часто бывает более функционально, чем попытки точного визуального позиционирования.
В конечном итоге, мы приходим к выводу, что прямых механизмов для точного управления визуальным положением строк в табличном поле управляемой формы 1С не существует. Метод ТекущаяСтрока лишь гарантирует видимость, а Сдвинуть() изменяет порядок данных, а не прокрутку.
Если для нас критически важна полная визуальная синхронизация с точностью до позиции строки (например, "вторая снизу"), то в рамках стандартных средств платформы 1С это скорее всего будет невозможно реализовать без значительных компромиссов или использования неофициальных "хаков", которые могут быть нестабильны и сложны в поддержке. Разработчикам приходится прибегать к косвенным методам, альтернативным способам представления информации или же менять требования к пользовательскому интерфейсу, принимая во внимание ограничения платформы.
В большинстве случаев, наиболее практичным решением будет использование одной объединенной таблицы, если это позволяет логика данных, или применение динамических отборов во второй таблице, чтобы всегда показывать только связанные строки, возможно, единственной строкой вверху списка. Это обеспечивает функциональность и удобство, не пытаясь обойти фундаментальные ограничения платформы по управлению прокруткой.