Как предотвратить «сползание» строк в Таблице Значений на форме 1С 7.7 при их программном сдвиге?

Программист 1С v7.7
← На главную

Разработчики, работающие с платформой 1С:Предприятие 7.7, часто сталкиваются с неприятным визуальным эффектом при работе с экранным элементом ТаблицаЗначений. Когда на форме размещена таблица с фиксированным количеством строк (например, 10 строк для интерфейса быстрого подбора), программная установка текущей строки через метод ТекущаяСтрока() заставляет таблицу «ползти». Вместо того чтобы просто переместить курсор, платформа пытается центрировать строку, из-за чего сверху уходят значимые данные, а снизу появляются пустые области. Разберем, почему это происходит и как решить проблему несколькими способами.

Причина возникновения проблемы «Scroll Offset»

Проанализируем ситуацию: элемент управления ТаблицаЗначений в 7.7 является программной оболочкой над стандартным системным объектом Windows (ListView). Когда мы вызываем метод ТекущаяСтрока(НовыйНомер), платформа инициирует внутреннее событие прокрутки. Если индекс строки находится во второй половине видимой области, алгоритм отрисовки 1С пытается обеспечить «запас» видимости снизу. В результате таблица прокручивается вверх, даже если все строки физически помещаются в отведенное на форме пространство. Это создает эффект «сползания» и нарушает строго фиксированный интерфейс.

Решение №1: Метод кратковременной фиксации строк

Это самое эффективное и изящное решение, найденное в процессе обсуждения. Мы можем обмануть движок отрисовки, временно зафиксировав строки. Метод Фиксировать() блокирует прокрутку указанного количества строк. Если мы зафиксируем строки непосредственно перед изменением фокуса, платформа не сможет «прокрутить» таблицу.

Рассмотрим алгоритм реализации по шагам:

  1. Определяем целевой номер строки, куда должен переместиться курсор.
  2. Вызываем метод Фиксировать(КоличествоСтрок), где количество — это индекс новой строки минус один.
  3. Устанавливаем новую текущую строку.
  4. Снимаем фиксацию, чтобы пользователь мог продолжать работу в обычном режиме.

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


Процедура СдвинутьВверх()
    ТекСтр = ТЗ.ТекущаяСтрока();
    Если ТекСтр > 1 Тогда
        // Запоминаем данные, чтобы сдвинуть их физически
        ТЗ.СдвинутьСтроку(-1, ТекСтр);
        НоваяПозиция = ТекСтр - 1;
        
        // Магия фиксации:
        // Фиксируем строки выше текущей, чтобы таблица не дергалась
        ТЗ.Фиксировать(НоваяПозиция - 1, 0);
        
        // Устанавливаем фокус на новую позицию
        ТЗ.ТекущаяСтрока(НоваяПозиция);
        
        // Сбрасываем фиксацию (0 строк)
        ТЗ.Фиксировать(0, 0);
    КонецЕсли;
КонецПроцедуры

Важное примечание: Будьте осторожны с параметрами метода Фиксировать(). Если вы попытаетесь зафиксировать больше строк, чем фактически отображается в элементе управления на форме (например, при изменении шрифта или масштаба экрана), 1С 7.7 может аварийно завершить работу («вылететь»). Поэтому рекомендуется жестко ограничивать размер таблицы на форме и отключать возможность изменения размера окна.

Решение №2: Метод перестановки данных (Data Swap)

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

Выясним причину, почему это удобно: для пользователя визуально строка переместится (данные в ней изменятся), но для системы фокус останется на той же самой строке (например, на 5-й). Поскольку индекс текущей строки не меняется, прокрутка не инициируется.

Проанализируем пример кода для обмена данными между текущей и вышестоящей строками:


Процедура ПереставитьДанныеВверх()
    ТекСтр = ТЗ.ТекущаяСтрока();
    Если ТекСтр <= 1 Тогда
        Возврат;
    КонецЕсли;
    
    ИндексВыше = ТекСтр - 1;
    
    // Перебираем колонки и меняем значения местами
    Для НомКол = 1 По ТЗ.КоличествоКолонок() Цикл
        ИмяКол = ТЗ.ПолучитьПараметрыКолонки(НомКол);
        
        ВремЗнач = ТЗ.ПолучитьЗначение(ТекСтр, ИмяКол);
        ЗначВыше = ТЗ.ПолучитьЗначение(ИндексВыше, ИмяКол);
        
        ТЗ.УстановитьЗначение(ТекСтр, ИмяКол, ЗначВыше);
        ТЗ.УстановитьЗначение(ИндексВыше, ИмяКол, ВремЗнач);
    КонецЦикла;
    
    // Теперь нам нужно переставить курсор на строку выше, 
    // используя метод из Решения №1, либо оставить его на месте.
    // Если оставить на месте, пользователь увидит, как данные "проплывают" мимо курсора.
КонецПроцедуры

Решение №3: Использование внешней компоненты FormEx

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

Рассмотрим преимущества работы с FormEx:

Сравнительный анализ методов

Выберем подходящий вариант в зависимости от ваших задач:

  1. Метод с Фиксировать(): Лучший выбор, если нужно сохранить стандартное поведение 1С и использовать минимум кода. Работает стабильно при условии фиксированного размера шрифта.
  2. Метод подмены данных: Идеален для интерфейсов «кассира», где важно, чтобы курсор всегда находился в одном и том же визуальном секторе экрана.
  3. Использование Йоксель или 1CPP: Если таблица должна быть очень сложной, лучше заменить стандартную ТЗ на ТабличныйДокумент или Grid от 1CPP. Это полностью снимает все ограничения платформы 7.7 на отрисовку.

Резюме: Чтобы интерфейс в 1С 7.7 выглядел профессионально, всегда контролируйте поведение фокуса в таблицах. Использование кратковременной фиксации перед методом ТекущаяСтрока() — это проверенный «костыль», ставший стандартом индустрии для реанимации старых конфигураций.

← На главную