Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Hello, World!
  
 

Фильтр по датам

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
  
 
Во Флориде и в Королевстве сейчас  14:22[Войти] | [Зарегистрироваться]

MS Word вместо QReport: текст, изображения и списки

Василий Нестеров
дата публикации 19-08-2002 14:22

MS Word вместо QReport: текст, изображения и списки

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

Текст

Сначала о самом простом - добавлении в документ Word нужной строки текста. Поместим на форму компоненты WordDocument , WordApplication и WordParagraphFormat с палитры Servers. Нас интересуют в первую очередь свойство Range компонента WordDocument и свойство Selection компонента WordApplication. Классики утверждают, что они являются ссылкой на объекты Range и Selection. Range представляет из себя, проще говоря, кусок текста, это может быть как весь текст документа, так и любая его часть. Его пределы задаются двумя (или меньше) параметрами типа OleVariant. Например:
var range1, range2, range3, a, b : OleVariant;
...
range1:=WordDocument1.Range;
a:=5;
b:=15;
range2:=WordDocument1.Range(a,b);
range3:=WordDocument1.Range(a); 
Первый наш объект включает в себя весь текст документа, у второго мы ограничили пределы 5-м и 15-м символами, третий представляет из себя весь последующий текст документа, начиная с 5-го символа. Объект имеет несколько полезных методов, например, с его помощью можем добавить текст в документ:
range2.InsertAfter('MS Word'); 
Это мы вставили текст после выделенного Range. Точно также можем вставить текст и перед ним, для этого служит метод InsertBefore(). Текст, заключенный в объекте Range, можем получить так:
WordDocument1.Range(a,b).Text; 

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

a:=5;
b:=15;
WordDocument1.Range(a,b).Font.Bold:=1;
WordDocument1.Range(a,b).Font.Size:=14;
WordDocument1.Range(a,b).Font.Color:=clRed; 
Если хотим отменить выделение жирным шрифтом, присваиваем 0. Аналогично можно сделать шрифт курсивом, подчеркнутым - наберите WordDocument1.Range.Font., и среда сама подскажет, какие могут быть варианты. Методы Select, Cut, Copy и Paste работают как в обычном тексте. С помощью Paste можем на место выбранного Range вставить не только строки, но и рисунок, находящийся в буфере обмена.
WordDocument1.Range(a,b).Select;
WordDocument1.Range(a,b).Cut;
WordDocument1.Range(a,b).Copy;
WordDocument1.Range(a,b).Paste; 

С помощью Range можем найти в документе нужную строку. Пусть в тексте содержится слово "picture". Например, нам на его место надо будет вставить рисунок.

var a, b, vstart, vend: OleVariant;
      j, ilengy: Integer;
...
ilengy:=Length(WordDocument1.Range.Text);
for j:=0 to ilengy-8 do begin
  a:=j;
  b:=j+7;
  if WordDocument1.Range(a,b).Text='picture' then begin
   vstart:=j;
   vend:=j+7;
  end;
end;
WordDocument1.Range(vstart,vend).Select;

Такая процедура находит и выделяет нужный кусок текста.

Теперь про Selection, представляющий из себя выделенный фрагмент документа. Если выделения нет, это текущая позиция курсора в документе. С его помощью можем вставить что-либо на место выделенного фрагмента, сделать выравнивание, изменить шрифт. Он также имеет методы InsertAfter() и InsertBefore():
WordApplication1.Selection.InsertAfter("text1");
WordApplication1.Selection.InsertBefore("text2");
Форматирование выделенного текста происходит аналогично Range, например:
WordApplication1.Selection.Font.Bold:=1;
WordApplication1.Selection.Font.Size:=16;
WordApplication1.Selection.Font.Color:=clGreen;
Для выравнивания проще воспользоваться компонентом WordParagraphFormat. Сначала только нужно "подключить" его к выделенному фрагменту текста:
WordParagraphFormat1.ConnectTo(WordApplication1.Selection.ParagraphFormat);
WordParagraphFormat1.Alignment:=wdAlignParagraphCenter; 
Значения его свойства Alignment может принимать значения wdAlignParagraphCenter, wdAlignParagraphLeft, wdAlignParagraphRight, смысл которых очевиден. Имеются и методы Cut, Copy и Paste, которые в пояснениях вряд ли нуждаются:
WordApplication1.Selection.Cut;
WordApplication1.Selection.Copy;
WordApplication1.Selection.Paste; 
Убираем выделение с помощью метода Collapse. При этом необходимо указать, в какую сторону сместится курсор, будет ли он до ранее выделенного фрагмента или после:
var vcol: OleVariant;
...
vcol:=wdCollapseStart;
WordApplication1.Selection.Collapse(vcol);
При этом выделение пропадет, а курсор займет позицию перед фрагментом текста. Если присвоить переменной значение wdCollapseEnd, то курсор переместится назад. Можно просто поставить в скобках "пустышку":
WordApplication1.Selection.Collapse(EmptyParam); 
Тогда свертывание выделения производится по умолчанию, к началу выделенного текста.

Рисунки

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

Простейший метод вставить в документ рисунок - по упомянутым причинам он же и единственный - скопировать его в Word из буфера обмена. Предположим, рисунок у нас находится в компоненте DBImage. Сначала нужно загнать его в буфер обмена:

Clipboard.Assign(DBImage1.Picture); 
Теперь для его вставки следует воспользоваться методом Paste объектов Range или Selection: WordApplication1.Selection.Paste или WordDocument1.Range(a,b).Paste. Оставить для рисунка достаточное количество пустых строк и попасть в нужное место - это уже наша забота. Если он попадет посреди текста, вид будет довольно противный - при такой вставке обтекание текстом рисунка происходит как-то странно. Можно приготовить для отчета шаблон, где заменяем рисунком какое-либо ключевое слово. О том, как найти в документе нужный текст, см. выше.

А теперь о несколько ином способе вставки рисунка, который устраняет проблемы с обтеканием и дает нам возможность перемещать его по документу, масштабировать и задавать отступы между рисунком и текстом. Способ, собственно, тот же - копируем из буфера обмена, но не прямо в документ, а в "рамку" - текстовую вставку. В ней может находиться не только текст, но и картинка, чем и воспользуемся.
"Рамки" образуют коллекцию Frames, нумеруются целым индексом, пробегающим значения от 1 до WordDocument1.Frames.Count. Добавим в документ рамку, изменим ее размер и вставим рисунок:

Clipboard.Assign(DBImage1.Picture);
vstart:=1;
vend:=2;
WordDocument1.Frames.Add(WordDocument1.Range(vstart,vend));
i:=1;
WordDocument1.Frames.Item(i).Height:=DBImage1.Height;
WordDocument1.Frames.Item(i).Width:=DBImage1.Width;
WordDocument1.Frames.Item(i).Select;
WordApplication1.Selection.Paste;

Здесь для простоты предполагается, что размер DBImage равен размеру самой картинки, а также что до этого рамок у нас в документе не было. Обратить внимание следует на несколько моментов. Размер рамки надо задавать до того, как копировать в нее рисунок. Иначе она будет иметь размер по умолчанию, под который замасштабируется и наша картинка. При попытке изменить размер рамки задним числом размер картинки уже не изменится. Кроме того, параметр Range при добавлении рамки часто никакой роли не играет. Рамка изначально все равно появится в левом верхнем углу документа, а указанный кусок текста при этом не пострадает. Но это только в том случае, если он не выделен. Если в документе есть выделение, рамка появится вместо выделенного фрагмента. Таким образом можем ее вставить в нужное место взамен какого-то ключевого слова.
При желании можем ее подвигать в документе и "вручную". Для этого служат свойства горизонтального и вертикального позиционирования, которые задают ее отступ от левого верхнего "угла" документа:

i:=1;
WordDocument1.Frames.Item(i).VerticalPosition:=30;
WordDocument1.Frames.Item(i).HorizontalPosition:=50; 
Отступ между краями рамки и текстом задается следующим образом:
WordDocument1.Frames.Item(i).HorizontalDistanceFromText:=10;
WordDocument1.Frames.Item(i).VerticalDistanceFromText:=10; 
А теперь о масштабировании. Для этого достаточно длину и ширину рамки умножить на одно и то же число. Например:
WordDocument1.Frames.Item(i).Height:=DBImage1.Height*1.5;
WordDocument1.Frames.Item(i).Width:=DBImage1.Width*1.5;
При этом наша картинка в полтора раза пропорционально растянется. Точно также можно и уменьшить, но делить, как и множить, следует на одно число. Растягивать длину и ширину по-разному у меня лично не получалось. Задавать размер опять-таки надо еще до вставки рисунка. Ну и, наконец, удаление рамки:
WordDocument1.Frames.Item(i).Delete; 

Списки

Списки в документе образуют коллекцию Lists, к отдельному списку обращаемся WordDocument1.Lists.Item(i), где i целое число от 1 до WordDocument1.Lists.Count ... на этом все. Нет методов, позволяющих не то что создать новый список, а даже добавить пункт к уже существующему. Ничего страшного, настоящие герои всегда идут в обход:)) Сейчас мы все же проделаем и то, и другое. Все что нам понадобится - свойство Range отдельного списка, то есть его текст без разделения на пункты, а также возможность его выделить:
WordDocument1.Lists.Item(i).Range.Select;

Для этого в любом случае потребуется заготовка. Неважно, вставлена она в общий шаблонный документ или хранится в отдельном файле. Заготовку делаем так: выбираем в меню Формат/Список, и сохраняем, если это отдельный шаблон списка. У нас появляется пустой список без текста с одним маркером. Далее вспоминаем, как мы делали списки вручную - писали текст, нажимали "Enter", появлялся новый элемент списка. Теперь то же самое, только программно. Предположим, у нас уже открыт документ с заготовкой, и мы хотим внести в список пункты "Item 1" и "Item 2":

var i: Integer;
      vcol: OleVariant;
...
i:=1;
vcol:=wdCollapseEnd;
WordDocument1.Lists.Item(i).Range.Select;
WordApplication1.Selection.Collapse(vcol);
WordApplication1.Selection.InsertAfter('Item 1');
WordDocument1.Lists.Item(i).Range.Select;
WordApplication1.Selection.Collapse(vcol);
WordApplication1.Selection.InsertAfter(#13);
WordDocument1.Lists.Item(i).Range.Select;
WordApplication1.Selection.Collapse(vcol);
WordApplication1.Selection.InsertAfter('Item 2');
WordDocument1.Lists.Items(i).Range.Select;
WordApplication1.Selection.Copy; 
То есть мы вставляем в документ текст первого пункта списка, он попадает на свое место. Потом посылаем в Word символ перехода строки, он честно переходит и тем самым сам создает нам второй пункт списка, куда и вставляем нужную строку. Ну и так далее, нужное количество раз. Последние две строки нужны, если список заготовлен в отдельном файле - после их выполнения список оказывается в буфере обмена. Здесь выгода в том, что можем иметь заготовки списков разных стилей и по ходу дела выбирать, какой список создать. Затем открываем документ, где должен быть список, выделяем с помощью Range нужный кусок, копируем из буфера обмена через WordDocument1.Range(a,b).Paste. Чтобы не испортить файл с заготовкой, можем сразу после открытия пересохранить его под другим именем, а можем просто выйти из него без сохранения изменений
var vsave: OleVariant;
...
vsave:=wdDoNotSaveChanges;
WordDocument1.Close(vsave); 

Константа сохранения изменений может принимать значения

Символьное обозначение Шестнадцатеричное
wdSaveChanges $FFFFFFFF
wdDoNotSaveChanges $00000000
wdPromptToSaveChanges $FFFFFFFE

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

var i,j: Integer;
...
i:=1;
j:=1;
WordDocument1.Lists.Item(i).ListParagraphs.Item(j).Range.Text:='Item 1';
Так что можно с помощью переходов строки создать нужное количество элементов, а затем их заполнить:
WordDocument1.Lists.Item(i).Range.Select;
WordApplication1.Selection.Collapse(vcol);
WordApplication1.Selection.InsertAfter(#13);
j:=1;
WordDocument1.Lists.Item(i).ListParagraphs.Item(j).Range.Text:='Item 1';
j:=2;
WordDocument1.Lists.Item(i).ListParagraphs.Item(j).Range.Text:='Item 2';

Это было в предположении, что у нас один элемент списка в заготовке уже есть. Ну вот, в общем-то, и все про текст, списки и картинки




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

 Обсуждение материала [ 29-01-2009 03:31 ] 27 сообщений
  
Время на сайте: GMT минус 5 часов

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

Web hosting for this web site provided by DotNetPark (ASP.NET, SharePoint, MS SQL hosting)  
Software for IIS, Hyper-V, MS SQL. Tools for Windows server administrators. Server migration utilities  

 
© При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
Все используемые на сайте торговые марки являются собственностью их производителей.

Яндекс цитирования