Delphi word объединить ячейки

Обновлено: 07.07.2024

Мне необходим компонент для печати данных через ms word.
Фаил макета содержит элементы, которые должны быть при печати заменены данными из БД

Каждый, наверное, хоть раз сталкивался с необходимостью выдачи отчета. В Delphi имеются для этого специальные компоненты, но они налагают на нас достаточно строгие ограничения на форму представления данных. Одним из выходов может служить использование программы MS Word. Здесь не будем подробно обсуждать простейший вопрос, как открыть документ и добавить в него нужную строку текста, это есть практически в каждом учебнике по Delphi, приведем только самые необходимые сведения. А из литературы на эту тему особенно рекомендуется найти книжку А.Я. Архангельского "Язык SQL в Delphi 5". Но что может придать отчету такую читабельность, как представление результатов в систематизированном табличном виде? В данной статье и обсуждается вопрос программной работы с таблицами документа Word.

Тут могут быть два пути. Первый - если мы знаем заранее структуру данных отчета, можем приготовить шаблон, куда в ячейки таблицы затем просто занесем нужные данные. И второй - создаем отчет с нуля, рисуем в документе таблицу, заполняем ее. При этом мы можем программно добавить или удалить строки и столбцы, объединить или разбить ячейки - почти все, что мы делаем в самом Word'e. Все, что понадобится - компоненты WordApplication и WordDocument с палитры Servers

Теперь все по порядку - открываем файл и приступаем. Предварительно объявляем переменную FileName, типа OleVariant, которой присваиваем строку с именем файла.

WordApplication1.Documents.Open(FileName,
EmptyParam, EmptyParam, EmptyParam,
EmptyParam, EmptyParam, EmptyParam,
EmptyParam, EmptyParam, EmptyParam,
EmptyParam, EmptyParam);
WordDocument1.ConnectTo(WordApplication1.ActiveDocument);

Обратите внимание на количество параметров - "пустышек". Их число не совпадает с тем, что обычно приводится в книжках. Объясняется это тем, что "книжная" функция предназначена для MS Word 97, а такая запись для Word 2000 и Word XP.

Создание нового документа выглядит проще:

WordApplication1.Connect;
WordApplication1.Documents.Add(EmptyParam, EmptyParam, EmptyParam, EmptyParam);
WordDocument1.ConnectTo(WordApplication1.ActiveDocument);

Здесь также ставим на пару "пустышек" больше - по тем же самым причинам. Кроме того, полезно будет сразу же отключить проверку орфографии, чтобы Word не тратил время понапрасну:

По окончании работы нам надо сохранить или распечатать наш отчет:

где переменная в скобках типа OleVariant, ей присваиваем строку с именем файла.

В документе нас пока больше всего интересует объект Range, который нам понадобится при создании таблицы. Он представляет из себя кусок текста, который может включать в себя как весь текст документа, так и любую его часть. То есть:

var
range1, range2, range3, a, b: OleVariant;
begin
range1 := WordDocument1.Range;
a := 5;
b := 15;
range2 := WordDocument1.Range(a, b);
range3 := WordDocument1.Range(a);

Первый наш объект включает в себя весь текст документа, у второго мы ограничили пределы 5-м и 15-м символами, третий представляет из себя весь последующий текст документа, начиная с 5-го символа. Объект имеет несколько полезных методов, например, с его помощью можем добавить текст в документ:

Это мы вставили текст после выделенного Range. Точно также можем вставить текст и перед ним, для этого служит метод InsertBefore(). Текст, заключенный в объекте Range, можем получить так:

Кроме того, с помощью Range можем изменить шрифт в пределах объекта. Пример:

Если хотим отменить выделение жирным шрифтом, присваиваем 0. Аналогично можно сделать шрифт курсивом, подчеркнутым - наберите WordDocument1.Range.Font., и среда сама подскажет, какие могут быть варианты. Методы Select, Cut, Copy и Paste работают как в обычном тексте. С помощью Paste можем на место выбранного Range вставить не только строки, но и рисунок, находящийся в буфере обмена.

Работа со столбцами, строками и ячейками

Таблицы в документе Word образуют коллекцию Tables. Их количество можем узнать так:

к отдельной таблице обращаемся по ее номеру:

где i - целое число. В данном случае мы обращаемся к первой таблице, а вообще i может принимать значения от 1 до WordDocument1.Tables.Count. Если нам необходимо создать таблицу самим, следует поступить так:

WordDocument1.Tables.Add(WordDocument1.Range, i, j,
EmptyParam, EmptyParam);

Эта таблица - единственное, что будет в документе, так как она заменяет собой указанный в числе параметров объект Range. В данном случае получаем таблицу на i строк и j столбцов. Если уже еcть какой-то текст, который надо сохранить, совершенно аналогичным образом можем указать пределы объекта Range:

a:=5;
b:=15;
WordDocument1.Tables.Add(WordDocument1.Range(a,b), i, j,
EmptyParam, EmptyParam);

Переменные a и b должны быть объявлены как OleVariant.

Ну вот, теперь у нас есть таблица. Неважно, содержалась она уже в документе или мы создали ее сами. Посмотрим, что же мы с ней можем сделать. Число столбцов и строк узнаем так:

Здесь мы опять обратились к первой таблице, но можем работать с любой - надо только правильно указать ее номер. Теперь изменим ширину столбцов или высоту строк:

Аналогично можем задавать размеры отдельных строк и столбцов:

Здесь j - опять таки целое число, начинается от 1. Можем обратится к отдельной ячейке, прочитать или изменить содержащийся в ней текст:

Здесь j и k целые переменные, изменяются от 1 до числа строк или столбцов соответственно. Присвоив данной величине строковое выражение, увидим, что оно появилось в ячейке (j,k). Несколько непривычно, но в таблицах Word на первом месте стоит именно номер строки. Можем также задать программно отступы от края ячеек, как для всей таблицы сразу, так и для отдельной ячейки:

В данном случае мы задали одинаковые отступы для всей таблицы, но аналогичные четыре свойства есть и у отдельной ячейки. Выделить нужную ячейку, столбец или строку можем следующим образом:

Кроме того, можем подогнать размеры ячеек по содержимому. Для этого вызываем метод AutoFit:

Добавить строку или столбец также не представляет сложностей:

Мы добавили строку внизу и столбец справа. Теперь вставим столбец в определенном месте таблицы:

var
i, j: Integer;
varcol: OleVariant;
begin
j := 2;
varcol := WordDocument1.Tables.Item(i).Columns.Item(j);
WordDocument1.Tables.Item(i).Columns.Add(varcol);

Совершенно аналогично поступаем и со строками. Вообще в скобках указаны строка или столбец, перед которыми происходит вставка. Однако явно указать в скобках почему-то нельзя, надо через переменную.

Теперь про объединение ячеек. Довольно просто:

Мы объединили две соседние по горизонтали ячейки (j,k) и (j,k+1). При этом получается, что большая ячейка как бы имеет два "адреса". Аналогично надо действовать и при объединении по вертикали. Все точно так же, но с нумерацией ячеек после объединения двух соседних по вертикали начинается путаница и при попытке заполнить таблицу возникают ошибки.

Теперь разобьем ячейки.

Здесь мы разбили ячейку (j,k) на две по горизонтали. Переменные varcol и varrow типа OleVariant, это количество столбцов и строк, на которые разбивается данная ячейка. Здесь снова с нумерацией начинается чехарда, так что этот вопрос разбиения и объединения ячеек представляет скорее чисто теоретический интерес. В таких случаях лучше заранее приготовить шаблоны.

Теперь для примера удалим из таблицы второй столбец или третью строку:

Внешний вид таблицы

Простейшая таблица, конечно, смотрится не очень. Теперь посмотрим, как мы можем ее приукрасить. При желании все сделать посимпатичнее можем использовать текстуру. Выглядеть это будет так:

Совершенно аналогично можем сделать текстуру в целом столбце или строке:

Текстура задается шестнадцатеричной константой, список констант можно найти заголовочном файле Word2000.pas. Можно их использовать как в шестнадцатеричном, так и в символьном виде. Чтобы не загромождать материал, значения констант будут выноситься в "Приложение" в конце статьи. Сразу оговорюсь, что заливка будет черно-белая или в шкале серого. Заливку определенным цветом пока так и не удалось обнаружить. Самая первая константа означает отсутствие заливки. Ее можно использовать, чтобы отменить текстуру.

Чтобы выделить что-нибудь важное, можем изменить шрифт текста в определенной ячейке. Для этого воспользуемся свойствами объекта Selection:

В данном примере мы сделали цвет текста в ячейке (1,2) красным, выделили его курсивом и изменили размер на 16. Кроме того, можем сделать шрифт подчеркнутым, перечеркнутым и т.п.

Еще один способ изменить внешний вид таблицы - использовать стилевые шаблоны Word'a. У таблицы имеется метод AutoFormat, который меняет внешний вид таблицы в соответствии с некими предопределенными стилями. В заголовочном файле он описан следующим образом:

procedure AutoFormat(var Format: OleVariant; var ApplyBorders: OleVariant;
var ApplyShading: OleVariant; var ApplyFont: OleVariant;
var ApplyColor: OleVariant; var ApplyHeadingRows: OleVariant;
var ApplyLastRow: OleVariant; var ApplyFirstColumn: OleVariant;
var ApplyLastColumn: OleVariant; var AutoFit: OleVariant);

Первый параметр представляет из себя собственно константу, задающую стиль, а остальные показывают, будут ли требования нового стиля применяться конкретно к границам, тени, шрифту, цвету, первой строке, последней строке, первому столбцу и последнему столбцу. Последний параметр в списке указывает, надо ли подгонять размер ячеек по их содержимому - лучше самому потом вызвать AutoFit.

Как показала практика, работают только два первых параметра. Все остальные заменяем "пустышками". То есть это скорее будет просто способ изменения стиля границ, но и на том спасибо. Некоторые стили таблиц даны в приложении, полный же список ищите в заголовочном файле. Для примера применим к нашей таблице стиль "Вэб3". Вместо второго параметра ставим вариантную переменную, которой присваиваем wdTableFormatApplyBorders. То есть на практике это выглядит так:

var
tformat, tappbrd: OleVariant;
begin
tformat := wdTableFormatWeb3;
tappbrd := wdTableFormatApplyBorders;
i := 1;
WordDocument1.Tables.Item(i).AutoFormat(tformat, tappbrd, EmptyParam,
EmptyParam, EmptyParam, EmptyParam,
EmptyParam, EmptyParam, EmptyParam, EmptyParam);

И еще об одном способе создания таблиц

Людям, интересующимся работой с MS Word, возможно, тоже попадались в интернете компоненты, превращающие в таблицу соответствующим образом отформатированный текст. Вот мы как раз и разберемся, как же они устроены. Здесь нам опять надо вспомнить про объект Range, а именно про имеющийся у него метод ConvertToTable. В заголовочном файле это выглядит так:

function ConvertToTable(var Separator: OleVariant; var NumRows: OleVariant;
var NumColumns: OleVariant; var InitialColumnWidth: OleVariant;
var Format: OleVariant; var ApplyBorders: OleVariant;
var ApplyShading: OleVariant; var ApplyFont: OleVariant;
var ApplyColor: OleVariant; var ApplyHeadingRows: OleVariant;
var ApplyLastRow: OleVariant; var ApplyFirstColumn: OleVariant;
var ApplyLastColumn: OleVariant; var AutoFit: OleVariant;
var AutoFitBehavior: OleVariant; var DefaultTableBehavior: OleVariant)

Здесь опять видим все те же константы применения стиля, что и в автоформате. Только в отличие от него тут они ошибок не вызывают. Правда, есть у меня жуткое подозрение, что они все равно не работают и можем со спокойной совестью поставить вместо них "пустышки" - всех, кроме опять-таки, первых двух параметров "применения изменений". Теперь по порядку. Первый параметр у нас задает символ, которым будут отделяться ячейки одной строки нашей будущей таблицы, второй - число строк таблицы, третий - число столбцов, затем идет ширина столбцов. Следующая группа параметров задает стиль таблицы и особенности его применения, необходимые значения констант есть в таблице "Приложения". Последние три параметра задают подгонку размера ячеек по содержимому, но на самом деле не работают. Так что ставим вместо них EmptyParam. И, наконец, практический пример. Предположим, мы открыли новый документ и занесли в него нужный текст:

Такую операцию повторим трижды, и у нас будет заготовка для таблицы на 4 столбца и 3 строки. Будущие столбцы отделяются символами табуляции, а строки - переходами на новую строку. Теперь выделяем объект Range - в данном случае это весь текст документа, и превращаем его в таблицу:

var
tsepar, tnumrows, tnumcols, tincolw, tformat,
tappbrd, tappshd, tappfnt, tappclr, tapphr, tapplr,
tappfc, tapplc: OleVariant;
begin
tsepar := wdSeparateByTabs;
tnumrows := 3;
tnumcols := 4;
tincolw := 150;
tformat := wdTableFormatNone;
tappbrd := wdTableFormatApplyBorders;
tappshd := wdTableFormatApplyShading;
tappfnt := wdTableFormatApplyFont;
tappclr := wdTableFormatApplyColor;
tapphr := wdTableFormatApplyHeadingRows;
tapplr := wdTableFormatApplyLastRow;
tappfc := wdTableFormatApplyFirstColumn;
tapplc := wdTableFormatApplyLastColumn;

WordDocument1.Range.ConvertToTable(tsepar, tnumrows, tnumcols, tincolw,
tformat, tappbrd, tappshd, tappfnt, tappclr, tapphr, tapplr,
tappfc, tapplc, EmptyParam, EmptyParam, EmptyParam);

В общем-то, мы можем задавать только первые шесть параметров, а все остальные заменить на "пустышки". Единственное, что здесь новенькое, это параметр "разделителя". В данном случае в качестве разделителя будет использоваться символ табуляции. Другие варианты смотрите в последней таблице "Приложения", но мне кажется, особой практической пользы от них нет.

Дамир
дата публикации 19-07-2009 12:43

В статьях, посвященных работе с таблицами Word, как правило, авторы избегают тем, касающихся объединенных ячеек. Оно и понятно: любое обращение к ячейке таблицы, находящейся в объединенной области, приводит к возникновению ошибки. Это внутренняя проблема редактора Word, связанная с архитектурой таблицы, и с этим ничего не поделаешь.

Однажды потребовалось перевести в базу данных нормативные данные, оформленные в редакторе Word в виде таблиц. И сразу же возникли проблемы с объединенными ячейками — как заполучить данные, находящиеся в объединенных ячейках.

Но, оказывается, именно возникновение исключений при обращении к отсутствующим ячейкам и позволяет решить эту проблему. Логика простая: раз возникло исключение при обращении к какой-либо ячейке, значит с этой ячейкой не все гладко. Значит, надо этим воспользоваться. На этом принципе основана методика распознавания таблиц Word, представленная в данной статье.

Для начала создаем запись:

и массивный тип

Данный массив будет характеризовать всю таблицу, а элементы массива — каждую ячейку. Что означают поля записи TWordTableCell, можно догадаться по названиям.

В следующем фрагменте показаны переменные, необходимые для работы с таблицей.

Ядром обработки таблицы является следующая процедура:

Stop on Delphi Exception). Как видно из кода, инициализируются не все поля записи FWordTableCell. Для определения остальных полей производится обработка данных в процедуре CalcWordTableProp:

Итак, заполнены все поля записи FWordTableCell для всех ячеек. Есть информация о каждой ячейке, которой можно воспользоваться, например, чтобы узнать содержимое любой ячейки.

Для демонстрации работы с массивом FWordTableCell воспользуемся компонентом TMStringGrid — аналогом компонента TStringGrid, но с возможностью объединения ячеек. Можно было бы использовать компонент TStringGrid, т.к. он работает гораздо быстрее TMStringGrid, или любой другой подходящий компонент, но так будет нагляднее.

Для объединения ячеек в таблице TMStringGrid предусмотрены функции с перегрузкой:

где ALeft, ATop, ARight, ABottom — координаты левой верхней и правой нижней объединяемых ячеек таблицы TMStringGrid.

Однако, в массиве FWordTableCell эти координаты отсутствуют, и их нужно вычислить по данным массива FWordTableCell.

Для этой цели введем дополнительные типы (данные типы нужны исключительно для подготовки данных для компонента TMStringGrid):

а также, переменные и процедуры:

Здесь процедура CalcGridProps заполняет массив RowCell коллекции TGridCol для каждой ячейки (также вычисляется действительное число колонок таблицы, т.к. FMaxUsedCols не является таковым):

Процедура WriteToGrid формирует копию таблицы Word в компоненте TMStringGrid:

Для демонстрации работы приведенного выше кода была создана программа DemoWordTable.exe (Рисунок 1).



Рисунок 1. Интерфейс программы

Нажав кнопку "Открыть таблицу Word", можно открыть документ Word, содержащий таблицу. Программа считывает первую таблицу и создает ее копию в компоненте TMStringGrid (Рисунок 2).



Рисунок 2. Таблица в Word (на заднем плане) и ее копия на форме MainForm

Кроме того, программа позволяет и обратное действие, т.е. создавать произвольную таблицу на форме и переносить ее в документ Word.

Для изменения числа строк и столбцов, а также фиксированных строк и столбцов предусмотрены поля Edit (После изменения значения в поле Edit нужно нажать "Enter", чтобы изменения вступили в силу). Чтобы объединить какие-либо ячейки, нужно сперва их выделить, удерживая клавишу Shift и нажимая клавиши со стрелками. Затем щелкнуть правой кнопкой мыши. Откроется Popup Menu с кнопками "Объединить ячейки" и "Разбить ячейки" (Рисунок 3.). Нажатие кнопки "Объединить ячейки" приведет к объединению ячеек выделенной области. Если выделения нет, т.е. выделена только одна ячейка, то кнопка "Объединить ячейки" открывает редактор ячеек (Рисунок 4). В редакторе можно выбрать нужные ячейки для объединения, ввести текст, который будет находиться в ячейке и выбрать положение текста в ячейке (TO_LEFT, TO_CENTER, TO_RIGHT).



Рисунок 3. Объединение ячеек



Рисунок 4. Объединение ячеек с помощью редактора

После создания таблицы можно нажать на кнопку "Записать таблицу Word", после чего будет создан новый документ Word, и таблица в нем, которая будет копией созданной таблицы (Рисунок 5).



Рисунок 5. Таблица на форме MainForm (на заднем плане) и ее копия в Word

Напоследок нужно сказать, что есть еще одна уловка при объединении ячеек таблицы Word: если заранее известны все номера ячеек, которые нужно объединить, то объединение нужно начать справа налево, снизу вверх. Тогда объединенные ячейки не спутают индексы ячеек, и все пройдет гладко:

К сожалению, хотя данный метод и работает, но очень уж медленно из за неповоротливости редактора Word.

К статье прилагается пример:


Смотрите также материалы по темам: [Работа с MS Word]

Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
Функция может не работать в некоторых версиях броузеров.

В этой статье мы рассмотрим пример того, как управлять объектами Word-а (Excel - аналогично) из программ на Delphi.

Для чего это нужно ?

Задачи могут быть самые разные, в общем случае это использование возможностей Word-а в своей программе, н-р: проверка текста на орфографию; печать текста, графики; экспорт отчетов в Word или изначальное создание их там и т.д.

Подготовительные работы.

На самом деле существует несколько способов сделать это, мы рассмотрим только один (пример кроме Delphi 5, в Delphi5 для этого есть компоненты на закладке Servers переименуете в программе типы на соответствующие компоненты, дальше так же).

Для начала начнем новый проект File, New Application; File, Save All. Создадим отдельную папку для проекта и сохраним Unit1 как Main, а Project1 как WordWriter.

Далее для работы с Word-ом нам потребуется библиотека типов Word-а, это делается так: Project, Import Type Library, Add, далее переходим в папку, где стоит Word ( у меня это - "c:\program files\microsoft office) , заходим в папку Office и выбираем файл - msword8.olb (цифра -? версии Word-а - у Вас может отличаться ) или excel8.olb (для Excel).Нажимаем Оk. Delphi создаст 2 файла - Word_tlb.pas и Office_tlb.pas, их надо включить в раздел uses модуля Main нашего проекта:

Теперь займемся непосредственно программированием.

В разделе var опишем следующие переменные:

Далее проектируем форму:

  1. Поместим вверх нашей формы кнопку - button1 типа tbutton, поменяем заголовок (св-во Caption) на 'Старт'.
  2. Под кнопкой разместим панель - panel1 типа tpanel. Внутри панели поместим компонент - bevel1 типа tbevel, поменяем св-во Align на alClient (при этом рамка растянется на всю панель).
  3. Сверху панели (далее все компоненты будут размещаться внутри этой панели) разместим метку - label1 типа tlabel, поменяем значение св-ва Caption на 'Передать в ячейку':
  4. Ниже слева поместим метку - label1 типа tlabel, св-во Caption поменяем на 'X='
  5. Правее метки помещаем компонент Edit1 типа tEdit, св-во Text меняем на '1'
  6. По правой границе Edit1 помещаем компонент UpDown1 типа tUpDown, в списке св-ва 'Associate' выбираем Edit1, св-во 'Position' приравниваем '1'
  7. Чуть отступаем вправо и повторяем шаги 4-6 , заменив Edit1 на Edit2, UpDown1 на UpDown2, Label1 на Label2 соответственно.
  8. Ниже размещаем еще одну метку - label4 типа tlabel, меняем св-во 'Caption' на 'Новое значение ячейки:'
  9. Ниже размещаем компонент Edit3 типа tEdit, св-во Text меняем на '0'
  10. И, наконец, в самом низу панели размещаем кнопку BitBtn1 типа tBitBtn, меняем св-во 'Kind' на 'bkOk'.

Теперь напашем обработчики - именно в них и заключается вся функциональность программы:

1. Назначим обработчик OnClick компоненту Button1 :

2. Зададим обработчик формы:

3. Назначим обработчик OnClick компоненту Bitbtn1 :

Дополнительная информация

Справка Word-а (по Visual Basic, по умолчанию она не ставится - запустите заново Setup и поставте в соотв. месте галочку)

  • Чарльз Калверт "Delphi 4. Энциклопедия пользователя" (издательство - DiaSoft)
  • Марко Кэнту "Delphi4 для профессионалов" (издательство - Питер)

Если у Вас другая версия Word-а:

Параметры ф-ций могут отличаться - обратитесь к справке (см выше) или если у Вас версия Delphi 3 и выше, то используем универсальный метод - пишешь имя объекта, ставишь точку (если нужно посмотреть список параметров у функции , то после открывающей скобки ) , нажимаешь 'ctrl'+'пробел' и изучаешь существующие методы и св-ва.

Читайте также: