Delphi word копировать текст
Предположим, у нас уже открыт файл. Вопросы открытия и сохранения документов уже были в других статьях, так что подробно на этом останавливаться не будем. Просто по ходу дела будет приведено то, чего раньше не встречалось - выход из документа без сохрания изменений. Как-то забыл, извините:)
Сначала о самом простом - добавлении в документ Word нужной строки текста. Поместим на форму компоненты WordDocument, WordApplicationи WordParagraphFormat с палитры Servers. Нас интересуют в первую очередь свойство Range компонента WordDocument и свойство Selection компонента WordApplication. Классики утверждают, что они являются ссылкой на объекты Range и Selection. Range представляет из себя, проще говоря, кусок текста, это может быть как весь текст документа, так и любая его часть. Его пределы задаются двумя (или меньше) параметрами типа OleVariant. Например:
Первый наш объект включает в себя весь текст документа, у второго мы ограничили пределы 5-м и 15-м символами, третий представляет из себя весь последующий текст документа, начиная с 5-го символа. Объект имеет несколько полезных методов, например, с его помощью можем добавить текст в документ:
Это мы вставили текст после выделенного Range. Точно также можем вставить текст и перед ним, для этого служит метод InsertBefore(). Текст, заключенный в объекте Range, можем получить так: WordDocument1.Range(a,b).Text; Кроме того, с помощью Range можем изменить шрифт в пределах объекта. Пример:
Если хотим отменить выделение жирным шрифтом, присваиваем 0. Аналогично можно сделать шрифт курсивом, подчеркнутым - наберите WordDocument1.Range.Font., и среда сама подскажет, какие могут быть варианты. Методы Select, Cut, Copy и Paste работают как в обычном тексте. С помощью Paste можем на место выбранного Range вставить не только строки, но и рисунок, находящийся в буфере обмена.
С помощью Range можем найти в документе нужную строку. Пусть в тексте содержится слово "picture". Например, нам на его место надо будет вставить рисунок.
Такая процедура находит и выделяет нужный кусок текста.Теперь про Selection, представляющий из себя выделенный фрагмент документа. Если выделения нет, это текущая позиция курсора в документе. С его помощью можем вставить что-либо на место выделенного фрагмента, сделать выравнивание, изменить шрифт. Он также имеет методы InsertAfter() и InsertBefore():
Форматирование выделенного текста происходит аналогично Range, например:
Для выравнивания проще воспользоваться компонентом WordParagraphFormat. Сначала только нужно "подключить" его к выделенному фрагменту текста:
Значения его свойства Alignment может принимать значения wdAlignParagraphCenter, wdAlignParagraphLeft, wdAlignParagraphRight, смысл которых очевиден. Имеются и методы Cut, Copy и Paste, которые в пояснениях вряд ли нуждаются:
Убираем выделение с помощью метода Collapse. При этом необходимо указать, в какую сторону сместится курсор, будет ли он до ранее выделенного фрагмента или после:
При этом выделение пропадет, а курсор займет позицию перед фрагментом текста. Если присвоить переменной значение wdCollapseEnd, то курсор переместится назад. Можно просто поставить в скобках "пустышку":
Тогда свертывание выделения производится по умолчанию, к началу выделенного текста. РисункиЛогично было бы предположить, что рисунки документа будут представлять из себя коллекцию, аналогичную таблицам, и мы, обратившись к конкретной картинке, сможем менять ее свойства - обтекание, размер и т.д. Однако ничего подобного в WordDocument не обнаруживается. Потому возможности управления встраиваемыми в документ изображениями сильно ограничены. Простейший метод вставить в документ рисунок - по упомянутым причинам он же и единственный - скопировать его в Word из буфера обмена. Предположим, рисунок у нас находится в компоненте DBImage. Сначала нужно загнать его в буфер обмена:
Теперь для его вставки следует воспользоваться методом Paste объектов Range или Selection: WordApplication1.Selection.Paste или WordDocument1.Range(a,b).Paste. Оставить для рисунка достаточное количество пустых строк и попасть в нужное место - это уже наша забота. Если он попадет посреди текста, вид будет довольно противный - при такой вставке обтекание текстом рисунка происходит как-то странно. Можно приготовить для отчета шаблон, где заменяем рисунком какое-либо ключевое слово. О том, как найти в документе нужный текст, см. выше. А теперь о несколько ином способе вставки рисунка, который устраняет проблемы с обтеканием и дает нам возможность перемещать его по документу, масштабировать и задавать отступы между рисунком и текстом. Способ, собственно, тот же - копируем из буфера обмена, но не прямо в документ, а в "рамку" - текстовую вставку. В ней может находиться не только текст, но и картинка, чем и воспользуемся.
"Рамки" образуют коллекцию Frames, нумеруются целым индексом, пробегающим значения от 1 до WordDocument1.Frames.Count. Добавим в документ рамку, изменим ее размер и вставим рисунок:
Здесь для простоты предполагается, что размер DBImage равен размеру самой картинки, а также что до этого рамок у нас в документе не было. Обратить внимание следует на несколько моментов. Размер рамки надо задавать до того, как копировать в нее рисунок. Иначе она будет иметь размер по умолчанию, под который замасштабируется и наша картинка. При попытке изменить размер рамки задним числом размер картинки уже не изменится. Кроме того, параметр Range при добавлении рамки часто никакой роли не играет. Рамка изначально все равно появится в левом верхнем углу документа, а указанный кусок текста при этом не пострадает. Но это только в том случае, если он не выделен. Если в документе есть выделение, рамка появится вместо выделенного фрагмента. Таким образом можем ее вставить в нужное место взамен какого-то ключевого слова.
При желании можем ее подвигать в документе и "вручную". Для этого служат свойства горизонтального и вертикального позиционирования, которые задают ее отступ от левого верхнего "угла" документа:
А теперь о масштабировании. Для этого достаточно длину и ширину рамки умножить на одно и то же число. Например:
При этом наша картинка в полтора раза пропорционально растянется. Точно также можно и уменьшить, но делить, как и множить, следует на одно число. Растягивать длину и ширину по-разному у меня лично не получалось. Задавать размер опять-таки надо еще до вставки рисунка. Ну и, наконец, удаление рамки:
Списки Списки в документе образуют коллекцию Lists, к отдельному списку обращаемся WordDocument1.Lists.Item(i), где i целое число от 1 до WordDocument1.Lists.Count . на этом все. Нет методов, позволяющих не то что создать новый список, а даже добавить пункт к уже существующему. Ничего страшного, настоящие герои всегда идут в обход:)) Сейчас мы все же проделаем и то, и другое. Все что нам понадобится - свойство Range отдельного списка, то есть его текст без разделения на пункты, а также возможность его выделить:
Для этого в любом случае потребуется заготовка. Неважно, вставлена она в общий шаблонный документ или хранится в отдельном файле. Заготовку делаем так: выбираем в меню Формат/Список, и сохраняем, если это отдельный шаблон списка. У нас появляется пустой список без текста с одним маркером. Далее вспоминаем, как мы делали списки вручную - писали текст, нажимали "Enter", появлялся новый элемент списка. Теперь то же самое, только программно. Предположим, у нас уже открыт документ с заготовкой, и мы хотим внести в список пункты "Item 1" и "Item 2":
То есть мы вставляем в документ текст первого пункта списка, он попадает на свое место. Потом посылаем в Word символ перехода строки, он честно переходит и тем самым сам создает нам второй пункт списка, куда и вставляем нужную строку. Ну и так далее, нужное количество раз. Последние две строки нужны, если список заготовлен в отдельном файле - после их выполнения список оказывается в буфере обмена. Здесь выгода в том, что можем иметь заготовки списков разных стилей и по ходу дела выбирать, какой список создать. Затем открываем документ, где должен быть список, выделяем с помощью Range нужный кусок, копируем из буфера обмена через WordDocument1.Range(a,b).Paste. Чтобы не испортить файл с заготовкой, можем сразу после открытия пересохранить его под другим именем, а можем просто выйти из него без сохранения изменений
Константа сохранения изменений может принимать значения
Символьное обозначение | Шестнадцатеричное |
wdSaveChanges | $FFFFFFFF |
wdDoNotSaveChanges | $00000000 |
wdPromptToSaveChanges | $FFFFFFFE |
Первое значение сохраняет изменения, второе дает возможность выйти без сохранения изменений. Последняя константа вызывает при выходе стандартный диалог сохранения изменений. Можем сделать и несколько по-другому. Хотя мы не можем создать новый элемент списка, но текст в уже существующем изменить можно:
Так что можно с помощью переходов строки создать нужное количество элементов, а затем их заполнить:
Это было в предположении, что у нас один элемент списка в заготовке уже есть. Ну вот, в общем-то, и все про текст, списки и картинкиСтатистика документовВ данном небольшом материале рассматривается вопрос подсчета статистики файлов *.doc и *.rtf. Такой вопрос у меня возник, когда пришлось сделать небольшую базу данных по учету документов, куда надо было заносить и статистику документа - число знаков, слов и т.п. Открывать каждый раз Word, считать статистику и забивать ее в форму ввода было лень, так что пришла в голову мысль это дело автоматизировать. Информации по данному вопросу найти так и не удалось, так что основным источником знаний служили заголовочный файл Word2000.pas и справка по Visual Basic for Applications. Ну и, конечно, множество разных экспериментов. Сразу оговорюсь, что я не профессиональный программист, так что в тонкости интерфейсов вникать не будем - сам в них не особо разбираюсь. Потому, не мудрствуя лукаво, просто поместим на форме компоненты WordApplication и WordDocument с палитры Servers. Для работы используются свойства и методы этих компонентов. Встроенная статистика Word подсчитывает статистику обычного текста, обычных и концевых сносок. Для подсчета статистики используется метод компонента WordDocument ComputeStatistic(). Он имеет один параметр, характеризующий, что именно считать, представляющий из себя шестнадцатеричную константу. Константы описаны в заголовочном файле Word2000.pas, он лежит обычно в /Delphi/Ocx/Servers.
Шестнадцатеричная | Символьное обозначение | Смысл |
$00000000 | wdStatisticWords | Количество слов |
$00000001 | wdStatisticLines | Количество строк |
$00000002 | wdStatisticPages | Количество страниц |
$00000003 | wdStatisticCharacters | Знаки без пробелов |
$00000004 | wdStatisticParagraphs | Количество разделов |
$00000005 | wdStatisticCharactersWithSpaces | Знаки с пробелами |
Это было основное, что надо знать. Ну а теперь по порядку. Поместив на форму упомянутые компоненты, видим, что свойств и методов у них совсем мало. В первую очередь следует определиться с методом ConnectKind компонента WordApplication. Оно может принимать различные значения, но мы оставим присваемое по умолчанию значение ckRunningOrNew. Это означает, что соединение происходит с уже работающим сервером, при его отсутствии запускается новый. Как правило, это вполне устраивает. Первым делом откроем документ. Предварительно надо объявить переменную FileName, она будет типа OleVariant, которой присвоим строку с именем файла.
Обратите внимание на количество параметров-"пустышек". Их число больше того, которое обычно приводится в книжках. Ну, в моих, во всяком случае. Объясняется это тем, что "книжные" функции предназначены для MS Word 97, а такая запись для работы с Word 2000 и Word XP. "Plain Text"Объявив нужное количество переменных типа LongInt (в очень большом файле или при суммировании по нескольким документам в принципе может оказаться больше знаков, чем пределы обычного целого типа), можем уже и приступать к подсчету. Например, посчитаем число слов, знаков с пробелами и без пробелов обычного текста, а также количество страниц в документе. Результаты сохраним соответственно в "длинных" переменных
Открыв нужный документ в Word'е и вызвав диалог подсчета статистики, нетрудно увидеть, что значения переменных равны параметрам вордовской статистики со сброшенным флажком "Учитывать все сноски". СноскиСноски в документах могут быть обычные и концевые. То есть если первые располагаются внизу данной страницы, то концевые - строго в конце документа. Кроме того, они могут отличаться и нумерацией - автоматической или заданной пользователем. Начнем с обычных сносок как с самого простого. В терминологии объектной модели Word - Footnotes. Сначала надо вычислить количество самих сносок:
Подсчет статистики текста в сноске производится так:
Здесь ifoot - целое число, "нумерующее" сноску. Для того, чтобы учесть сами номера сносок, сделаем так:
Это мы посчитали для примера количество слов в сноске с номером ifoot и ее метке - при пользовательской нумерации в качестве "номера" может быть целое предложение. Далее начинаем перебирать их одну за другой. При этом следует учесть, что кроме статистики сносок необходимо получить и статистику их "номеров". То есть:
Прибавление единицы появляется оттого, что сумма статистики сносок и номеров не совпадает с тем, что выдает встроенная статистика Word. Между номером сноски и текстом сноски Word ставит пробел, который почему-то не учитывается. Условный оператор определяет, как пронумерована данная сноска - по умолчанию или нет. В последнем случае следует проверить количество слов в обозначении сноски. Такая схема дает результат, совпадающий со показаниями встроенной статистики. Кроме того, цикл у нас идет от 1 - так начинается нумерация сносок в MS Word, да и практически всех остальных объектов тоже.Теперь перейдем к концевым сноскам. Теоретически все то же самое, только вместо слова "Footnotes" пишем "Endnotes". И тут наталкиваемся на сюрприз - почему-то оно считает неточно. Я в данном случае поступил так: сохраняю документ под другим именем, переконвертирую концевые сноски в обычные и далее все, как сказано выше. Сохранение документа:
где в скобках стоят два параметра типа OleVariant - имя файла и шестнадцатеричная константа, задающая формат файла. Некоторые константы:
Шестнадцатеричная | Символьное обозначение | Смысл |
$00000000 | wdFormatDocument | Документ Word |
$00000004 | wdFormatDOSText | Простой текст |
$00000006 | wdFormatRTF | Файл RTF |
Полный список констант формата можно найти все в том же файле Word2000.pas. И еще один интересный момент - если просто поставить в скобки обе константы, работать не будет. Следует предварительно объявить две переменных, присвоить им соответствующие значения и только потом сохранять. Ну, а теперь, собственно, можем вернуться к сноскам. Конвертирование концевых сносок в обычные происходит так:
Теперь мы имеем документ, в котором содержатся только обычные сноски. С ними никаких проблем не возникает, пример, как с ними работать, см. выше. Если интересует статистика отдельно разных типов сносок, считаем предварительно статистику обычных сносок, сохраняем ее в "буферных" переменных и считаем еще раз после конвертирования. Разница даст статистику концевых сносок по отдельности. Сложив статистику сносок и простого текста, получаем статистику документа с учетом сносок так, как ее дает сам Word. Дополнительно. Тут по традиции несколько покритикуем Microsoft. Как оказалось, Word показывает не все, что содержится в документе. Не принимаются в расчет колонтитулы. А ведь в них может содержаться изрядный кусок текста, особенно в справках, бланках и т.п. Оказывается, Word их на самом деле считает, но нам не показывает. Вот и посмотрим, как же его можно заставить это сделать. Колонтитулы в документе тесно связаны с несколько загадочной штукой под названием "разделы" - Sections. Каждый раздел может иметь верхние и нижние колонтитулы. Потому первым делом определяем количество абзацев.
Здесь у нас целые переменные isectct, icofct, icohct обозначают соответственно количество разделов как таковых, количество нижних и верхних колонтитулов данного раздела. Переменная isec служит "номером" раздела, переменные icof, icoh "нумеруют" соответственно нижние и верхние колонтитулы в пределах данного раздела. Количество колонтитулов в разделе определяем так:
Теперь уже можем "достать" текст из колонтитула:
В данном случае мы для примера посчитали число слов, содержащихся в нижнем колонтитуле под номером icof, принадлежащем разделу под номером isec. Теперь можем написать "двойной" цикл для подсчета статистики верхних и нижних колонтитулов.
← →O'ShinW © ( 2013-01-22 16:19 ) [0]
Запущен Ворд W
W := CreateOleObject("Word.Application");
Есть документ образец D1
D1 := W.Documents.Open(Pattern);
Есть новый документ D2
D2 := W.Documents.Add;
Хочу в новом документе D2 наделать страниц по образцу D1
while not(DS.Eof) do
begin
Copy1Paste2(W, D1, D2, a, b);
W.Selection.InsertBreak(OleVariant(7));
W.Selection.Start := a;
W.Selection.End := b;
ReplaceByRecord(W, DS);
DS.Next;
end;
procedure TWordExporter.Copy1Paste2(W, D1, D2: Variant; a,b:Integer);
begin
D1.Activate;
D1.Range(a, b).Select;
W.Selection.Copy;
D2.Activate;
W.Selection.Paste;
end ;
все работает. Но есть нюанс..
W.Selection.Copy помещает копируемое в системный буфер обмена, и если переключится на любое другое приложение, что-то скопировать в буфер и вставить, то вставится не ожидаемое, а содержимое шаблонного документа D1(равно как и скопированное в другом приложении может быть вставлено в D2).
Пытался писать
COPY_TEMPL := W.Selection;
но потом в
COPY_TEMPL.paste;
получаю ошибку "Объект уничтожен"
sniknik © ( 2013-01-22 16:26 ) [1]
> Пытался писать
> .
нафига. че то смысл ускользает. напиши комментарии к своим действиям.
> помещает копируемое в системный буфер обмена
ну так, сохрани "системный буфер обмена" до, восстанови после. не?
clickmaker © ( 2013-01-22 16:33 ) [2]
а просто значение из Д1 нельзя присвоить в Д2 что-ли?
← →sniknik © ( 2013-01-22 16:36 ) [3]
у selection-ов куча методов кроме Copy и Paste вообще то (работать н вариантами а интерфейсами). например есть Text т.е. -
W2.Selection.Text:= W1.Selection.Text;
должно сработать.
O'ShinW © ( 2013-01-22 16:38 ) [4]
> нафига. че то смысл ускользает. напиши комментарии к своим
> действиям.
D1 := W.Documents.Open(Pattern);
D1.Range(a, b).Select;
COPY_TEMPL := W.Selection; //один раз, не в буфер взять, а в переменную
и потом
while not(DS.Eof) do
begin
COPY_TEMPL.paste; // только вставлять, не копируя каждый раз
W.Selection.InsertBreak(OleVariant(7));
W.Selection.Start := a;
W.Selection.End := b;
ReplaceByRecord(W, DS);
DS.Next;
end;
----------
> ну так, сохрани "системный буфер обмена" до, восстанови
> после. не?
т.е. имеешь ввиду, аля так:
procedure TWordExporter.Copy1Paste2(W, D1, D2: Variant; a,b:Integer);
begin
D1.Activate;
PUSH_BUFF;
D1.Range(a, b).Select;
W.Selection.Copy;
D2.Activate;
W.Selection.Paste;
POP_BUFF;
end;
?
но могут поместить что-то в буфер м/д этими действиями.
O'ShinW © ( 2013-01-22 16:42 ) [5]
> а просто значение из Д1 нельзя присвоить в Д2 что-ли?
нет
в d2 на выходе много листов, оформленных по образцу из d1
>> W2.Selection.Text:= W1.Selection.Text;
тогда разметка сбивается
O'ShinW © ( 2013-01-22 16:45 ) [6]
> но могут поместить что-то в буфер м/д этими действиями.
тогда хук?
ну ,на изменение буфера..
> COPY_TEMPL.paste; // только вставлять, не копируя каждый раз
а оно и не копируется каждый раз, если ты этого не сделал. (а бы делаешь см. Copy1Paste2).
sniknik © ( 2013-01-22 16:50 ) [9]
>>> W2.Selection.Text:= W1.Selection.Text;
> тогда разметка сбивается
еще раз
> у selection-ов куча методов кроме Copy и Paste вообще то (работать н вариантами а интерфейсами). например есть Text т.е. -
не? т.е. пример работает, т.е. правда, почему не посмотреть остальное?
sniknik © ( 2013-01-22 16:53 ) [10]
> смотрел.. Все через буфер идет
врешь. давай возьмем например Text . буфер меняется .
O'ShinW © ( 2013-01-22 17:05 ) [11]
> врешь. давай возьмем например Text . буфер меняется ??
> ?
нет. Но и не работает, форматирование другое получается.
> а оно и не копируется каждый раз, если ты этого не сделал.
Copy1Paste2. - это я так сейчас написал.
Раньше постоянно не копировал заново, копировал один раз.
и любое использование буфера плодило тысячи страниц с содержимым отличным от D1, равным тому ,что скопировали в буфер.
> у selection-ов куча методов кроме Copy и Paste вообще то
Хорошо, взял я текст. Он вставится. только будет не
Адрес
Дорогой, ФИО
(Логотип(картинка))
Адрес
Дорогой, ФИО
clickmaker © ( 2013-01-22 17:11 ) [12]
так форматирование, вроде как, отдельно можно взять-присвоить.
← →sniknik © ( 2013-01-22 17:13 ) [13]
> нет. Но и не работает
работает. так как ему положено, это текст. не самообманывайся, называй вещи своими именами.
> Хорошо, взял я текст. Он вставится. только будет не
я тебе не навязываю текст, я его как пример привел. и ты не делай одолжений "хорошо беря" его, тебе очевидно нужно другое . еще раз - там КУЧА методов.
sniknik © ( 2013-01-22 17:15 ) [14]
> так форматирование, вроде как, отдельно можно взять-присвоить.
там не только форматирование, там вообще все что ворд делает можно извне "дергая за веревочки" реализовать. теоретически. т.к. как конкретно это надо разбираться, а это дело пишущего.
O'ShinW © ( 2013-01-22 17:26 ) [15]
> работает. так как ему положено, это текст. не самообманывайся,
> называй вещи своими именами.
Что так будет работать - я знаю. Поэтому и даже не рассматривал вариант.
> тебе очевидно нужно другое . еще раз - там КУЧА методов
Открыл макрос, набрал Selection(.) посмотрел.
не очень много.
Некоторые уже пробовал (класс писался мной еще год назад, тогда ни к чему н пришел, помнится. Просто сейчас решил дописать по-человечески)
> и ты не делай одолжений
мне совершенно незачем повышать шрифт :) на кого бы то ни было, тем более на такого уважаемого мной человека, как ты.
Сказал же так, потому чт ты настойчиво предлагал использовать TEXT (хоть и , например)
> так форматирование, вроде как, отдельно можно взять-присвоить.
наверное..
но потом, скорее всего, придется прыгать по абзацам, строкам вручную..
т.е. не получится вроде такого
format := такой, text := такой
и 1:1 по образцу.
sniknik © ( 2013-01-22 17:34 ) [16]
> Открыл макрос, набрал Selection(.) посмотрел.
> не очень много.
не поленился, повторил, посчитал - 159 свойств/методов вперемешку, разделать/считать вложенные от "подобьектов" не стал.
да, мизер совсем.
O'ShinW © ( 2013-01-22 17:35 ) [17]
да..
воот :)
поэтому, я сразу и спросил, как бы мне
>Копировать из одного документа MSWord в другой, без буфера обмена
Например, один из вариантов, который представляется простым, имхо:
Весь selection насильно переписать в другую, не глобальную переменную,
может ей выделить, установить размер подходящий, и просто переместить туда из selection всё.
т.е. тот же
COPY_TEMPL := W.Selection;
но "вручную"
не приравнять указатель, а создать/ наполнить
O'ShinW © ( 2013-01-22 17:37 ) [18]
17 к 14
к 16
159 свойств/методов - это всего.
Там про Copy|PAste и аналогичных - немного
sniknik © ( 2013-01-22 17:41 ) [19]
> Там про Copy|PAste и аналогичных - немного
где логика? ты пишешь о проблеме с ними, хочешь по другому, а ищешь среди аналогичных. хотя искать нужно как раз во всех оставшихся.
sniknik © ( 2013-01-22 17:44 ) [20]
> всех оставшихся
НАПРИМЕР в "Text аналогичных", раз он работает так тебе нужно но без форматирования.
clickmaker © ( 2013-01-22 17:49 ) [21]
S1 := D1.Selection.FormattedText;
D2.Selection.FormattedText:= S1;
не?
← →O'ShinW © ( 2013-01-22 18:14 ) [22]
намекаешь на FormattedText?
Да, это почти как нужно..
Но, почти. Потому что еще картинки-логотипы не берутся и размеры листа не те, а по-умолчанию.
Картинки можно, конечно, и потом вставить. И размеры задать.
А если первый раз все-таки целиком вставить, как раньше, то и размеры задавать не надо, по размерам первого листа идет.
← →sniknik © ( 2013-01-22 18:19 ) [23]
> Но, почти.
рассмотрели 2, осталось 157 свойств/методов (155 без 2-х в [0]).
O'ShinW © ( 2013-01-22 18:20 ) [24]
> S1 := D1.Selection.FormattedText;
> D2.Selection.FormattedText:= S1;
>
ну да, почти
W.Selection.Copy;
COPY_TEMPL := W.Selection.FormattedText;
D2 := W.Documents.Add;
W.Selection.Paste; // для размеров листов
while not(DS.Eof) do
begin
W.ActiveDocument.Range.FormattedText := COPY_TEMPL;
W.Selection.InsertBreak(OleVariant(7));
и т.п.
В принципе, картинками теперь попадать осталось..
и таблицами
и еще чем-нибудь
но сначала проверить есть ли они..
блин, проще, наверное, буфер обмена залочить..
← →O'ShinW © ( 2013-01-22 19:12 ) [25]
нет, все-таки надо сделать уж
> sniknik ©
> clickmaker ©
Спасибо!
брат Птибурдукова ( 2013-01-22 19:50 ) [26]
> O"ShinW © (22.01.13 16:42) [5]
Хе, делал такое же, когда лотусом занимался, только там не ворд был, а эксель. Если мне не изменяет склероз, мы тупо копировали файл шаблона (не через буфер, естественно), а потом копию наполняли данными.
O'ShinW © ( 2013-01-22 20:42 ) [27]
> брат Птибурдукова (22.01.13 19:50) [26]
У екселя есть хороший метод copyto(destination), в обход буфера
O'ShinW © ( 2013-01-24 13:31 ) [28]
D2.Range(0,0).InsertFile( Pattern );
никакого буфера..
> sniknik ©
и не надо ничего говорить :)
ps
Спасибо!
leonidus © ( 2006-06-17 19:11 ) [0]
Проблема простая и много раз обсуждалась но у меня есть нюанс. Моя программа по нажатию горячей клавиши (установлен глобальны хук на клаву) при чем клавиша нажимается и держится, должна записать в буфер обмена выделенный в любом приложении текст (подразумеваем что окно в котором текст выделен имеет фокус ввода). Я делаю так:
и все прекрасно работает если "горячая клавиша" это Ctrl, но если "горячая клавиша" скажем Shift то код не срабатывает. И на самом деле если скажем руками нажать Shift и одновременно Ctrl+C то ничего в буфер обмена не скопируется, поэтому и код не работает. Но как же мне быть ведь условие "нажатия и не отпускания" горячей клавиши у меня обязательно?
← →Leonid Troyanovsky © ( 2006-06-18 10:48 ) [1]
> leonidus © (17.06.06 19:11)
> нюанс. Моя программа по нажатию горячей клавиши (установлен
> глобальны хук на клаву) при чем клавиша нажимается и держится,
> должна записать в буфер обмена выделенный в любом приложении
Не очень понятно, зачем программа, горячая клавиша и т.д.
если нажатие ^C и так копирует выделенное в буфер.
> Леонид, а что такое ^C ?
--
Regards, LVT.
leonidus © ( 2006-06-18 13:44 ) [4]
Ну это понятно, но если горячая клавиша у пользователя Shift то пока он ее держит то эмитация нажатия Ctrl+C через keybd_event не приводит к успеху, вот я и спрашиваю что делать. А про горячую клавишу - это именно так нужно, т.е. юзер выделил текст и держит горячую клавишу а программа берет и копирует тест в буфер. Как это реализовать?
А сразу нажать Ctrl+C, вместо какой-то другой горячей клавиши - разве юзер этого не может? Ему это даже и привычнее как-то.
← →leonidus © ( 2006-06-19 10:16 ) [6]
Нет так не получится, не спрашивайте почему, просто не получится. Юзер должен нажать и держать горяцую клавишу а программа скопировать текст в буфер.
← →Leonid Troyanovsky © ( 2006-06-19 18:49 ) [7]
> leonidus © (19.06.06 10:16) [6]
> Юзер должен нажать и держать горяцую клавишу а программа
> скопировать текст в буфер.
Остается лишь SendMessage WM_COPY.
Т.е., оно должно сработать для обычных EDIT(вкл. редактор COMBOBOX), RichEdit и даже Word (хотя, для последнего, возможно, что через
SendMessageW, не помню).
Ну, а для нестандартных edit"ов (которые могут быть чем угодно)
все это может быть напрасным.
--
Regards, LVT.
TStas © ( 2006-06-19 20:46 ) [8]
Вот проблему на ровном месте выдумали. Когда мне надо было транслит к аське написать, я именно ctrl+C Ctrl+Enter аське отсылал. Все работало замечательно. Иногда, правда, аське не все обрабатывала, так она в принципе скоростью не отличаеттся
← →Германн © ( 2006-06-20 02:08 ) [9]
Имхо, в сабже явно проглядывает неверное понимание термина HotKey ("горячая клавиша")! :-(
И непонимание того, что в качестве "горячей клавиши" может выступать либо "функциональные клавиши" - F1..F12 (плюс с Shift-ом), либо какое-то сочетание иных клавиш, которое не имеет заранее заданного значения.
> и еще не понятно, если по сути своей PostMessage и SendMessage
> выполняют одинаковые функции, то зачем их вызывать вместе?
В твоем случае, видимо, достаточно лишь последнего.
← →leonidus © ( 2006-06-24 21:46 ) [15]
В том то и дело что если посылать WM_COPY то это сработает только для Edit-контролов, а мне нужно из любых контролов копировать в буфер.
← →leonidus © ( 2006-06-29 10:18 ) [16]
люди help!
Буфер обмена Windows - это специальный контейнер для текста или графики, которые вырезаются, копируются и вставляются из одних приложений в другие. В данной статье рассказывается, как использовать объект TClipboard для выполнения операций вырезки/копирования/вставки в Вашем Delphi-приложении.
Буфер обмена в общих чертах
Вероятно, Вы знаете, что буфер обмена (далее - БО) может содержать только один фрагмент данных в конкретный момент времени. Именно с этими данными выполняются все основные операции обмена между приложениями. Вполне логично, что формат данных, хранимых в БО в конкретный момент, также чётко опеределён. Если в БО записывается новая "порция" данных, то информация, которая содержалась в нём ранее, уничтожается. Содержимое БО не удаляется после вставки в данных в конкретное приложение, т.е. информация будет храниться там до тех пор, пока не будет записана какая-либо другая, либо пока БО не будет принудительно очищен.
Объект TClipboard
Для того, чтобы работать с БО в своём приложении, мы должны подключить модуль ClipBrd в uses нашего проекта, за исключением тех случаев, когда мы используем готовые методы некоторых компонент для работы с БО.
Примерами таких компонентов могут быть TEdit, TMemo, TOLEContainer, TDDEServerItem, TDBEdit, TDBImage и TDBMemo. В модуль ClipBrd включен объект TClipboard, обращаться к которому можно просто Clipboard. Мы будем использовать методы CutToClipboard, CopyToClipboard, PasteFromClipboard, Clear и HasFormat при работе с БО и манипуляциями с текстом и графикой.
Отправка и получение текста
uses ClipBrd;
.
Clipboard.AsText := SomeStringData_Variable;
Чтобы получить текст из БО, следует делать так:
uses ClipBrd;
.
SomeStringData_Variable := Clipboard.AsText;
Примечание: если требуется просто скопировать текст в буфер обмена, например из TEdit, то не обязательно подключать модуль ClipBrd. У TEdit есть метод CopyToClipboard, который автоматически копирует выделенный текст из этого компонента в БО (данные переводятся в формат CF_TEXT).
procedure TForm1.Button2Click(Sender: TObject) ;
begin
//Следующий код выделяет весь текст в TEdit
Edit1.CopyToClipboard;
end ;
Чтобы извлекать изображения из БО, программа должна знать, в каком формате там храниться изображение. Аналогично, чтобы записывать в БО графику, приложение должно "сообщить" буферу обмена тип отправляемого изображения. Некоторые возможные значения параметра Format приведены ниже; однако в Windows определено гораздо больше форматов.
CF_TEXT - Текст, где каждая строка заканчивается CR-LF комбинацией символов.
CF_BITMAP - Изображение в формате Windows bitmap.
CF_METAFILEPICT - Изображение Windows metafile.
CF_PICTURE - Объект типа TPicture.
CF_OBJECT - Любой значимый объект.
Метод HasFormat возвращает True, если данные в буфере обмена хранятся в указанном формате и могут быть прочитаны:
if Clipboard.HasFormat(CF_METAFILEPICT) then
ShowMessage( 'Clipboard has metafile' );
В общем случае, MyBitmap - это объект одного из типов: TGraphics, TBitmap, TMetafile или TPicture.
Чтобы получить графические данные из БО, нужно: проверить текущий формат содержимого БО и использовать метод Assign, указав конечный объект для импорта данных:
uses clipbrd;
.
procedure TForm1.Button1Click(Sender: TObject) ;
begin
if Clipboard.HasFormat(CF_BITMAP) then Image1.Picture.Bitmap.Assign(Clipboard) ;
end ;
Немного о расширенной работе с буфером обмена
Буфер обмена хранит информацию, которую мы можем перемещать между разными приложениями, в самых различных форматах; к тому же, сами приложения могут работать с разными форматами. Однако при чтении данных из БО в Delphi-приложении через объект TClipboard, мы можем использовать только стандартные форматы: текст, графика и мета-файлы.
Допустим, у нас есть 2 запущенных Delphi-приложения. Что Вы скажете насчёт того, чтобы определить собственный формат БО для пересылки данных между этими двумя приложениями? Допустим, мы создали в меню команду "Вставить" и хотим, чтобы этот пункт был недоступен, когда, к примеру, в буфере обмена нет текстовых данных. С тех пор, как с БО начала работать какая-либо другая программа, мы не можем отследить момента, когда в буфере произойдёт какое-либо изменение. У класса TClipboard не предусмотрено таких событий, которые оповещали бы нас об этом. Всё, что нам нужно сделать - это поставить "хуки" в систему событий буфера обмена и тогда наше приложение будет автоматически узнавать обо всех изменениях его содержимого.
Если нам нужна более гибкая система работы с буфером обмена, уведомления об изменениях в содержимом буфера и специальные форматы данных, мы можем всё это реализовать. Но об этом в следующей статье.
Перевод, дополнения — Ерёмин Андрей
Статья добавлена: 10 марта 2007
Зарегистрируйтесь/авторизируйтесь,
чтобы оценивать статьи.
Статьи, похожие по тематике
Для вставки ссылки на данную статью на другом сайте используйте следующий HTML-код:
Ссылка для форумов (BBCode):
Поделитесь ссылкой в социальных сетях:
Комментарии читателей к данной статье
Пока нет комментариев к данной статье. Оставьте свой и он будет первым.
Сегодня, в последний рабочий день недели, практически весь день провозился над передачей данных из Delphi в Word. Так как подозрение есть, что работа продолжится то решил кое-какие моменты по работе с Microsoft Word в Delphi запечатлеть и у себя в блоге. Написать такую мини-шпаргалку (тем более, что по Excel уже кое что есть).
Для начала, немного общих моментов по работе с MS Office в Delphi. И первое, что мы сделаем — это создадим объект Word.Application. Создается этот объект абсолютно также, как и объект Excel.Application:
Всё достаточно просто. Далее мы можем работать с объектом следующим образом:
- Создавать документ Word с нуля
- Открыть уже существующий документ и изменить в нем текст для получения необходимой формы документа.
Рассмотрим оба варианта, т.к. оба они имеют как свои плюсы, так и недостатки.
1. Создание документа Microsoft Word в Delphi с нуля.
Чтобы создать новый документ необходимо выполнить метод Add у коллекции Documents, т.е.:
и после этой операции уже начинать работать с документам обращаясь к нему по индексу или имени в коллекции. Также, можно создать новый документ по шаблону (*.dot). Для этого необходимо выполнить тот же метод Add, но с одним входным параметром — путем к файлу-шаблону:
Чтобы получить список всех открытых в данный момент документов Word можно воспользоваться следующим листингом:
Обратите внимание, что нумерация начинается с 1, а не с нуля. Чтобы активировать любой документ из коллекции для работы, необходимо выполнить метод Activate:
где index — номер документа в коллекции.
Теперь можно приступать к записи и чтению документа. Для работы с текстов в документе Word, как и в Excel для работы с ячейками таблицы, определен объект Range. Именно методы этого объекта и дают нам возможность работы с текстом. Для начала рассмотрим работу двух основных методов: InsertBefore и InsertAfter.
Как следует из название — первый метод вставляет текст в начало содержимого Range, а второй — в конец. При этом сам объект Range может содержать как весть документ (Document) так и какую-либо его часть. Например, в следующем листинге я вставлю строку в начало документа и затем методом InsertAfter буду добавлять несколько строк текста в конец документа:
При выполнении этих трех операции Range содержал весь документ.
Если работать со всем документом неудобно, а необходимо, например выделить фрагмент с 50 по 100 символ и работать с ним, то можно воспользоваться функцией Range, которая вернет нам необходимый объект Range:
Это что касается записи текста. Решение обратной задачи — чтения текста из документа ещё проще. Достаточно воспользоваться свойством Text у объекта Range:
Также для чтения документа можно воспользоваться коллекцией документа Words (слова). За слово принимается непрерывный набор символов — цифр и букв, который оканчивается пробелом.
Перечисляются слова документа точно также как и при работе с коллекцией документов, т.е. первое слово имеет индекс 1 последнее — Word.Count.
В данном случае я вывел на экран последнее слово в документе.
Очевидно, что приведенный выше способ работы с документам хорош в случае, когда требуется создать относительно простой документ Word и не требуется лишний раз рассчитывать фрагменты текста, правильно вставлять таблицы и т.д. Если же необходимо работать с документами, которые имеют сложное содержание, например текст в перемежку с рисунками, таблицами, а сам текст выводится различными шрифтами, то, на мой взгляд наиболее удобно использовать второй способ работы с Word в Delphi — просто заменить текст в уже заранее заготовленном документа.
2. Работа с документами Word в Delphi. Открытие готового документа и замена текста.
Чтобы открыть заранее заготовленный документ Word в Delphi достаточно воспользоваться методом Open у коллекции Documents, например так:
Метод Open можно вызывать с несколькими аргументами:
- FileName: string — путь и имя файла;
- ConfirmConversions: boolean — False — не открывать диалоговое окно «Преобразование файла» при открытии файла, формат которого не соответствует формату Word (doc или docx)
- ReadOnly:boolean — True — открыть документ в режиме «Только для чтения»
- AddToRecentFiles: boolean — True, чтобы добавить документ в список недавно открытых документов.
- PasswordDocument: string — пароль для открытия документа
- PasswordTemplate: string — пароль для открытия шаблона
- Revert : boolean — True, чтобы вернуться к сохраненному документу, если этот документ открывается повторно.
- WritePasswordDocument: string — пароль для сохранения измененного документа в файле
- WritePasswordTemplate:string — пароль для сохранения изменений в шаблоне
- Format:integer — формат открываемого документа.
Обязательным параметром метода Open является только FileName, остальные — могут отсутствовать. Если же Вам необходимо воспользоваться несколькими параметрами, то их необходимо явно указывать при вызове метода, например:
В этом случае документ открывается в режиме «Только для чтения». При таком способе вызова (с явным указанием аргументов) положение аргументов может быть произвольным.
Что касается последнего аргумента — Format, то он может принимать целочисленные значения (применительно к версиям Microsoft Word 2007 и выше) от 0 до 13. При этом, для того, чтобы открыть «родные» вордовские документы (doc) достаточно использовать значения 0 или 6.
Приведенная выше функция позволяет провести поиск и замену текстового фрагмента во всём документе. Для того, чтобы ограничить возможности пользователя при работе с шаблоном документа я обычно ставлю на необработанный файл пароль, а после обработки — пароль снимаю и сохраняю документ с другим названием в необходимую директорию.
Вот, наверное, самые-самые простые методы работы с Word в Delphi. Кстати, пишу пост и, думаю, что у кого-то из читателей может возникнуть вопрос: причём тут Delphi в Internet и Word в Delphi? :) Честно говоря, приведенный выше фрагменты кода можно использовать для нужд в Internet с натяжкой, например, при автосоставлении небольших отчётов по чему-либо. А вообще, в недалеком будущем, есть в планах поразбираться с Тезаурусом Word и попробовать составить небольшой синонимайзер для собственных нужд — он-то и пригодится нам в Internet :)
Читайте также: