вторник, 25 мая 2010 г.

Табуляция в ячейке таблицы

Сегодня столкнулся с задачкой: выровнять по разделителю цифры в столбце таблицы. Всё бы ничего, но таблица была сложная, с множеством объединённых ячеек и на 1500 строк (да, бывают и такие таблицы).
Естественно, я не стал это делать вручную, а за 5 минут наваял простенький макрос, который сделал это за меня:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 Sub CellAlignDecimal() Dim oTbl As Table 'Таблица, в которой работаем Dim oCell As Cell 'Ячейка таблицы Dim c As Integer 'Количество столбцов в таблице Set oTbl = Selection.Tables(1) 'Работаем в таблице, где находится курсор Set oCell = oTbl.Range.Cells(1) 'Первая ячейка таблицы c = oTbl.Columns.Count 'Перебор всех ячеек Do 'Обрабатываем ячейки только в последнем столбце If oCell.ColumnIndex = c Then With oCell.Range.ParagraphFormat .Alignment = wdAlignParagraphJustify 'Абзац выравниваем по ширине .FirstLineIndent = 0 'Отступ первой строки убираем .TabStops.ClearAll 'Убираем все отступы табуляции в ячейке 'Ставим позицию табуляции по разделителю посередине ячейки .TabStops.Add oCell.Width / 2, wdAlignTabDecimal, wdTabLeaderSpaces End With End If Set oCell = oCell.Next DoEvents Loop Until oCell Is Nothing End Sub

Макрос простенький, но имеет ряд нюансов работы с таблицей, на которые стоит обратить внимание:

  1. Перебор ячеек я делаю не циклом For или For Each, а циклом Do…Loop Until, выбирая следующую ячейку методом Next. Оказывается, этот способ работает быстрее для таблиц.

  2. Ячейки перебирать нужно во всей таблице, а не только в интересующем нас столбце. Это вызвано тем, что в таблице присутствуют ячейки, объединённые по столбцам и доступ к отдельным столбцам отсутствует. Именно поэтому, чтобы определить в нужном ли столбце находится текущая ячейка, я пользуюсь свойством ColumnIndex, сравнивая его с номером требуемого столбца. В моём случае это последний столбец таблицы. Также хочу обратить внимание, что я записал количество столбцов в отдельную переменную, чтобы не вычислять его каждый раз при сравнении.

  3. Установка табуляции в ячейке таблицы имеет свои особенности. Например, в моём случае табуляция проставилась так:

    Как видно, позиция табуляции находится чуть дальше 16,5 см, если верить линейке, но, если вызывать окно табуляции для данного абзаца, то там будет стоять цифра 1,62 см. Это вызвано тем, что позиция табуляции отсчитывается не от начала страницы, как можно подумать, глядя на линейку, а от начала текста, который этой табуляцией выравнивается. Поэтому в коде позицию табуляции я вычисляю по ширине ячейки (строка 19).

Из полезного, хочу отметить оператор DoEvents, который временно передаёт управление приложению, чтобы оно выполнило накопившиеся задачи и дало знать операционной системе, что всё в порядке. Этот оператор очень хорошо показывает себя именно в таких циклах, где перебор осуществляется внутри больших коллекций элементов.
Макрос сэкономил мне массу времени, но его можно усовершенствовать: добавить диалог ввода номера(ов) столбца(ов), в ячейки которого(ых) нужно обработать. Также, если передавать его неискушённому пользователю, следует предусмотреть проверку, что курсор находится в таблице.
И напоследок. Как быть, если нужно установить позицию табуляции не посередине ячейки, а в другом её месте? Как вычислить это место внутри ячейки? Прежде всего, нужно это место записать в переменную типа Range, а затем, используя метод Range.Information(wdHorizontalPositionRelativeToTextBoundary), получить положение этого диапазона относительно текста ячейки. Пример такого макроса можно посмотреть на форуме wordexpert.ru