Delphi word объединить ячейки
Delphi site: daily Delphi-news, documentation, articles, review, interview, computer humor.
Работа с таблицами не всегда интересна, но во время формирования отчетности всегда востребована. Для создания таблицы используется хитрая конструкция WordApp.ActiveDocument.Tables.Add, которой нужно передать пять параметров:
После выполнения этого метода курсор перемещается внутрь таблицы, и вы можете начинать ввод данных в первую ячейку. Для движения между ячейками нужно использовать метод Selection.MoveRlght с указанием в качестве первого параметра (точность) значения 12. Если вспомнить табл. 3.1, то точность со значением 12 соответствует движению между ячейками.
В движении между ячейками есть интересные нюансы. Если вы находитесь в самой последней ячейке последней строки и но идее двигаться дальше некуда, при перемещении в следующую ячейку будет создана новая строка. В следующем примере вы увидите это на практике, когда мы создадим таблицу из двух строк, а заполним три строїш.
Если находиться в последней ячейки последней строїш и выполнить перемещение на строку вниз (в качестве точности для метода Move указать 5), то вы выйдете из таблицы и окажетесь справа от нее. После этого можно перейти па строку ниже путем перемещения курсора на одну позицию вправо. Этот вариант мы также рассмотрим в следующем примере.
Итак, давайгс выясним, как создать и заполнить таблицу (рис. 3.17). Я специально добавил заголовок перед таблицей н текст после таблицы, чтобы вы знали, как войти в таблицу и как выйти из нее. Код для создания такого документа показан в листинге 3.29.
Рис. 3.17. Пример программно созданной таблицы
Листинг 3.29. Программное создание таблицы
ShowMessageC'Похоже, что Word не установлен С); exit: end.
// Изменяем стиль текущего абзаца. // потому что он будет в таблице WordApp.Selection.Font.Size.=12; WordApp.Selec tion.Pa ragraphs.Ali gnment:=3: WordApp Selection Font Bold=false:
// Заполнение таблицы WordApp.Selection.Font.Bol d:=true: WordApp.Selection.TypeText('Параметр'). WordApp.Select i on.MoveRight(12.1): WordApp.SelecLion.Font Bold:=lrue. WordApp.Selection.TypeText('Описание'). WordApp.Select i on.MoveRight(12,1); WordApp.Selection TypeText('Name'); WordApp.Select i on .MoveRighU12,1): WordApp.Selecti on.TypeText('Имя шрифта'): WordApp Selection.MoveRight(12.1): WordApp.Selection.TypeText('Size'). WordApp.Selection.MoveRight(12.1): WordApp.Select!on.TypeText('Размер шрифта'):
// Выход из таблицы WordApp Selection Move(5. 1): WordApp Selection.Moved. 1). WordApp Selection.TypeParagraph.
Заголовок таблицы сделан жирным шрифтом кеглем 20, После печати заголовка размер шрифта изменяется на 12 и "жирность" убирается. Зачем? Дело в том, что внутри таблицы для текста используются текущие параметры абзаца, а после печати заголовка текущим стал жирный шрифт размера 20, но такой гекст в ячейках таблицы не нужен.
В представленном примере я указал достаточно интересные параметры создания таблицы.
Ширина таблицы устанавливается в свойстве WordApp.Selection.Range. Что это за свойство? Свойство Range возвращает ширину текущего абзаца, значит, таблица будет создана на всю ширину.
Количество колонок и строк я установил равным двум, а в примере мы заполняем три строки.
Для таблицы по умолчанию установлено поведение -1.
В качестве варианта заполнения устанавливается значение 0, что соответствует фиксированной ширине колонок.
После заполнения таблицы перемещаемся дальше. Мы создали таблицу размером 2x2, то есть с четырьмя ячейками, но при этом перемещаемся и заполняем шесть ячеек. Программа MS Word сама создает новую строку, если таблица заканчивается, а вы требуете переместиться в новую ячейку.
Для выхода из таблицы выполняются две строки:
WordApp.Selection.Move(5. 1): WordApp.Selection.Moved, 1), Первая перемещает курсор на одну строку вниз, но реально курсор оказывается справа от таблицы. Вторая строка двигает курсор вправо, а так как таблица занимает всю ширину и вправо двигаться некуда (да и символов справа нет, чтобы перемещаться по ним), курсор оказывается на следующей за таблицей строке.
Я унаследовал приложение, которое работает, но я хотел бы добавить к нему. Что я хотел бы сделать, так это объединить первую ячейку с 4-й или 5-й ячейкой во 2-м ряду. Шаблон был создан в словах, и с помощью закладок приложение заменяет эти слова информацией из программы. Вторая строка (технически 3-я, но я игнорирую заголовок) использует только 2 из 6 возможных ячеек, причем первая ячейка в основном текстовая, что делает ее едва читаемой. Он заменяет закладки построчно. Таблица является частью шаблона, а не кодом.
Проблема в том, что он использует Word_TLB, к которому я не привык и пару дней искал верное решение моей проблемы. Самое близкое, что я получил, - это объединение всех ячеек в строке.
В любом случае я добавлю несколько фрагментов кода в отношении того, что я считаю актуальным, и всегда могу обновить фоновый код, если это необходимо.
Переменные, используемые в функции (если мне не хватает чего-то очевидного)
Вот где заполняется фактическая строка. Предыдущий раздел просто добавляет данные, но пока ничего не заменяет.
DoRow - это место, где строка заменяется в отношении закладок . Если он находит закладки, он переключает текст.
Этот подход не работает. Я думаю, это потому, что это диапазон строки, однако я не уверен, как перейти от одной ячейки к другой, чтобы я мог объединить все, что между ними.
Если я просто сделаю TRow.Cells.Merge, этот метод объединит все ячейки в строке.
Удалено больше избыточных данных. Не уверен, насколько легко мне будет воспроизвести эту проблему в другом проекте, хотя я мог бы попробовать. Не желая удалять все используемые переменные, я думаю, это могло бы дать мне информацию, необходимую для фактического объединения ячеек.
Возможно следующее (проверено с D7 и Word2007) поможет.
Он показывает, как создать таблицу Word полностью в коде, а затем объединить диапазон ячеек во 2-й строке таблицы. Это намеренно немного длинновато для целей отслеживания. Ваша непосредственная проблема может заключаться в том, что Merge () необходимо вызвать в начальной ячейке диапазона для слияния, и его нужно передать в качестве аргумента, ячейку, на которой нужно завершить слияние.
Даже если приведенный ниже код не решает полностью ваши проблемы, вы можете использовать следующий код для иллюстрации остающейся проблемы, а не свой «живой» код.
Между прочим, единственная причина, по которой я использовал позднее связывание в приведенном ниже коде, заключается в том, что он переработан из моего более раннего ответа. Для справки в будущем, когда вы застряли на чем-то вроде этого, на самом деле проще попробовать и сделать то, что вы используете после раннего связывания (т. Е. С помощью COM-объектов в файле импорта TLB, потому что во время компиляции вы узнаете, действительно ли вы вызвать правильный метод для правильного объекта и предоставить правильные аргументы. Обратной стороной является то, что вы должны предоставить все аргументы, где эквивалент с поздним связыванием может позволить вам предоставить только некоторые из них, например, версия Documents.Open с ранним связыванием требует 12 аргументов, каждому из которых нужно передать OleVariant.
Вы спросили в комментарии о раннем и позднем связывании. Это слишком большая тема, чтобы втиснуться в этот ответ, но по сути это два разных способа взаимодействия с объектами внутри другого приложения (или в DLL).
Позднее связывание - это то место, где вы взаимодействуете с ними, используя варианты. Поддержка автоматизации Delphi скрывает большую часть деталей взаимодействия с этими внешними объектами за своей поддержкой автоматизации посредством позднего связывания. Чтобы автоматизировать таким образом, внешнее приложение должно иметь интерфейсы IDispatch. Позднее связывание обычно начинается с вызова CreateOleObject, чтобы получить ссылку на объект автоматизации верхнего уровня во внешнем приложении.
Позднее связывание легко сделать, но также легко ошибиться, потому что детали интерфейса внешнего объекта скрыты за вариантом (ами), который вы используете с ним, и компилятор Delphi не может использовать его типобезопасность для защиты ты от себя.
Раннее связывание означает использование необработанных интерфейсов, которые предоставляет объект. Обычно это делается с помощью кода в файле импорта TLB, который содержит определения методов и функций интерфейса Object Pascal, что позволяет компилятору обеспечивать безопасность типов и синтаксическую корректность вашего кода. Таким образом, это безопаснее и проще (в некотором смысле) сделать (или, по крайней мере, сделать правильно), и может быть намного быстрее, потому что это сокращает уровень косвенного обращения (через варианты), задействованный при использовании позднего связывания.
Все это и многое другое о Delphi и COM / автоматизации объясняется в книге Эрика Хармона о программировании COM в Delphi, выдержки из которой приведены здесь:
Дамир
дата публикации 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.
Функция может не работать в некоторых версиях броузеров.
© При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
Все используемые на сайте торговые марки являются собственностью их производителей.
Я унаследовал приложение, которое работает, но я хотел бы добавить к нему. То, что я хотел бы сделать, – это слияние с первой на четвертую или пятую ячейку на 2-й строке. Шаблон был создан словом и с помощью закладок приложение заменяет эти слова информацией из программы. Вторая строка (технически 3-я, но я игнорирую заголовок) использует только 2 из возможных 6 ячеек, причем первая ячейка является главным образом текстом, что делает ее едва читаемой. Он заменяет закладки в строке на строку. Таблица является частью шаблона и не создается через код.
Проблема в том, что это использование Word_TLB, к которому я не привык, и проверил пару дней для действительного исправления моей проблемы. Самое близкое, что я получил, это слияние всех ячеек в строке.
В любом случае я добавлю некоторые фрагменты кода в отношении того, что, на мой взгляд, релевантно, и всегда может обновлять с помощью фонового кода, если это необходимо.
Переменные, используемые в функции (В случае, если мне не хватает чего-то очевидного)
Вот где заполняется фактическая строка. В предыдущем разделе просто добавляются данные, которые еще не заменяют.
DoRow – это место, где строка заменяется относительно закладок… Если она находит закладки, она переключает текст.
Этот подход, похоже, не работает. Я думаю, что это потому, что это диапазон строк, однако я не уверен, как добраться из одной ячейки в другую, чтобы я мог объединить все между ними.
Если я просто делаю TRow.Cells.Merge, этот метод объединяет все ячейки в строке.
Возможно, следующее (тестируемое с D7 и Word2007) поможет.
Он показывает, как полностью создать таблицу Word в коде, а затем объединить ряд ячеек в таблице 2-й строки. Это преднамеренно немного укоренилось, для отслеживания целей. Ваша непосредственная проблема может заключаться в том, что Merge() необходимо вызвать в стартовой ячейке span для слияния, и ее необходимо передать в качестве аргумента, ячейка для завершения объединения.
Даже если следующее не полностью решает ваши проблемы, вы можете использовать следующий код, чтобы проиллюстрировать оставшуюся проблему, а не ваш “живой” код.
Кстати, единственная причина, по которой я использовал позднюю привязку в коде ниже, состоит в том, что она переработана из более раннего моего ответа. В будущем, когда вы застряли над чем-то вроде этого, на самом деле проще попробовать и сделать то, что вы используете после раннего связывания (т.е. Использовать COM-объекты в файле импорта TLB, потому что вы обнаруживаете во время компиляции, являетесь ли вы ссылайтесь на правильный метод на правильном объекте и поставьте правильные аргументы. Недостатком является то, что вы должны предоставить все аргументы, в которых эквивалент поздней привязки может позволить вам предоставить только некоторые из них, например раннюю версию Documents.Open требуется 12 аргументов, для которых необходимо передать OleVariant.
Еще один момент заключается в том, что обычный способ решить что-то вроде слияния ячеек с нуля – это записать макрос Word и посмотреть, как он это делает. Обычно это легко может быть переведено в код автоматизации Delphi. Макрос, который я записал, является исключением. Перевод его в Delphi привел к исключению “interface not supported”, поскольку макрос называется Merge для выбора диапазона, который, как представляется, не поддерживает COM-объект.
Вы спросили в комментарии о начале v. Позднего связывания. Это слишком большая тема, чтобы втиснуться в этот ответ, но по сути это два разных способа взаимодействия с объектами внутри другого приложения (или в DLL).
Более поздняя привязка – это то, где вы взаимодействуете с ними, используя варианты. Поддержка автоматизации Delphi скрывает большую часть деталей взаимодействия с этими внешними объектами за поддержкой автоматизации через позднюю привязку. Чтобы быть автоматическим таким образом, внешнее приложение должно обрабатывать интерфейсы IDispatch. Позднее привязка обычно начинается с вызова CreateOleObject, чтобы получить ссылку на объект автоматизации верхнего уровня во внешнем приложении.
Позднее связывание легко сделать, но в равной степени легко ошибиться, поскольку детали интерфейса к внешнему объекту скрыты за вариантами (-ами), которые вы используете с ним, и компилятор Delphi не может использовать свою безопасность типа для защиты вы от себя.
Раннее связывание означает использование необработанных интерфейсов, которые предоставляет объект. Обычно вы делаете это с помощью кода в файле импорта TLB, который содержит определения объектов и методов интерфейса Object Pascal, что позволяет компилятору обеспечить безопасность и синтаксическую корректность вашего кода. Таким образом, это безопаснее и проще (в некотором роде) сделать (или, по крайней мере, получить право), и может быть полезно немного быстрее, потому что он вырезает слой косвенности (через варианты), задействованный при использовании позднего связывания.
Все это и многое другое о Delphi и COM/автоматизации объясняется в книге Эрика Хармона о программировании COM в Delphi, приведенном здесь:
В этой статье мы рассмотрим пример того, как управлять объектами 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 опишем следующие переменные:
Далее проектируем форму:
- Поместим вверх нашей формы кнопку - button1 типа tbutton, поменяем заголовок (св-во Caption) на 'Старт'.
- Под кнопкой разместим панель - panel1 типа tpanel. Внутри панели поместим компонент - bevel1 типа tbevel, поменяем св-во Align на alClient (при этом рамка растянется на всю панель).
- Сверху панели (далее все компоненты будут размещаться внутри этой панели) разместим метку - label1 типа tlabel, поменяем значение св-ва Caption на 'Передать в ячейку':
- Ниже слева поместим метку - label1 типа tlabel, св-во Caption поменяем на 'X='
- Правее метки помещаем компонент Edit1 типа tEdit, св-во Text меняем на '1'
- По правой границе Edit1 помещаем компонент UpDown1 типа tUpDown, в списке св-ва 'Associate' выбираем Edit1, св-во 'Position' приравниваем '1'
- Чуть отступаем вправо и повторяем шаги 4-6 , заменив Edit1 на Edit2, UpDown1 на UpDown2, Label1 на Label2 соответственно.
- Ниже размещаем еще одну метку - label4 типа tlabel, меняем св-во 'Caption' на 'Новое значение ячейки:'
- Ниже размещаем компонент Edit3 типа tEdit, св-во Text меняем на '0'
- И, наконец, в самом низу панели размещаем кнопку BitBtn1 типа tBitBtn, меняем св-во 'Kind' на 'bkOk'.
Теперь напашем обработчики - именно в них и заключается вся функциональность программы:
1. Назначим обработчик OnClick компоненту Button1 :
2. Зададим обработчик формы:
3. Назначим обработчик OnClick компоненту Bitbtn1 :
Дополнительная информация
Справка Word-а (по Visual Basic, по умолчанию она не ставится - запустите заново Setup и поставте в соотв. месте галочку)
- Чарльз Калверт "Delphi 4. Энциклопедия пользователя" (издательство - DiaSoft)
- Марко Кэнту "Delphi4 для профессионалов" (издательство - Питер)
Если у Вас другая версия Word-а:
Параметры ф-ций могут отличаться - обратитесь к справке (см выше) или если у Вас версия Delphi 3 и выше, то используем универсальный метод - пишешь имя объекта, ставишь точку (если нужно посмотреть список параметров у функции , то после открывающей скобки ) , нажимаешь 'ctrl'+'пробел' и изучаешь существующие методы и св-ва.
Читайте также: