Столкнулся давеча с задачей:
- Пользователям сложно смотреть отчёты, в которых много колонок. Им хотелось подсвечивать текущую строку (строку в которую они ткнули мышкой), чтобы с неё взгляд не сбивался на соседние строки.
- Также необходимо, чтобы при выделении пользователем нескольких ячеек из соседних строк, выделялись все эти несколько строк.
- Далее решено было добавить этот механизм ВО ВСЕ отчёты и ПРИ ЭТОМ НИЧЕГО НЕ СЛОМАТЬ (здесь было МНОГО тонкостей - всё подробно откомментил в программном коде).
Поиск решения:
- Установка выделенных строк не подходит, т.к. придётся скидывать выделение произведённое пользователем, и сломается суммирование чисел в выделенных ячейках, т.к. будет выделяться целиком строка.
- Также можно вытащить заголовки строк - но это отъедает лишнее место и для выделения строки, надо тыкать именно в заголовок, а при переходе к ячейке, это выделение слетит и опять ломай глаза для поиска соседних ячеек по строке
- Поэтому выбран вариант обведения строки, лишённый минусов выше, но имеющий дополнительный плюс - внутри обведённой строки, отдельно видно выделенные ячейки, что позволяет фокусировать на них внимание.
- При этом не стал менять цвет обведения по причинам (но при желании это несложно добавить):
- чтобы он не совпал с цветом фона текущей или соседней строки и гарантированно нормально выделялся на фоне строки. А цвет обведения по умолчанию должен изначально удовлетворять данным правилам - поэтому его лучше не трогать.
- выше производительность, не нужно в дополнение сохранять и восстанавливать ещё и цвет границы.
- Вместо того, чтобы обводить ячейки, естественно можно их заливать фоном. Реализация будет почти та же самая, что и предложена в статье. Не стал делать по причинам:
- Но в таком случае есть риск не угадать с фоном, чтобы он одновременно нормально отображался для всех настроек оформления в разных базах.
- Выбранный цвет фона может совпасть с соседним цветом фона.
- Также вероятность найти отчёт, где ячейки имеют разный фон, выше, чем отчёт, где ячейки по-разному обведены. А когда в строке разные настройки ячеек, это несёт доп. сложности, и в производительности кода и в подборе правильного нового фона выделения.
- При заливке фоном мы потеряем то выделение фоном, которое существует и несёт дополнительную информацию. Например, потеряем выделение цветом особой ячейки, или при выделении нескольких строк потеряем чередование цвета строк, которое часто делают для удобства просмотра строк в отчёте.
- Для выделения фоном, надо вычислять и хранить больше данных - хранить данные не только верхней и нижней выделенной строки, но и всех внутренних - чтобы вернуть их потом в исходное положение
Смысл найденного решения:
- получаем выделенные строки
- запоминаем их обведение до наших изменений
- обводим выделенные строки
- снимаем обведение с предыдущих выделенных строк
- ЧТОБЫ НИЧЕГО НЕ СЛОМАТЬ учитываем, что обведение могло быть разным у разных ячеек строки
Распространение решения:
Чтобы решение появилось сразу во всех отчётах, где не переопределена форма отчёта, в общую форму отчёта добавляем программный код ниже. Для отчётов, у которых определена собственная форма отчёта, очевидно, данную настройку надо провести в собственной форме.
&НаКлиенте
Перем ДанныеВыделенныхСтрок;
&НаКлиенте
Процедура ОтчетТабличныйДокументПриАктивизации(Элемент)
// Делаем через обработчик ожидания, чтобы дать возможность выделить несколько строк,
// т.к. событие срабатывает сразу при выделении первой ячейки.
ПодключитьОбработчикОжидания("ВыделитьТеущиеСтроки", 0.1, Истина);
КонецПроцедуры
&НаКлиенте
Процедура ВыделитьТеущиеСтроки()
// 1. Найдём строки, где выделены ячейки
ТекВерх = ОтчетТабличныйДокумент.ТекущаяОбласть.Верх;
ТекНиз = ОтчетТабличныйДокумент.ТекущаяОбласть.Низ;
ОбластьТекСтроки = ОтчетТабличныйДокумент.Область(ТекНиз,,ТекВерх);
// 2. Скинем предыдущее обведение в состояние до нашего вмешательства
Если ДанныеВыделенныхСтрок <> Неопределено Тогда
//2.1. Если выделенные строки не менялись - ничего не делаем
Если ТекВерх = ДанныеВыделенныхСтрок.Верх И ТекНиз = ДанныеВыделенныхСтрок.Низ Тогда
Возврат;
КонецЕсли;
// 2.2. Вернём назад верхнюю границу
// Обнаружена багофича, что если строке целиком вернуть толщину, которая была у неё изначально, то результат будет отличаться от начального.
// Изначально для колонок идущих правее последней колонки (т.е. с номером больше, чем ШиринаТаблицы) Границы не отображаются.
// Но после установки новой границы, начнёт отображаться. Поэтому сначала полностью стираем границу, которую мы установили выделением,
// потом для колонок отчёта (с первой по ШиринаТаблицы) возвращаем сохранённую границу.
// Альтернативный вариант - можно выделять не всю строку, а только колонки с первой по ШиринаТаблицы - но он кажется менее функциональным и интуитивно понятным.
НевидимаяЛиния = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.НетЛинии);
СтрокаВерх = ОтчетТабличныйДокумент.Область(ДанныеВыделенныхСтрок.Верх,, ДанныеВыделенныхСтрок.Верх);
СтрокаВерх.ГраницаСверху = НевидимаяЛиния;
ОбластьВерх = ОтчетТабличныйДокумент.Область(ДанныеВыделенныхСтрок.Верх, 1, ДанныеВыделенныхСтрок.Верх, ОтчетТабличныйДокумент.ШиринаТаблицы);
Если ДанныеВыделенныхСтрок.ГраницаСверху <> Неопределено Тогда
ОбластьВерх.ГраницаСверху = ДанныеВыделенныхСтрок.ГраницаСверху;
Иначе
Для Каждого НастройкиЯчейки Из ДанныеВыделенныхСтрок.УникальныеНастройкиГраницыВерх Цикл
ТекЯчейкаВерх = ОтчетТабличныйДокумент.Область(ДанныеВыделенныхСтрок.Верх, НастройкиЯчейки.НомерКолонки,
ДанныеВыделенныхСтрок.Верх, НастройкиЯчейки.НомерКолонки);
ТекЯчейкаВерх.ГраницаСверху = НастройкиЯчейки.ГраницаСверху;
КонецЦикла;
КонецЕсли;
// 2.3. Вернём назад нижнюю границу
СтрокаНиз = ОтчетТабличныйДокумент.Область(ДанныеВыделенныхСтрок.Низ,, ДанныеВыделенныхСтрок.Низ);
СтрокаНиз.ГраницаСнизу = НевидимаяЛиния;
ОбластьНиз = ОтчетТабличныйДокумент.Область(ДанныеВыделенныхСтрок.Низ, 1, ДанныеВыделенныхСтрок.Низ, ОтчетТабличныйДокумент.ШиринаТаблицы);
Если ДанныеВыделенныхСтрок.ГраницаСнизу <> Неопределено Тогда
ОбластьНиз.ГраницаСнизу = ДанныеВыделенныхСтрок.ГраницаСнизу;
Иначе
Для Каждого НастройкиЯчейки Из ДанныеВыделенныхСтрок.УникальныеНастройкиГраницыНиз Цикл
ТекЯчейкаНиз = ОтчетТабличныйДокумент.Область(ДанныеВыделенныхСтрок.Низ, НастройкиЯчейки.НомерКолонки,
ДанныеВыделенныхСтрок.Низ, НастройкиЯчейки.НомерКолонки);
ТекЯчейкаНиз.ГраницаСнизу = НастройкиЯчейки.ГраницаСнизу;
КонецЦикла;
КонецЕсли;
КонецЕсли;
// 3. При выделении всего документа, дальнейшие действия не требуются.
// Более того, если не сделать эту проверку, то дальше упадём с ошибкой, при попытке получения ячейки с координатами (0,х,0,х)
ВыделенВесьТабДок = ТекВерх = 0 Или ТекНиз = 0;
Если ВыделенВесьТабДок Тогда
// обработка выделенных строк на прошлом шаге для случая, когда ВыделенВесьТабДок = Истина, инициирует событие ПриАктивизации.
// Чтобы не заходить в бесконечный цикл, очистим данные выделенных строк.
ДанныеВыделенныхСтрок = Неопределено;
Возврат;
КонецЕсли;
// 4. Запомним текущие значения обведённости строк
ДанныеВыделенныхСтрок = Новый Структура;
ДанныеВыделенныхСтрок.Вставить("Верх", ТекВерх);
ДанныеВыделенныхСтрок.Вставить("Низ", ТекНиз);
ДанныеВыделенныхСтрок.Вставить("ГраницаСверху", ОбластьТекСтроки.ГраницаСверху);
ДанныеВыделенныхСтрок.Вставить("ГраницаСнизу", ОбластьТекСтроки.ГраницаСнизу);
// В общем случае у разных ячеек строки могут быть разные настройки Границ (настройки обведения)
// и чтобы вернуть их назад, их надо запомнить.
// Свойство ГраницаСверху (и все остальные границы) для области будет иметь значение неопределено,
// если для разных ячеек области у этой границы будут отличаться толщина или тип границы
// Отмечу, что ЦветРамки при этом, может отличаться, и на Границы это никак не повлияет,
// т.к. ЦветРамки является самостоятельным свойством области, как и сама Граница.
УникальныеНастройкиГраницыВерх = Новый Массив;
ДанныеВыделенныхСтрок.Вставить("УникальныеНастройкиГраницыВерх", УникальныеНастройкиГраницыВерх);
Если ОбластьТекСтроки.ГраницаСверху = Неопределено Тогда
Для НомерКолонки = 1 По ОтчетТабличныйДокумент.ШиринаТаблицы Цикл
НастройкиЯчейки = Новый Структура("НомерКолонки, ГраницаСверху");
НастройкиЯчейки.НомерКолонки = НомерКолонки;
ЯчейкаВерх = ОтчетТабличныйДокумент.Область(ТекВерх, НомерКолонки, ТекВерх, НомерКолонки);
НастройкиЯчейки.ГраницаСверху = ЯчейкаВерх.ГраницаСверху;
УникальныеНастройкиГраницыВерх.Добавить(НастройкиЯчейки);
КонецЦикла;
КонецЕсли;
УникальныеНастройкиГраницыНиз = Новый Массив;
ДанныеВыделенныхСтрок.Вставить("УникальныеНастройкиГраницыНиз", УникальныеНастройкиГраницыНиз);
Если ОбластьТекСтроки.ГраницаСнизу = Неопределено Тогда
Для НомерКолонки = 1 По ОтчетТабличныйДокумент.ШиринаТаблицы Цикл
НастройкиЯчейки = Новый Структура("НомерКолонки, ГраницаСнизу");
НастройкиЯчейки.НомерКолонки = НомерКолонки;
ЯчейкаНиз = ОтчетТабличныйДокумент.Область(ТекНиз, НомерКолонки, ТекНиз, НомерКолонки);
НастройкиЯчейки.ГраницаСнизу = ЯчейкаНиз.ГраницаСнизу;
УникальныеНастройкиГраницыНиз.Добавить(НастройкиЯчейки);
КонецЦикла;
КонецЕсли;
// 5. Обведём текущие строки сверху и снизу самой толстой линией.
// Ограничения (встречаются крайне редко): если строка уже обведена самой толстой линией, то при установке курсора на ней, ничего не изменится.
// Избавиться от этого без побочных эффектов невозможно, потому что,
// если в таком случае наоборот убирать обведение, то строка перестанет выделяться на фоне остальных строк.
// Логика подсказывает, что выделенных строк в отчёте должно быть меньшинство, иначе теряется смысл их выделения.
// Поэтому даже если на практике и встретится такой отчёт (а вероятность этого мала),
// то выделение текущей строки в нём всё равно будет приносить, тот результат, которого мы и добивались.
НаибольшаяВозможнаяТолщинаЛинии = 3;//ограничение платформы
Линия = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная, НаибольшаяВозможнаяТолщинаЛинии);
СтрокаВерх = ОтчетТабличныйДокумент.Область(ТекВерх,,ТекВерх);
СтрокаВерх.ГраницаСверху = Линия;
СтрокаНиз = ОтчетТабличныйДокумент.Область(ТекНиз,,ТекНиз);
СтрокаНиз.ГраницаСнизу = Линия;
КонецПроцедуры
Побочное действие (НЕСУЩЕСТВЕННОЕ и встречаются крайне РЕДКО):
- если выделить несколько таблиц внутри одного отчёта, то выделение слетит до выделения первой таблицы. Поэтому при необходимости скопировать несколько таблиц, можно скопировать сначала весь отчёт.
Ограничения и особенности (встречаются крайне редко):
- Если строка уже обведена самой толстой линией, то при установке курсора на ней, ничего не изменится. Избавиться от этого без побочных эффектов невозможно, потому что, если в таком случае наоборот убирать обведение, то строка перестанет выделяться на фоне остальных строк. Логика подсказывает, что выделенных строк в отчёте должно быть меньшинство, иначе теряется смысл их выделения. Поэтому даже если на практике и встретится такой отчёт (а вероятность этого мала), то выделение текущей строки в нём всё равно будет приносить, тот результат, которого мы и добивались.
- Если в выделенной строке есть объединённые по вертикали ячейки, то обведение, в отличие от выделения, не разделит визуально объединённую ячейку на две части, а просто не будет в ней отображаться - в основном такое может быть только в шапке отчёта, где данный функционал и не нужен.
------------------------------------
ИНТЕРЕСНЫХ ВАМ ЗАДАЧ, ПЛОДОТВОРНОЙ РАБОТЫ И ОРИГИНАЛЬНЫХ/ОПТИМАЛЬНЫХ РЕШЕНИЙ!!
Проверено на платформе 8.3.17.1989.