Delphi word выравнивание текста

Обновлено: 06.07.2024

Delphi site: daily Delphi-news, documentation, articles, review, interview, computer humor.

Для создания абзацев в документе можно использовать коллекцию Paragraphs объекта Document, представляющую собой набор абзацев данного документа. Добавить новый абзац можно с помощью метода Add этой коллекции:

Для вставки собственно текста в документ применяется не объект Paragraph, а объект Range, представляющий любую непрерывную часть документа (в том числе и вновь созданный абзац). Этот объект может быть создан разными способами. Например, можно указать начальный и конечный символы диапазона (если таковые имеются в документе):

Rng := App.ActiveDocument.Range(2 4): // со 2-го no 4-й символы

Можно также указать номер абзаца (например, только что созданного):

Кроме того, можно указать несколько последовательных абзацев:

Rng := App.ActiveDocument.Range (Арр.Acti veDocument.Paragraphs.Item(3).Range.Start. App.Acti veDocument.Paragraphs.Item(5).Range.End) Вставить текст можно с помощью методов InsertBefore (перед диапазоном) или InsertAfter (после диапазона) объекта Range, например:

Помимо объекта Range текст можно вставлять с помощью объекта Selection, являющегося свойством объекта Word.Application и представляющего собой выделенную часть документа (этот объект создается, если пользователь выделяет часть документа мышью, и может быть создан также с помощью приложенияконтроллера). Сам объект Selection можно создать, применив метод Select к объекту Range, например:

В приведенном выше примере в текущем документе выделяется третий абзац.

Если мы хотим вставить строку текста в документ либо вместо выделенного фрагмента текста, либо перед ним, это можно сделать с помощью следующего фрагмента кода:

Отметим, что если свойство Options.ReplaceSelection объекта Word.Application равно True, выделенный текст будет заменен новым (этот режим действует по умолчанию); если же нужно, чтобы текст был вставлен перед выделенным фрагментом, а не вместо него, следует установить это свойство равным False:

Символ конца абзаца при использовании объекта Selection может быть вставлен с помощью следующего фрагмента кода:

К объекту Selection, так же как и к объекту Range, можно применить методы InsertBefore и InsertAfter. В этом случае, в отличие от предыдущего, вставляемый текст станет частью выделенного фрагмента текста.

С помощью объекта Selection, используя его свойство Font и свойства объекта Font, такие как Bold, Italic, Size и другие, можно отформатировать текст. Например, таким образом можно вставить строку, выделенную полужирным шрифтом:

Для наложения на вставляемый текст определенного заранее стиля можно использовать свойство Style объекта Selection, например:

Sel.TypeTextC'Это текст, который станет заголовком'); Sel.TypeParagraph:

Нередко документы Word содержат данные других приложений. Простейший способ вставить такие данные в документ - использовать метод Paste объекта Range:

Естественно, в этом случае в буфере обмена уже должны содержаться вставляемые данные.

Если нужно поместить в буфер обмена часть документа Word, это можно сделать с помощью метода Сору объекта Range:

Следующее, что нужно научиться делать, - это перемещать курсор в нужное место текста, чем мы и займемся в следующем разделе.

Вывод текста является одной из основных задач, которую приходится решать в программе при организации вывода данных. Речь пойдет о выводе текста с использованием Windows API функций. Данная статья, безусловно не претендует на полноту обзора этой тематики, но о некоторых "подводных камнях" я все же расскажу.

Функции, которые позволяют это выполнять, весьма разнообразны, и использовать их, как Вы уже поняли, можно в разных ситуациях и случаях, и собственно говоря, именно Вам и решать, какие использовать. Кроме функций, которые непосредственно выводят текст, также существует внушительный список "подсобных" функций.
Давайте глянем на tCanvas. В этом классе реализовано только две функции TextOut и TextRect. Когда задача стоит просто в выводе текста на цветном фоне (например, combo box цветов), то функций этого класса предостаточно, и в большинстве случаев я ими и пользуюсь. Но давайте заглянем за ширму. Функция TextOut использует одноименную функцию Windows, а TextRect использует функцию ExtTextOut, т.е. если на прямую вызывать функции Windows, можно получить тот же результат. Кроме того, в этих функциях есть передаваемые параметры, которые класс прячет, использование которых в определенных ситуациях не может быть не нужным и полезным. Формат функций я буду приводить из модуля windows.pas поставляемый с Delphi 3. Справочную информацию о передаваемых параметрах Вы сможете посмотреть в файле справки, но давайте я первый раз все же расскажу. Все GDI функции вывода имеют параметр DC - контекст устройства, на который нужно нарисовать. Естественно, Canvas подставляет туда Canvas.Handle. Если Вы хотите нарисовать на чем-то другом, то должны самостоятельно получить контекст устройства функциями, типа GetDC. Не забывайте (!) освобождать ресурсы функцией ReleaseDC.

X, Y - привязочные координаты, относительно которых происходит прорисовка. По умолчанию, привязка выполнена к левому верхнему углу. Я конечно немного не правильно выразился - в Windows принято понятие "выравнивание", а не "привязка". Оно настраивается через функцию SetTextAlign, но о ней чуть позже.

Str - переменная, которая содержит выводимый текст, а Count - длина этого текста. В качестве переменной Str можно использовать переменную, типа array [0..n] of Chat; можно передавать просто текст: 'Пример текста'. Если текст находится у Вас в переменной типа string то нужно произвести приведение типов: PChar(VarString). Как видно уже с самого названия и предаваемых параметров, функция имеет гораздо больше возможностей, нежели предыдущая. Прежде всего, текст выводится в прямоугольнике, т.е. как бы сперва выводится прямоугольник, а затем в нем текст, но гораздо быстрее, чем это производилось бы двумя функциями.

Если значение Options будет содержать ETO_CLIPPED, то текст будет виден только в указанном прямоугольнике. Заметьте, что в функцию передается PRect. Это означает, что параметр может быть пустым, т.е. nil. В этом случае, функция будет работать аналогично TextOut. Если вы используете переменную r:tRect, то в функцию должны передать @r.

Выравнивание также, устанавливается предварительно при помощи SetTextAlign.

Наиболее интересен параметр DX. Это ссылка на массив, типа array [0..n] of integer, где каждый элемент является шириной символа. Настоящая ширина может отличатся от указанного значения. Это можно использовать, например, для имитации моноширного шрифта, или для сжатия текста таким образом, чтоб он помещался в отводимую область. В отличии от предыдущих функций, функция DrawText не имеет параметров X, Y и использует для руководства координат параметр lpRect. Заметим, что этот параметр является переменной, т.к. функция может модифицировать значения, если ее вызвать с параметром uFormat равным DT_CALCRECT, при этом прорисовка не будет осуществлятся. Параметр uFormat может включать в себя все значения выравнивания по этому предварительной глобальной настройки при помощи SetTextAlign не требуется.

По умолчанию текст, который не вместится в lpRect будет обрезаться. Чтобы этого не происходило, в параметре uFormat используйте DT_NOCLIP.

По-прежнему есть проблема с вертикальным выравниванием по центру (DT_VCENTER). Оно работает только для однострочного текста, т.е. для многострочного текста сперва придется вычислить lpRect, а затем изменив lpRect.top и lpRect.bottom, добиться желаемого результата.

Используйте DT_WORD_ELLIPSIS и (или) DT_PATH_ELLIPSIS если необходимо вывести длинный текст, который не помещается в одну строку. Выглядит это примерно так: надо вывести "C:\Program Files\Borland\Delphi3\Source\VCL", а выведется "C:\Program Files\. \VCL". В этом случае, значение DT_MODIFYSTRING обязательно.

DT_NOPREFIX позволяет выводить "&", а не подчерк под следующим по тексту символом. Без этого значение в строке придется записывать "&&". Оговорюсь, что практически все функции, в названиях которых есть окончание "Ex", являются расширением одноименных функций без "Ex". В файле справки упоминается, что функции без "Ex" являются "пережитками" Windows 3.1, по этому рекомендуют использовать расширенные функции. По моему личному опыту могу судить, что разницы никакой, если Вам не нужны дополнительные параметры, и хлопоты по их заполнению :).

Горизонтальное выравнивание не влияет на результат вывода. Вывод многострочного текста. В качестве параметра PolyTextArray нужно передавать переменную типа array [0.. Strings-1] of TPolyText. Структура TPolyText содержит все те же параметры, которые передаются функции ExtTextOut.
Под Windows 95/98 не поддерживается.

Примечание:
Кстати, советую всегда, перед начало освоения нового "камня преткновения" обращать на этот пункт. Лично у меня был случай, когда пишешь, пишешь, приносишь клиенту - не работает. Почему?! Читаешь MSDN: "Windows 95/98: Unsupported".

Должен огорчить всех любителей "красоты" - в Windows нет стандартной поддержки выравнивания текста по ширине. Теперь, думаю понятно, почему даже в tRichEdit нет этого.

Теперь немного о "подсобных" функциях, вызов которых влияет на результат вывода текста. Об одной из них упоминал выше - SetTextAlign. Не пугайтесь по поводу типа UINT - это обычный тип Integer. Параметр Flags должен указывать выравнивание текста как по вертикали, так и по горизонтали (TA_NOUPDATECP, TA_UPDATECP, TA_LEFT, TA_RIGHT, TA_CENTER, TA_TOP, TA_BOTTOM, TA_BASELINE). Хочу отметить два момента. Во-первых, если горизонтальное выравнивание может быть TA_CENTER, то по вертикали такого нет, и при необходимости такой реализации Вам придется соответствующим образом задавать параметр Y. Во-вторых, использование TA_UPDATECP и TA_NOUPDATECP приводит к тому, что текущая координата после вывода текста будет или не будет изменятся. Задает цвет тексту. Здесь COLORREF обычный DWORD. Я зачастую в качестве этого параметра передаю функцию RGB(r, g, b: byte) или CMYK(c, m, y, k: Byte) - это разные цветовые модели. Задает смещение каждого символа в строке относительно той точки, в которой он, должен рисоваться, т.е. если CharExtra = 1 то второй символ смещается в право на 1 пиксель, второй на 2 и т.д. Может быть отрицательным, тогда символы "налезут" друг на друга. При этом искажения начертания нет. Удлиняет или укорачивает выводимый текст на величину BreakExtra за счет изменения длины пробелов. Количество пробелов в строке указывается в BreakCount.

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

Работа с текстом

Сначала о самом простом - добавлении в документ Word нужной строки текста. Поместим на форму компоненты WordDocument, WordApplicationи WordParagraphFormat с палитры Servers. Нас интересуют в первую очередь свойство Range компонента WordDocument и свойство Selection компонента WordApplication. Классики утверждают, что они являются ссылкой на объекты Range и Selection. Range представляет из себя, проще говоря, кусок текста, это может быть как весь текст документа, так и любая его часть. Его пределы задаются двумя (или меньше) параметрами типа OleVariant.

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

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

Кроме того, с помощью 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, то курсор переместится назад. Можно просто поставить в скобках " пустышку" :

Тогда свертывание выделения производится по умолчанию, к началу выделенного текста.

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

Но оказывается, что многие задачи в Delphi уже решены, надо только уметь использовать их. Рассмотрим свойства компонентов, которые так или иначе связаны с позиционированием компонентов относительно друг друга, а потом и несколько примеров для реализации типичных интерфейсов программ. Свойства будут рассмотрены в алфавитном порядке, так что при чтении, возможно, придется "прыгать".

Align (выравнивание)

Свойство заставляет компонент менять некоторые из своих размеров и положение при изменении размеров компонента-родителя. Возможные значения:

alNone – значение по умолчанию, положение компонента зависит только от Left, Top, Width, Height.

alBottom – компонент "прижимается" к нижней части компонента-родителя. Занимает всю доступную ширину родителя. Работает только свойство Height. Если есть два компонента, один из которых имеет alBottom (или alTop), а второй alLeft (alRight), то первый компонент займёт максимальную высоту, а второй разместится в оставшейся части.

alTop – компонент "прижимается" к верхней части компонента-родителя. Остальное – аналогично alBottom.

alLeft - компонент "прижимается" к левой части компонента-родителя. Занимает всю доступную высоту родителя. Работает только свойство Width.

alRight - компонент "прижимается" к правой части компонента-родителя. Аналогичен alLeft.

alClient – компонент занимает всё доступное пространство компонента-родителя. Если есть компоненты с другими выравниваниями, то вначале выравниваются они. Нельзя разместить на одном родителе два компонента с этим типом выравнивания.

AlignWithMargins (выравнивать с учетом отступов)

Указывает на то, что при использовании свойства Align, нужно учитывать свойство Margins. О нём - ниже.

Anchors

С английского названия этого свойства переводиться как "якорь". Позволяет закрепить края компонента к краям родителя таким образом, чтобы при изменении размеров родителей расстояние между заданными краями оставалось постоянным. Свойство представляет собой множество (set). В инспекторе объектов редактируется как 4 вложенных свойства типа Boolean. По умолчанию выставлены только akTop и akLeft.

Чтобы понять, как это свойство работает, сделайте такие два эксперимента. Поставьте на форму панель (можно кнопку), сделайте размеры такими, чтобы компонент занимал по площади где-то половину формы и был размещён в центре. Выставьте все четыре подсвойства в True. Запустите программу и изменяйте мышкой размеры формы, понаблюдайте эффект. Также попробуйте выставлять только некоторые подсвойства равными True.

Это свойство появилось с 4, то ли c 5 версии Delphi.

AutoSize (авторазмер)

Если значение свойства - True, то компонент пытается занять минимальный размер, при котором на нём вмещаются все его дочерние компоненты без сдвига оных. В случае, если на компоненте нет ничего, то он может ужаться до нулевых размеров (так поступает панель). Не все компоненты имеют это свойство.

Constraints (ограничивающее условие)

Иногда бывает, что нежелательно, чтобы компонент увеличивал (или уменьшал) свои размеры больше какой-то величины. Поэтому его размеры можно и нужно ограничить. Это свойство имеет четыре подсвойста: MaxHeight, MaxWidth, MinHeight и MinWidth, названия которых сами говорят за себя. Если например, в свойство MaxHeight формы вписать число 400, то увеличить высоту формы больше 400 не получится. Число 0 означает игнорирование данного ограничения. Понятное дело, что MaxHeight >= MinHeight, и аналогично с шириной. Если попытаться нарушить условие, то Delphi поправит за вами, уравняв их. Кстати, при этом наблюдается интересный эффект. Если MaxHeight = MinHeight, то у компонента (формы) нельзя изменить высоту. А ширину – можно. Развернуть в полный экран тоже не получится. Рекомендую поэкспериментировать с этим свойством. Хотя его применение и достаточно ограничено.

Height (высота)

Указывает высоту компонента в пикселях. Игнорируется при некоторых установках свойств Align и Anchors.

Left (слева)

Указывает на расстояние в пикселях от левого края компонента до левого края компонента-родителя (обычно это форма). Игнорируется при некоторых установках свойств Align и Anchors.

Margins (кромка, край; приграничная область)

Это свойство начинает проявлять себя только если AlignWithMargins = True. В таком случае можно указать, на сколько меньше должен занимать компонент при выравнивании. Вокруг компонента как бы создаётся отступ. Посмотрите на рисунок, где для нижней панели все 4 подсвойства выставлены по 10 и сравните с предыдущим рисунком.

Padding (заполнение)

Это свойство чем-то подобно свойству Margins. Только действует для вложенных в данный родительский компонент дочерних компонент. То есть, выставив равным все 4 подсвойства по 10, а для вложенного компонента сделав Align = alClient, получим, что компонент не займёт всё пространство, а останется каемка в 10 пикселей. Смотрим на рисунок.

Естественно, выставлять все 4 подсвойства одинаковыми не обязательно. И как всегда, чтобы увидеть всю прелесть этого свойства, меняем размеры формы мышкой и наблюдаем.

Top (верх)

Указывает на расстояние в пикселях от верхнего края компонента до верхнего края компонента родителя (обычно это форма). Игнорируется при некоторых установках свойств Align и Anchors.

Width (ширина)

Указывает на ширину компонента в пикселях. Игнорируется при некоторых установках свойств Align и Anchors.

Примеры реальных приложений

Попробуем "сымитировать" интерфейс некоторых популярных приложений, чтобы расположение компонентов было одинаковым.

Блокнот

Да, да, тот Блокнот, который есть в Windows.

  • Ставим на форму меню (TMainMenu). Заполняем.
  • Ставим на форму TStatusBar. Замечаем, что у него автоматически срабатывает Align=alBottom.
  • Ставим на форму TMemo. Выставляем Align=alClient.

Осталось только реализовать меню и приложение готово. Запустите и посмотрите, как при изменении размеров наше приложение ведёт себя аналогично Блокноту.

The Bat!

Теперь усложним задачку. Сымитируем интерфейс популярного почтовика. Кстати, он написан на Delphi.

  • Ставим на форму меню (TMainMenu), заполняем пунктами по вкусу (нужно создать хотя бы два-три пункта, иначе теряется весь эффект).
  • Ставим CoolBar.
  • Ставим на CoolBar два тулбар (TToolBar). Замечаем, как они выравниваются по верхней кромке.
  • Выбираем верхний тулбар и заполняем свойства Menu = MainMenu1, AutoSize = True, и, если у вас Delphi 2007, то и DrawingStyle = dsGradient.

Теперь у нас два меню, что ж, уберём лишнее – выделим форму и свойство Menu сделаем пустым.

  • Ставим на форму ImageList, кликаем дважды по нему и наполняем его иконками.
  • Выставим свойство Images у ToolBar2 равным ImageList. Замечаем, как у добавленных кнопок появились картинки. Они все одинаковы, поэтому кликаем по каждой и с помощью свойства ImageIndex выбираем понравившиеся. В конце выставляем свойство AutoSize = True для этого тулбара.
  • Для CoolBar также выставляем AutoSize = True. Замечаем, как всё "уляглось".
  • Ставим на форму TStatusBar.
  • Ставим на форму TreeView, выставляем Align = alLeft. Ширину делаем где-то на треть формы.
  • Ставим на форму компонент TSplitter (вкладка Additional). Внимательно - кликайте именно по форме, иначе он может выровняться по самому левому краю формы – в таком случае возьмите и перетащите его на место. Он автоматом выставляет Align = alLeft.
  • На оставшееся пространство ставим панель, и выставляем Align = alClient.
  • Теперь на панель ставим ListView, выставляем свойства Style = vsReport, Align = alTop. С помощью свойства Columns добавляем колонки.
  • Ставим на панель TSplitter. Выставляем Align = alTop. Компонент автоматом примет горизонтальное положение.
  • В оставшуюся часть панели ставим компонент TWebBrowser или TRichEdit (Чем вы решите отображать содержимое письма). Выставляем Align = alClient.

Запускаем, наслаждаемся. У меня получилось так:

Особенности – компоненты автоматически подгоняют размер при изменении размеров формы, границы между TreeView, ListView и просмотрщиком писем можно менять при запущенной программе. И самая главная особенность - достаточно профессиональный интерфейс мы получаем стандартными компонентами и без единой строчки кода!

Интересные заметки

1. Если один или несколько компонентов полностью заполняют своего родителя, то выделить мышкой самого родителя невозможно. И для многих это трагедия – они не знают, что делать. Можно, конечно, в инспекторе объектов в выпадающем списке поискать подходящий, но обычно и имени нужного компонента мы не помним. А всё просто. Выделяем любой компонент, который лежит на заданном компоненте, и жмём Esc. И, вуаля, выделен компонент-родитель! Ещё одно нажатие - и выделение уходит к родителю родителя. Это будет продолжаться до тех пор, пока выделение не перейдёт к форме. В примере почтовика, можно, нажав три раза Esc, гарантировано дойти до формы.

2. Если случайно компонент поставили не на того родителя, то перетянуть мышкой его уже нельзя. Удалять и ставить по-новому? НЕТ! На помощь приходит клавиатура. Выделяем нужный компонент (или несколько, просто зажав Shift). Потом жмём Ctrl+X (вырезать). Кликаем по нужному компоненту-родителю и жмём Ctrl+V (вставить). Более того, таким образом можно переносить компоненты между формами и даже проектами! А можно "вставить" не на форму, а в Блокнот. Присмотревшись, можно понять, как в виде текста представлен компонент, и даже подредактировать его. А потом и вставить на другую форму.

3. Если несколько компонентов находятся на форме, то их можно выделить, просто "охватив мышкой". То есть, провести по диагонали так, что бы в полученный прямоугольник попали нужные компоненты. А вот если компоненты находятся на панели, то так уже не получится – мы просто перемещаем панель. Решение простое. Просто нажмите Ctrl на клавиатуре и выделяйте как обычно.

5. В случае наличия на форме большого количества Edit'ов, многие пользователи любят переключаться между ними с помощью Tab. Но как только в своей программе попробуешь сделать это – курсор прыгает между ними, как ему вздумается. Кликаем правой кнопкой, в меню TabOrder выставляем стрелочками нужный порядок. Пусть пользователи радуются.

Заключение

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

Автор: Вадим К

Статья добавлена: 12 июня 2008

Рейтинг статьи: 4.50 Голосов: 4 Ваша оценка:

Зарегистрируйтесь/авторизируйтесь,
чтобы оценивать статьи.

Статьи, похожие по тематике

Для вставки ссылки на данную статью на другом сайте используйте следующий HTML-код:

Ссылка для форумов (BBCode):

Поделитесь ссылкой в социальных сетях:

Комментарии читателей к данной статье

Пока нет комментариев к данной статье. Оставьте свой и он будет первым.

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