Работа в системе LaTeX

Блоки и клей

Разбить на страницы
Показывать лекцию целиком

Текст состоит из блоков

Мы уже отмечали, что в процессе набора TeX не принимает во внимание, как буквы будут выглядеть на печати, а лишь учитывает, сколько места надо отвести на каждый символ. Давайте обсудим этот процесс подробнее.

С точки зрения TeX'а, каждая буква представляет собой блок (английский термин: box), т.е. прямоугольник с выделенной точкой отсчета ; горизонтальная прямая, проходящая через точку отсчета, называется базисной линией (английский термин: baseline). Блок характеризуется тремя размерами: шириной, высотой и глубиной. См. рисунок, на котором также изображен блок, соответствующий букве у.

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

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

В приведенных выше примерах мы сталкивались с блоками, которые TeX создает автоматически; в настоящей лекции пойдет речь о командах, предназначенных для создания блоков вручную. Сначала мы расскажем, какие средства для этого предоставляет нам LaTeX, а затем рассмотрим некоторые TeX'овские команды, дающие дополнительные возможности.

Команды LaTeX'а для генерации блоков

Блоки из строки

С одной командой для генерации блоков мы уже знакомы: это команда \mbox. Эта команда создает блок из текста, набираемого в одну строку. Полученный блок рассматривается TeX'ом как одна буква:

$$Проказница мартышка, \mbox{осел, козел} и косолапый мишка\ldots$$
Проказница мартышка,
\mbox{осел, козел} и
косолапый мишка\ldots

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

Теперь, когда мы знаем, что такое TeX'овские блоки, можно признаться, что окружения {picture},{tabular} и {array} тоже генерируют блоки, и именно поэтому создаваемый ими текст воспринимается TeX'ом как одна большая буква.

В аргументе команды \mbox может присутствовать все то же, что может быть в обычном тексте в пределах одной строки: математические формулы, команды смены шрифта или присваивания значений каким-то параметрам, команды для генерации блоков (например, тот же \mbox, или даже окружения {picture} или {array} ) и т.д. Запрещены в аргументе команды \mbox пустые строки или команды \par, выключные математические формулы, окружения, определяющие абзацы специального вида (скажем, {itemize} или {center}), команда \\ и тому подобные вещи, "не вписывающиеся в строку". Если в аргументе команды \mbox происходит смена шрифта, изменение каких-то параметров или определение команд, то по выходе из блока все эти изменения забываются, поскольку фигурные скобки, ограничивающие аргумент команды \mbox, ограничивают также и группу (" глобальные" команды вроде \setcounter сохраняют свое действие и по выходе из блока).

Блок, создаваемый командой \mbox, имеет ширину, равную " естественной" длине строки текста, являющегося его аргументом. Можно также создать блок из строки текста, ширина которого отлична от ее естественной длины. Для этого используется команда \makebox. Эта команда имеет один обязательный аргумент, имеющий такой же смысл, как аргумент команды \mbox, и, кроме того, необязательный аргумент — ширину блока, порождаемого командой:

$$Туда \makebox[5em]{и} обратно$$.
Туда \makebox[5em]{и} обратно.

Как видите, необязательный аргумент ставится перед обязательным; длина в нем может быть указана, как обычно, либо в какой-либо из TeX'овских единиц, либо как параметр со значением длины, возможно — с числовым коэффициентом. Сам текст, являющийся обязательным аргументом команды \makebox, размещается по центру в блоке ширины, указанной в необязательном аргументе. Если указать в необязательном аргументе команды \makebox ширину, меньшую естественной длины строки, то текст выйдет за края блока; поскольку место, отводимое TeX'ом блоку, определяется только тем, каковы ширина, высота и глубина блока, а не тем, какие размеры реально имеет текст, содержащийся в блоке, при этом может возникать наложение одного текста на другой. Например, размеры и точка отсчета блока, создаваемого командой \makebox[1.5em]{123456}, выглядят с точки зрения TeX'а так:

Для ясности мы использовали в этом примере крупный шрифт. А вот как такой "выпирающий за края" блок взаимодействует с окружающим текстом:

$$текст\makebox[1.5em]{123456}текст$$
текст\makebox[1.5em]{123456}текст

Можно также создать блок заданной ширины, в котором текст будет не центрирован, а прижат к правому или левому краю (полиграфисты говорят: " выключен вправо или влево"). Для этого в команде \makebox предусмотрен второй необязательный аргумент - буква l для текста, выключенного влево, или r для текста, выключенного вправо (можно также указать аргумент c - тогда текст будет центрирован, так же, как если бы второго необязательного аргумента не было). Пример:

$$\parindent=0pt \makebox[10em][r]{текст}\\ \makebox[10em][r]{екст}\\ \makebox[10em][r]{кст}\\ \makebox[10em][c]{текст}\\ \makebox[10em][l]{текст}$$
\parindent=0pt
\makebox[10em][r]{текст}\\
\makebox[10em][r]{екст}\\
\makebox[10em][r]{кст}\\
\makebox[10em][c]{текст}\\
\makebox[10em][l]{текст}

Мы установили нулевое значение абзацного отступа, чтобы все строки, включая первую, начинались с самого начала. Кстати, обратите внимание, что у нас получилась верстка с выравниванием без помощи таких вещей, как tabbing или tabular.

У команды \makebox значение ширины блока можно установить равным нулю. Если при этом присутствует необязательный аргумент l, то получится блок нулевой ширины, а текст будет выходить за его пределы вправо (и, стало быть, наложится на последующий текст в строке, если таковой присутствует); если присутствует необязательный аргумент r, то текст будет выходить влево за пределы блока (и тем самым накладываться на предшествующий текст):

$$текст\makebox[0pt][l]{???}текст\\ текст\makebox[0pt][r]{???}текст\\$$
текст\makebox[0pt][l]{???}текст\\
текст\makebox[0pt][r]{???}текст\\

Наряду с r (" прижатый вправо"), l ("прижатый влево") и c ("центрированный"), в качестве второго необязательного аргумента команды \makebox можно использовать и букву s, с которой начинаются английские слова stretched (растянутый) и shrunk (ужатый). Соответственно, при указании такого второго необязательного аргумента текст будет равномерно растянут или сжат до ширины, указанной в первом необязательном аргументе. Если при этом придется превысить предел растяжимости, то появится сообщение Underfull \hbox, а если окажется, что превышен предел сжимаемости, то вы увидите сообщение Overfull \hbox. Чтобы осмысленно применять \makebox с необязательным аргументом s, надо уметь управлять растяжимостью и сжимаемостью промежутков. Как это делать, рассказано в следующем разделе.

До сих пор мы задавали ширину блока в команде \mbox в явном виде. Можно, кроме того, выразить эту ширину через " естественную" ширину текста. Для этого служит команда \width. Вот, например, как сделать, чтобы чтобы ширина блока, получаемого с помощью \makebox, была на 30% больше естественной:

$$\makebox{скоросшиватель}\\[2pt] \makebox[1.3\width][r]{скоросшиватель}$$
\makebox{скоросшиватель}\\[2pt]
\makebox[1.3\width][r]
{скоросшиватель}

Командой \width можно пользоваться только внутри необязательного аргумента \makebox (или \framebox — см. ниже). Не пытайтесь пользоваться ею в качестве параметра со значением длины — ничего хорошего из этого не выйдет.

Блоки из абзацев

Если необходимо создать блок, в котором размещается сверстанный TeX'ом абзац текста, то можно воспользоваться командой \parbox. У этой команды два обязательных аргумента: первый — длина строк в получаемом абзаце, второй — собственно текст. Например, такой текст

$$\parbox{30cm}{ В строку\qquad \parbox{4cm}{вставили целый абзац текста, сверстанного по всем TeX'овским правилам. После этого продолжается}\qquad прерванная строка. }$$
В строку\qquad
\parbox{4cm}
{вставили целый
абзац текста, 
сверстанного
по всем TeX'овским 
правилам.
После этого 
продолжается}\qquad
прерванная строка.

Как видите, базисная линия блока, создаваемого командой \parbox, находится в точности посредине текста. Поэтому команду \parbox удобно использовать для включения больших фрагментов текста в математические формулы. Например, формула

$$\int_a^b f'(x)\,dx=f(b)-f(a)\qquad \parbox{4cm}{для всех функций f, производная которых интегрируема по Риману}$$

получается из такого исходного текста:

$$
  \int_a^b f'(x)\,dx=f(b)-f(a)\qquad
  \parbox{4cm}{для всех функций f,
  производная которых интегрируема
  по Риману}
$$

Если дать команду \parbox с необязательным аргументом, то создаваемый ею блок можно расположить относительно строки и по-иному: чтобы вровень с остальной строкой шла самая верхняя строка абзаца (для этого нужен аргумент t ) или самая нижняя (аргумент b ); можно также указать аргумент c — тогда блок будет расположен по центру, так же, как если бы необязательного аргумента вообще не было. Необязательный аргумент у этой команды должен идти перед обязательными.

Во втором обязательном аргументе команды \parbox, задающем текст, может присутствовать всё то же, что в обычном тексте, в том числе команды для вертикальных пробелов наподобие \vspace, пустые строки, разделяющие абзацы, выключные формулы и т.п. Абзацы, создаваемые командой \parbox, по умолчанию делаются без абзацного отступа и в режиме \sloppy. Если вы хотите чего-то другого, можно прямо внутри аргумента команды \parbox установить нужное вам значение абзацного отступа, параметра \tolerance и т.п.

Можно также указать LaTeX'у высоту, которую должен иметь блок, полученный в результате применения команды \parbox. Для этого используется второй необязательный аргумент, идущий непосредственно после первого. Наряду с явным указанием размера, можно воспользоваться командой \height, обозначающей " естественную" высоту текста, а также командой \totalheight (высота плюс глубина).

Наконец, в команде \parbox можно указать, как именно должен быть расположен текст внутри блока. Для этого используется третий необязательный аргумент, следующий непосредственно после второго. Этот аргумент — буква t, b, c или s. Буква t означает " сверху", b — "снизу", c — "по центру". Если третий необязательный аргумент не указан, то по умолчанию считается, что он совпадает с первым. Если же третьим необязательным аргументом является s, это означает, что текст будет растянут или ужат в соответствии с размером, указанным во втором необязательном аргументе. Если вы не позаботитесь о специальных командах, обеспечивающих такую растяжимость или сжимаемость, то получите сообщение об Overfullе или Underfullе.

В следующем примере блоки, созданные командой \parbox, для наглядности взяты в рамку (с помощью \fbox ):

$$\fbox{% \parbox[b][1.3\height]{2cm}{% Мы едем, едем, едем в далекие края.}}\qquad \fbox{% \parbox[t][1.3\height]{2cm}{% Мы едем, едем, едем в далекие края.}}$$
\fbox{%
\parbox[b][1.3\height]{2cm}{%
Мы едем, едем, едем
в далекие края.}}\qquad
\fbox{%
\parbox[t][1.3\height]{2cm}{%
Мы едем, едем, едем
в далекие края.}}

Команды \height и \totalheight, так же как и \depth, можно использовать только в необязательном аргументе команды \parbox (а также \framebox или \makebox ).

Наряду с \parbox, существует еще один способ создать блок из абзацев. Именно, существует окружение {minipage} (" министраница"), генерирующее блок из текста, расположенного внутри этого окружения; блок состоит из абзацев, ширина которых задается в обязательном аргументе окружения {minipage} (так же, как в команде \parbox ); перед обязательным аргументом этого окружения может стоять необязательный: буква t, b или c, причем смысл этого аргумента опять-таки такой же, как в команде \parbox. Основное отличие minipage от \parbox в том, что к тексту внутри этого окружения можно делать сноски с помощью команды \footnote, причем текст сноски появляется не внизу страницы, а внизу блока, генерируемого окружением minipage. При наборе книги, которую вы читаете, это окружение использовалось для печати примеров.

Текст в рамке; комбинации блоков

В лекции 3 мы уже упоминали про команду \fbox, берущую в рамку фрагмент текста, помещающегося в строку. Наряду с ней есть и команда \framebox, относящаяся к ней так же, как \makebox относится к \mbox: она берет текст в рамку заданного размера, причем текст внутри этой рамки либо центрирует (если необязательного аргумента нет или же задан необязательный аргумент c), либо прижимает к правому или левому краю рамки (если задан необязательный аргумент r или l). Смысл и расположение обязательных и необязательных аргументов у команды \framebox такой же, как и у команды \makebox.

Точнее говоря, первый обязательный аргумент команды \framebox задает не ширину рамки, а ширину текста, помещаемого в эту рамку. Сама же рамка отделена от текста пробелом ширины \fboxsep ; толщина линий в рамке равна \fboxrule. Обоим этим параметрам можно обычным образом присваивать новые значения.

Коль скоро каждый блок, создаваемый LaTeX'овскими командами, рассматривается TeX'ом просто как большая буква, возможны любые, сколь угодно причудливые, комбинации таких "букв". Пусть, например, нам надо взять в рамку абзац текста шириной $$6$$ см, чтобы получилось так:

$$\begin{center}\hbadness 2500 \fbox{% \parbox{6cm}{% Внутри \TeX'овских блоков может присутствовать не только собственно текст или формулы, но и другие блоки, внутри этих блоков - еще блоки, и так далее. Таким образом, блоки могут быть вложены друг в друга, как матрешки.}% } \end{center}$$

Просто поместить этот текст в аргумент команды \fbox не получится, поскольку наш текст в одну строку не укладывается, а команда \fbox, подобно команде \mbox, текстов, не укладывающихся в строку, не переваривает. Поэтому нужно сделать из нашего абзаца блок с помощью команды \parbox и этот блок (т.е. уже "букву") передать в качестве аргумента команде \fbox:

\fbox{%
\parbox{6cm}{%
Внутри TeX'овских блоков может ...
... друг в друга, как матрешки.}%
}

Обратите внимание на знаки процента, которыми заканчиваются первая и предпоследняя строки. Если бы их не было, то рамка отстояла бы от текста больше, чем надо, так как TeX решил бы, что аргумент команды \fbox имеет пробел до и после "буквы", созданной командой \parbox. См.лекцию 1 по поводу использования знака процента для удаления нежелательных пробелов.

Сдвиги относительно базисной линии

Когда при исполнении команды \makebox или \mbox TeX создает блок из меньших блоков (каждая буква, как мы помним, - это блок, из букв составляются слова - тоже блоки; наконец, блоки могут быть заданы в явном виде, в частности, командой \mbox ), то блоки эти размещаются в строке таким образом, что все их точки отсчета расположены на одной высоте (иными словами, их базисные линии продолжают одна другую). Можно, однако, сдвинуть блок по вертикали относительно базисной линии. Для этого удобно воспользоваться LaTeX'овской командой \raisebox. Эта команда требует двух обязательных аргументов. Первый из них - расстояние, на которое сдвигается по вертикали фрагмент текста, второй - сам этот фрагмент текста. Пример:

$$Слово \raisebox{2pt}{подскочило} в строке$$.
Слово \raisebox{2pt}{подскочило}
в строке.

Текст, расположенный во втором обязательном аргументе этой команды, должен удовлетворять тем же требованиям, что и аргумент команды \mbox: в нем могут быть самые разные TeX'овские команды, при условии, что среди них не будет команд типа пустой строки, \par, \\ и тому подобных, которые "не укладываются в строку" (зато в этом тексте, как водится, могут присутствовать любые команды, порождающие блоки, в частности, например, \parbox, а уж в ее аргументе оставляйте пустых строк, сколько душе угодно). Если первый обязательный аргумент команды \raisebox отрицателен, то текст будет, естественно, не поднят, а опущен. Вот, например, как можно определить команду \tex, печатающую эмблему TeX'а:

\newcommand{\TeX}{T\nolinebreak\hspace{-.1667em}\raisebox
            {-.5ex}{E}\nolinebreak\hspace{-.125em}X}

Тут же мы видим и примеры использования отрицательных промежутков для того, чтобы буквы сблизились. Команды \nolinebreak нужны, чтобы не случилось разрыва строки посередине эмблемы.

На самом деле команда \TeX определяется более экономным способом, который требует меньше машинного времени и памяти, но использует не рассматриваемые нами средства TeX'а. Время от времени мы будем приводить определения команд "в переводе с TeX'а на LaTeX".

Кроме вертикального сдвига блоков, команда \raisebox может делать еще одно полезное дело: с ее помощью можно обмануть TeX, заставив его считать, что блок, полученный после сдвига, имеет любую заданную нами высоту и глубину, независимо от того, сколько места реально занимает текст. Именно, эта команда может принимать, наряду с обязательными, необязательные аргументы. Между двумя обязательными аргументами можно указать необязательный аргумент — высоту, которую, по мнению TeX'а, должен иметь сдвинутый блок. Кроме того, после первого необязательного аргумента может стоять второй — глубина, которую, по мнению TeX'а, будет иметь сдвинутый блок. Вот пример:

$$Строка.\\ Вторая \raisebox{7pt}[1pt][10pt]{Ы}\\ Третья строка$$.
Строка.\\
Вторая
\raisebox{7pt}[1pt][10pt]{Ы}\\
Третья строка.

Буква Ы, поднятая на 7 пунктов над строкой, наложилась на первую строку, поскольку в первом необязательном аргументе команды \raisebox мы приказали TeX'у считать, что блок, образованный поднятой буквой Ы, имеет высоту всего лишь один пункт (стало быть, возвышается над базисной линией второй строки меньше, чем любая буква), и соответственно TeX не сделал дополнительного интервала между первой и второй строками. С другой стороны, третья строка отодвинулась от второй, поскольку во втором необязательном аргументе команды \raisebox мы велели TeX'у считать, что глубина блока, образованного поднятой буквой Ы, равна целым десяти пунктам, и TeX послушно оставил дополнительное место, чтобы этот блок не наложился на третью строку!

Иногда разумно использовать команду \raisebox даже с нулевым обязательным аргументом, только для того, чтобы менять (в глазах TeX'а) высоту и/или глубину блока, не сдвигая его относительно базисной линии. В лекции 9 мы увидим пример такого использования этой команды.

Команда \hbox

Возможности, предоставляемые LaTeX'ом для генерации блоков, достаточны для простых приложений, но в более серьезных случаях их не хватает. В этом и следующем разделах мы рассмотрим более гибкие средства, предоставляемые для этой цели непосредственно языком TeX и макропакетом Plain - TeX. Мы не будем пытаться описать все TeX'овские команды для генерации блоков (книгу [2] ничто заменить не может), но сообщим тот минимум сведений, который необходим для модификации LaTeX'овского стандартного оформления, о чем пойдет речь в следующей лекции. Подчеркнем, что всеми описываемыми в этом и следующем разделах TeX'овскими средствами можно пользоваться в LaTeX'овских исходных текстах.

Прежде всего давайте вспомним, что в каждый момент трансляции исходного текста TeX находится в одном из трех следующих режимов: горизонтальном (в процессе верстки абзаца), вертикальном (между абзацами), или математическом (в процессе набора математической формулы); при появлении первой же буквы или LaTeX'овской команды для генерации блока или линейки (к таковым относятся \mbox, \makebox, \fbox, \framebox, окружения {array}, {tabular} или {picture}, а также команда \ruleНо не \hrule или \vrule: это команды TeX'а, а не LaTeX'а. ) TeX из вертикального режима выходит и начинает очередной абзац.

Одна из основных TeX'овских команд для генерации блоков называется \hbox. В своем простейшем виде она полностью аналогична LaTeX'овской команде \mbox, с одним важным отличием: в вертикальном режиме команда \hbox не начинает нового абзаца, а только добавляет сгенерированный ею блок (т. е.\ фактически строку) к уже сверстанной части страницы. Внутри абзаца (в горизонтальном режиме) команда \hbox действует точно так же, как и \mbox. Вот пример:

$$На странице \hbox{уже} присутствует абзац текста. После того, как он кончится, TeX{} перейдет в вертикальный режим. \hbox{Строка} \hbox{Еще строка} Только теперь начинается новый абзац.$$
На странице \hbox{уже}
присутствует абзац текста.
После того, как он
кончится, TeX{} перейдет в
вертикальный режим.

\hbox{Строка} \hbox{Еще строка}
Только
теперь начинается новый абзац.

Сравните с тем, что было бы при использовании LaTeX'овской команды \mbox вместо \hbox:

$$На странице уже присутствует абзац текста. После того, как он кончится, TeX перейдет в вертикальный режим. \mbox{Эти слова} сразу начинают новый абзац.$$
На странице уже присутствует
абзац текста. После того, как
он кончится, TeX перейдет
в вертикальный режим.

\mbox{Эти слова} сразу
начинают новый абзац.

Растяжимые интервалы

До сих пор шла речь о важных, но непринципиальных различиях между TeX'овским \hbox и LaTeX'овским \mbox. Теперь поговорим о дополнительных возможностях, предоставляемых TeX'овской командой.

Команда \hbox "в чистом виде" создает блок, ширина которого равна естественной длине текста, являющегося ее аргументом. Кроме этого, она может создавать блоки любой заданной ширины. Для этого нужно сказать

\hbox to {ширина}{текст}

Здесь {ширина}должна быть выражена в воспринимаемых TeX'ом единицах длины: это может быть, например, 20pt, или 2.3cm, или, например, 0.12\textwidth - параметр со значением длины (возможно, с коэффициентом) тоже годится. Между to и обозначением ширины, а также между обозначением ширины и открывающей фигурной скобкой могут быть пробелы - TeX их проигнорируетПустых строк, однако, быть не должно.. Наконец, отсутствие backslash в слове to не является опечаткой: это не команда, а одно из "ключевых слов" TeX'а (подобно ключевым словам plus и minus, с которыми мы вскоре снова встретимся, или width и height, с которыми мы уже встречались в разделе, посвященном линейкам). Давайте опробуем эту новую возможность команды \hbox:

$$\hbox to 3cm {Два слова}$$
\hbox to 3cm {Два слова}

Если вы опробовали этот пример на вашем компьютере, то заметили, что на экране появилось сообщение

Underfull \hbox

Дело в том, что пробел между словами "Два" и " слова" не может растянуться настолько, чтобы наш блок имел ширину три сантиметра; в ситуациях, когда пробел насильно заставляют растянуться больше, чем положено, возникает сообщение об Underfull'е, как это было объяснено в разд. 3.6.6.

Можно, однако, заставить TeX создать блок требуемой ширины " без скандала". Для этого в том промежутке, который мы хотим растянуть, надо поставить команду \hfil:

$$\hbox {Два слова}\\ \hbox {Два \hfil слова}\\ \hbox to 2cm {Два \hfil слова}\\ \hbox to 3cm {Два \hfil слова}\\ \hbox to 4cm {Два \hfil слова}$$
\hbox {Два слова}\\
\hbox {Два \hfil слова}\\
\hbox to 2cm {Два \hfil слова}\\
\hbox to 3cm {Два \hfil слова}\\
\hbox to 4cm {Два \hfil слова}

Если мы не указываем явно ширину блока, а предоставляем TeX'у создать блок "естественной" ширины, то команда \hfil никакого действия не оказывает; если промежуток для достижения требуемой ширины надо растянуть, то растяжение на требуемое расстояние будет проведено в том месте, где стоит команда \hfil.

Если в аргументе команды \hbox присутствует не одна команда \hfil, а несколько, то растяжение произойдет на месте каждой из этих команд, причем размер этого растяжения будет распределен между командами \hfil равномерно: если необходимо превысить естественную ширину блока на $$5$$ \,см, а в аргументе команды \hbox стоят два \hfil, то на месте каждого из них будет добавлен пробел в $$2{,}5$$ см. Вот пример с несколькими \hfil:

$$\hbox to 4cm{Раз \hfil два \hfil три}$$
\hbox to 4cm
{Раз \hfil два \hfil три}

В частности, если \hfil стоит справа или слева от текста, то весь текст будет прижат влево или вправо, поскольку \hfil отмечает то единственное место, в котором интервалы могут растягиваться; если же две команды \hfil стоят по обе стороны от текста, то текст внутри блока будет центрирован, поскольку дополнительное растяжение поделится между двумя \hfil поровну:

$$\hbox to 0.7\textwidth {Слева\hfil} \hbox to 0.7\textwidth {\hfil Справа} \hbox to 0.7\textwidth {\hfil В центре\hfil}$$
\hbox to 0.7\textwidth
{Слева\hfil}
\hbox to 0.7\textwidth
{\hfil Справа}
\hbox to 0.7\textwidth
{\hfil В центре\hfil}

Можно считать, что на месте каждого \hfil в строку вставляется пружина; все эти пружины имеют одинаковую жесткость, в свободном состоянии все они имеют нулевую ширину, и все эти пружины могут сколь угодно широко растягиваться.

Наряду с \hfil существует команда \hfill, также задающая бесконечно растяжимые пробелы, причем эта растяжимость "в бесконечное число раз больше", чем у пробелов, задаваемых \hfil. Если в аргументе команды \hbox присутствуют \hfil и \hfill совместно, то все растяжения происходят только за счет "более растяжимых" \hfill:

$$\hbox to 4cm{\hfil Слово\hfil}\\ \hbox to 4cm{\hfill Слово\hfil}\\ \hbox to 4cm{\hfil Слово\hfill}$$
\hbox to 4cm{\hfil Слово\hfil}\\
\hbox to 4cm{\hfill Слово\hfil}\\
\hbox to 4cm{\hfil Слово\hfill}

Лидеры

В оглавлении к этой книге (и ко многим другим тоже) место между названием раздела и номером страницы заполняется рядом из точек. Это можно сделать с помощью LaTeX'овской команда \dotfill. Она работает так же, как и \hfill, с той разницей, что пробел, образующийся в результате действия этой команды, заполняется точками:

$$\hbox to 3cm{А\dotfill Б}$$
\hbox to 3cm{А\dotfill Б}

Кроме этого, есть LaTeX'овская команда \hrulefill, которая также действует аналогично команде \hfill и при этом заполняет пробел линейкой:

$$\hbox to 5cm{1\hrulefill 2\hrulefill 3}$$
\hbox to 5cm{1\hrulefill
2\hrulefill 3}

В TeXнической терминологии такие заполнители называют лидерами (leaders).

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

$$\hbox to 5cm{1\leaders \hbox{Ъ}\hfil 2}$$
\hbox to 5cm{1\leaders
\hbox{Ъ}\hfil 2}

Если бы мы хотели, чтоб буквы Ъ шли не вплотную, можно было бы, например, вместо "Ъ" написать так:

\hbox to 2em{\hfil Ъ\hfil}

В общем случае применяйте команду \leaders так:

\leaders $\langle$
\textit{блок}$\rangle$ $\langle\mbox{\cs(hfil)
\textit{или} \cs(hfill)}\rangle$

Здесь $$\langle блок\rangle$$ - это любая TeX'овская команда для генерации блока, например, \hbox, с которой мы уже познакомились, или \vbox или \copy, о которых еще пойдет речь. Команды LaTeX'а ( \mbox, \makebox, \parbox и т.п.) применять в этом контексте нельзя; если, тем не менее, хочется воспользоваться их возможностями, то их надо " спрятать" в \hbox, написав, например,

\hbox{\makebox[3em][r]{...}}

Между командой для генерации блока и командой \hfil или \hfill может быть пробел (например, конец строки). Команда \leaders работает так: выделяется столько свободного места, сколько получилось бы, если бы стояло просто \hfil или \hfill, а затем это место заполняется идущими вплотную друг к другу копиями $$\langle блок\rangle$$ столько раз, сколько этот блок поместится по ширине на выделенное место (если ширина свободного места меньше ширины блока, то ни разу).

С помощью команды \leaders можно также изменить толщину линейки, заполняющей свободное место. Именно, команда \hrulefill является по существу сокращением от

\leaders\hrule\hfill

Если же мы скажем, например,

\leaders\hrule height 1pt \hfill

то линейка будет иметь толщину 1 пункт, вместо принятых по умолчанию 0.4 пункта. Можно также написать \hfil вместо \hfill, с очевидными последствиями.

Клей

Выше мы рассмотрели команды \hfil и \hfill, которые действуют подобно вставленным в строку пружинам. Можно вставлять в строку пружины с самыми разнообразными свойствами, указав LaTeX'овской команде \hspace аргумент, содержащий plus- или minus-компоненту (в разд.3.9.4 мы упоминали об этой возможности, но в тот момент у нас еще не было серьезных примеров). Именно, если вы скажете

\hspace{"$x$ plus $y$ minus $z$"}

где $$x$$, $$y$$ и $$z$$ - длины, то вставите в текст пружину, которая в свободном состоянии имеет длину $$x$$, может увеличивать свою длину на $$y$$ и уменьшать свою длину на $$z$$ (в отличие от пружин, встречающихся в жизни, может выполняться неравенство $$x<z$$, и, того пуще, длины $$y$$ и $$z$$ могут быть отрицательными, но мы не будем объяснять, как TeX поведет себя в столь странной ситуации)Если мы заставим такую пружину растянуться или сжаться больше, чем сказано, то получим сообщение "Underfull \hbox " или "Overfull \hbox "; см.\ ниже. Здесь plus и minus - это, как мы помним, очередные ключевые слова TeX'а, наподобие to, width и height. Если мы создаем блок естественной ширины, то команда \hspace с таким аргументом создаст пробел размером $$x$$ ; если же мы в команде \hbox попросим TeX создать блок, ширина которого отличается от естественной, то для достижения требуемой ширины размеры пробелов будут изменяться. В TeXнической терминологии эти "пружины" называются клеем (Дональд Кнут отмечает, что название "клей" неудачно, но менять его поздно, поскольку оно, по его словам, "уже прилипло"). Длины $$y$$ и $$z$$, указанные после ключевых слов plus и minus, называются plus- и minus- компонентами клея. Длина $$x$$ называется естественным размером клея. С этой точки зрения команда \hfil также помещает в строку клей - с бесконечной растяжимостью и нулевым естественным размером.

Опишем более точно, как именно растягивается или сжимается клей при выполнении команды \hbox to ... Для простоты предположим дополнительно, что plus- и minus- компоненты клея всюду неотрицательны и что в строке отсутствует клей с бесконечной растяжимостью или сжимаемостью (в частности, в строке нет \hfil 'ов или \hfill 'ов; про клей с бесконечной сжимаемостью речь пойдет ниже). В этом случае TeX вычисляет "естественную ширину" блока, складывающуюся из ширин составляющих его элементов и естественных размеров клея, и сравнивает ее с требуемой шириной блока, указанной в команде \hbox после ключевого слова to. Если эти две ширины совпали, то все пробелы будут иметь естественный размер. Если требуемая ширина больше естественной, то TeX вычисляет, насколько больше, после чего "разверстывает" эту добавку между всеми пробелами пропорционально величинам plus - компонент клея в этих пробелах.

Вот пример. Предположим, мы создаем блок с помощью команды

\hbox to $a$ {А\hspace{0pt plus 2em}%
Б\hspace{1cm plus 1em minus 2mm}В}

где величина $$a$$ на $$13$$ мм больше суммы ширин букв А, Б и В, то пробел между А и Б будет равен $$2\,\rm мм$$, а пробел между Б и В - $$11\,\rm мм$$, поскольку plus - компонента клея между А и Б в два раза больше, чем plus - компонента клея между Б и В (и никакого другого клея в строке нет, так что ничего более растянуть нельзя). Если требуемая ширина меньше естественной, то уменьшение длины также распределяется между всеми элементами клея пропорционально величинам их minus-компонент. Если продолжить аналогию между TeX'овским клеем и пружинами, то можно сказать, что жесткость пружины при растяжении обратно пропорциональна величине plus-компоненты.

В приведенном примере оба пробела в блоке были созданы вручную командой \hspace ; если же в аргументе команды \hbox присутствуют пробелы, то следует учесть, что эти пробелы также, как мы объясняли ранее, обладают растяжимостью и сжимаемостью, которая также берется в расчет.

В случае, когда пробелы надо растягивать и требуемое растяжение блока больше, чем сумма plus - компонент всех элементов клея, на экран и в log -файл выдается знакомое вам сообщение Underfull \hbox ; если пробелы надо уменьшать и величина, на которую надо уменьшить ширину блока, меньше, чем сумма minus - компонент всех элементов клея, то выдается не менее знакомое сообщение Overfull \hbox.

Все сказанное относилось к случаю, когда бесконечно растяжимого клея в аргументе команды \hbox нет. Если же таковой присутствует (например, есть команда \hfil ) и пробелы надо растягивать, то растяжимость клея с конечными значениями plus -компонент утрачивается: соответствующие интервалы будут иметь естественный размер (что бы ни было написано в аргументе команды \hspace после plus), а все растяжения будут происходить только за счет команд \hfil. При этом сообщение об Underfull'е выдаваться не будет, как бы ни растянулись пробелы. Аналогично, если пробелы надо ужимать и присутствует клей с бесконечной сжимаемостью, все уменьшения пробелов произойдут только за его счет и никогда не будет выдано сообщения об Overfull'е.

Если в аргументе команды \hbox присутствуют команды \hfil и \hfill совместно, то при необходимости растягивать пробелы учитывается только \hfill, в то время как "в бесконечное число раз менее растяжимый" \hfil в расчет не берется (не говоря уж о клее с конечной растяжимостью):

$$\hbox to 4cm{\hfil Блоки и клей\hfil}\\ \hbox to 4cm{\hfil Блоки и клей\hfill}\\ \hbox to 4cm{\hfill Блоки и клей\hfill}$$
\hbox to 4cm
{\hfil Блоки и клей\hfil}
\hbox to 4cm
{\hfil Блоки и клей\hfill}
\hbox to 4cm
{\hfill Блоки и клей\hfill}

Ранее мы упоминали о том, что в аргументе команды \vspace может (вместо длины с plus- и/или minus-компонентой) стоять команда \fill (возможно, с коэффициентом). Как мы теперь понимаем, \vspace с таким аргументом также задает бесконечно растяжимый клей. Точнее говоря, \vspace{\fill} действует так же, как \hfill, в то время как команда \vspace{0.3\fill} задает клей, растяжимость которого составляет 30% от растяжимости \hfill (тем не менее, этот клей также "бесконечно растяжим" в том отношении, что его присутствие отменяет растяжимость \hfil 'ов и клея с конечными plus - компонентами).

Бесконечно сжимаемые интервалы

Мы уже два раза упомянули про клей с бесконечной сжимаемостью. Настало время объяснить, какими командами его создавать. Из многих способов укажем один, наиболее часто встречающийся. Команда \hss вставляет в строку клей, естественный размер которого равен нулю, и который при этом обладает бесконечной растяжимостью (подобно \hfil ) и бесконечной сжимаемостью. Типичное применение такого "бесконечно сжимаемого" клея — создавать блоки, ширина которых меньше реального размера текста, или блоки с наложением текстов. В самом деле, посмотрите на такой пример:

$$\hbox to 50pt {Кот\hss Пес}\\ \hbox{Кот\hss Пес}\\ \hbox to 30pt {Кот\hss Пес}\\ \hbox to 15pt {Кот\hss Пес}\\ \hbox to 0pt {Кот\hss Пес}$$
\hbox to 50pt {Кот\hss Пес}
\hbox{Кот\hss Пес}
\hbox to 30pt {Кот\hss Пес}
\hbox to 15pt {Кот\hss Пес}
\hbox to 0pt {Кот\hss Пес}

Если мы просим сделать ширину блока больше естественной, команда \hss действует так же, как и \hfil ; когда мы создаем блок с естественной шириной, слова "Кот" и " Пес" стоят вплотную друг к другу (естественная ширина клея, созданного \hss, равна нулю). Интересные вещи начинаются, когда мы просим, чтобы ширина была $$30\,\rm pt$$ (что меньше естественной). Интервал между словами при этом приходится уменьшить; поскольку его естественный размер равен нулю, то после уменьшения интервал становится отрицательным, т. е. слово " пес" сдвигается влево (накладываясь на слово "Кот"), причем сдвигается так, чтобы ширина блока (т. е. расстояние от начала слова "Кот" до конца слова "Пес") равнялась требуемым $$30\,\rm pt$$. Когда же мы наконец просим, чтобы ширина блока равнялась нулю, слову "Пес" приходится сдвинуться влево настолько, чтобы расстояние от его конца до начала слова "Кот" равнялось нулю - иными словами, кот и пес меняются местами! Заметим, кстати, что точка отсчета всех наших блоков совпадает с точкой отсчета буквы К из слова "Кот".

Еще один пример использования \hss: как создать блок, точка отсчета которого будет находиться в правом, а не левом конце текста (мы столкнулись с этой проблемой в лекции 5)? Ответ: надо сказать

\hbox to 0pt{\hss текст}

и все будет в порядке. В самом деле, \текст имеет ширину, отличную от нуля; чтобы блок имел в итоге нулевую ширину, приходится "уменьшать" тот интервал, где стоит \hss ; так как интервал уже нулевой, то это уменьшение сводится к тому, что текст сдвигается влево до тех пор, пока расстояние между его концом и точкой отсчета не станет равным нулю - а это и означает, что правый конец текста стал его точкой отсчета. В лекции 5 мы сказали, что эта проблема решается с помощью TeX'овской команды \llap, а теперь мы видим, как ее можно определить:

\newcommand{\llap}[1]{\hbox to 0pt{\hss #1}}

Кстати говоря, именно так она и определяется.

А если сказать

\hbox to 0pt{текст \hss}

то что, спрашивается, будет? Ответ: на сей раз будет уменьшаться интервал после текста; стало быть, сам текст никуда не сдвинется, но после него будет сделан такой "отрицательный пробел", чтобы суммарная ширина равнялась нулю. Иными словами, TeX будет просто считать, что ширина блока равняется нулю - мы обманули TeX, убедив его, что наш текст не занимает места по горизонтали! Для такого обмана (к нему приходится прибегать нередко) предусмотрена специальная TeX'овская команда \rlap, определяемая так:

\newcommand{\rlap}[1]{\hbox to 0pt{#1\hss}}

Все это также напоминает ситуацию с командой \lefteqn — и напоминает не случайно, поскольку эта команда определяется фактически так:

\newcommand{\lefteqn}[1]{\rlap{$\displaystyle #1$\hss}}

Еще раз о линейках

В аргументе команды \hbox может присутствовать и TeX'овская команда \vrule. Ее ценность в том, что она автоматически создает линейку, высота и глубина которой равна высоте и глубине объемлющего блока (ширина этой линейки будет по умолчанию равна $$0{,}4$$ пункта). Как объяснялось в разд. 3.10 , можно задать в явном виде ширину линейки с помощью ключевого слова width, высоту - с помощью ключевого слова height, а также (о чем в лекции 3 не говорилось) глубину с помощью ключевого слова depth (эти три ключевых слова могут следовать после \vrule в произвольном порядке). Приведем один пример использования \vrule внутри \hbox.

$$\begin{flushleft} \hbox{% \vrule\hspace{.5em}\parbox{.9\textwidth}% {Иногда используется следующий способ выделения текста: абзац набирается с некоторым отступом от левого поля, а слева от него, вровень с левым полем, печатается вертикальная линейка.}} \end{flushleft}$$

Предыдущий абзац в исходном тексте выглядел так:

\begin{flushleft}
\hbox{%
\vrule\hspace{.5em}\parbox{.9\textwidth}%
{Иногда используется следующий способ выделения текста:
абзац набирается с некоторым отступом от левого поля,
а слева от него, вровень с левым полем, печатается
вертикальная линейка.}}
\end{flushleft}

Этот текст нуждается в некоторых пояснениях. Во-первых, в последней строке первая из фигурных скобок закрывает аргумент команды \parbox, а вторая - \hbox. Во-вторых, мы воспользовались окружением \flushleft, чтобы LaTeX сам позаботился о разумных отступах до и после абзаца. Параметр \textwidth означает, как мы помним, ширину страницы. Теперь рассмотрим, что присутствует внутри \hbox. Сначала там идет линейка, затем отступ на $$0.5\,\rm em$$, и затем — огромная " буква", созданная командой \parbox. Согласно общему правилу, высота и глубина линейки, заданной командой \vrule, равна высоте и глубине объемлющего блока, а они в нашем случае совпадают с высотой и глубиной "огромной буквы" (ведь кроме нее, другого текста в нашем \hbox нет). Тем самым линейка получается как раз нужных размеров, что и требовалось!

Обратите еще внимание на знак процента после \hbox — без него получилось бы, что аргумент команды \hbox начинается с пробела, соответственно и линейка начиналась бы не с начала, а после пробела .

На самом деле в предыдущем примере было бы лучше, если бы правый край выделенного абзаца шел вровень с правым краем остального текста. Чтобы добиться этого, надо первый аргумент команды \parbox не взять с потолка, а вычислить. Для этого нам понадобятся переменные со значением длины. Предполагая, что мы определили с помощью \newlength переменные \shirina и \raznost, сделаем вот что:

\begin{flushleft}
\shirina=\textwidth
\settowidth{\raznost}{\vrule\hspace{.5em}}
\addtolength{\shirina}{-\raznost}
\noindent\hbox{%
\vrule\hspace{.5em}\parbox{\shirina}%
{Иногда используется ...
... линейка.}}
\end{flushleft}

Мы воспользовались командой \settowidth, чтобы найти размер, который занимает линейка вместе с пробелом. Кстати, если просто написать \hbox{\vrule\hspace{.5em}}, то на печати мы ничего не увидим (внутри \hbox 'а никакого текста нет, так что высота и глубина линейки равна нулю и она тем самым невидима); однако же эта команда создаст пробел, величина которого равна 0.4pt плюс 0.5em. Заключительное замечание: поскольку {flushright}, как и всякое окружение, ограничивает группу, все наши манипуляции с параметрами \shirina и "\raznost" забудутся по выходе из этого окружения.

Команда \vbox

Теперь рассмотрим вторую основную команду TeX'а для генерации блоков — команду \vbox. Эта команда создает блок, обрабатывая текст в вертикальном режиме. Вот первый пример:

$$\vbox{\hbox{Слово} \hbox{Еще слово}}$$
\vbox{\hbox{Слово}
\hbox{Еще слово}}

Получаемый блок имеет вид:

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

Прежде чем идти дальше, обсудим, что может содержаться в аргументе команды \vbox. Там могут присутствовать любые TeX'овские команды, допустимые между абзацами (т.е. в вертикальном режиме): команды \vspace, команды смены шрифта, присваивания значений различным параметрам, команды \newcommand и \renewcommand и т.п. Что же касается команд, которым соответствует что-либо на печати, то будем считать, что из них в аргументе \vbox возможны только TeX'овские команды \hbox, \vbox и \hrule, а также \copy, о которой речь пойдет позже. В частности, недопустим ни текст, ни LaTeX'овские команды \mbox, \parbox, \rule и т.п. Если вам требуется воспользоваться возможностями таких команд, "прячьте" их в \hbox, например, так:

\hbox{\raisebox{1pt}[2em][3em]{...}}

На самом деле в аргументе команды \vbox может находиться и обычный текст; при появлении первой же буквы или, скажем, команды \mbox или другой команды LaTeX'а для генерации блоков TeX переходит в горизонтальный режим, который продолжается до команды, завершающей абзац ( \par или пустой строки). Мы не будем вдаваться в детали; для тех приложений, которые мы имеем в виду, достаточно использовать команду \vbox так, как было предписано выше.

Когда TeX при выполнении команды \vbox составляет блоки друг с другом, он располагает их так, чтобы их базисные линии были, по возможности, на равных расстояниях друг от друга, так что обычно между блоками будет присутствовать дополнительный пробел. С другой стороны, линейки, созданные командой \hrule, приставляются к блокам без дополнительного пробела. Чтобы при этом линейка не оказалась вплотную к тексту, удобно в соответствующий блок вставить \strut. Следующий пример призван пояснить сказанное:

$$\parindent=0pt Неудачно:\\ \vbox{\hbox{Два слова} \hrule} Лучше так:\\ \vbox{\hbox{\strut Два слова} \hrule}$$
Неудачно:\\
\vbox{\hbox{Два слова}
      \hrule}

Лучше так:\\
\vbox{\hbox{\strut Два слова}
     \hrule}

Как обычно, \vbox посреди абзаца ведет себя просто как большая буква. Обратите также внимание, что мы не пытались убрать лишний пробел между \hbox и \hrule: в вертикальном режиме пробелы никакого влияния на текст не оказывают.

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

$$\vbox{\hrule \hbox{\vrule\,\strut Текст в рамке\,\vrule} \hrule}$$
\vbox{\hrule
\hbox{\vrule\,\strut
Текст в рамке\,\vrule}
\hrule}

По-прежнему мы используем \strut, чтобы горизонтальные линейки не подходили слишком близко к тексту (и \ для той же цели по горизонтали).

Блоковые переменные

В тех случаях, когда один и тот же фрагмент текста (например, фрагмент псевдорисунка, являющийся аргументом команды \multiput ) используется многократно, бывает полезно сверстать этот фрагмент раз и навсегда, а затем просто повторять его: это сэкономит как количество нажатий на клавиши, так и машинное время. Использование макроопределения в данном случае времени не сэкономит: если мы напишем, например,

\newcommand{\abcd}{\parbox{6cm}%
{Когда в товарищах согласья нет,
на лад их дело не пойдет, и выйдет
из него не дело — только м\'ука.}}

то при каждой обработке команды \abcd это макроопределение будет заново развертываться, и TeX будет заново находить переносы и места разрыва строк в одном и том же отрывке из " Лебедя, рака и щуки". Чтобы не заставлять TeX много раз повторять идентичные операции по верстке текста, надо сделать так. Во-первых, определим "блоковую переменную", которая будет хранить сверстанный фрагмент текста. Это делается с помощью команды \newsavebox. Единственный аргумент этой команды - имя новой блоковой переменной, которое должно удовлетворять тем же условиям, что любые имена TeX'овских команд: либо backslash с одной не-буквой, либо backslash с последовательностью букв. Имя новой блоковой переменной не должно совпадать с именем уже существующей команды или переменной длины (если вы попытаетесь нарушить это правило, LaTeX выдаст сообщение об ошибке). Во-вторых, присвоим нашей блоковой переменной значение — блок, и будем в дальнейшем этот блок использовать.

Давайте приведем пример того, как можно этим пользоваться. Выше мы приводили пример псевдорисунка — наклонной решетки, и там же мы отметили, что экономнее было бы создать наклонный отрезок раз и навсегда, а затем только повторять его. Теперь мы можем объяснить, как это сделать. Создадим блоковую переменную под названием \blok, написав в преамбуле следующее:

\newsavebox{\blok}

Теперь сверстаем тот текст, который будет храниться в нашей блоковой переменной, и запишем его в эту переменную. Для этих целей используется команда \sbox с двумя обязательными аргументами: первый — имя блоковой переменной, второй — текст, который в нее записывается. Итак:

\sbox{\blok}{\line(1,5){10}}

А теперь можно воспользоваться нашей блоковой переменной. Чтобы напечатать содержимое блоковой переменной, используется команда \usebox с одним обязательным аргументом — именем переменной. В нашем случае мы используем блоковую переменную в аргументе команды \multiput:

$$\newsavebox{\blok} \sbox{\blok}{\line(1,5){10}} \parindent=0pt \begin{picture}(100,50) \multiput(0,0)(10,0){10}% {\usebox{\blok}} \multiput(0,0)(2,10){6}% {\line(1,0){90}} \end{picture}$$
\begin{picture}(100,50)
\multiput(0,0)(10,0){10}%
{\usebox{\blok}}
\multiput(0,0)(2,10){6}%
{\line(1,0){90}}
\end{picture}

Можно было бы сделать аналогичный трюк и с горизонтальными линейками решетки, но большой экономии это не даст: горизонтальные и вертикальные линейки на псевдорисунках LaTeX не собирает из отдельных символов, а создает "в один присест" с помощью команд \hrule и \vrule, что и так достаточно быстро.

Текст, присутствующий в аргументе команды \sbox, будет сверстан в виде блока так, как если бы этот текст был передан в качестве аргумента команде \hbox или \mbox. Тем самым в аргументе \sbox может быть все то же, что может присутствовать в аргументе \hbox или \mbox. Если команда \sbox была дана внутри группы, то по выходе из этой группы содержимое блоковой переменной забудется.

Наряду с командой \sbox есть еще и команда \savebox, относящаяся к ней примерно так же, как \makebox относится к \mbox: между первым и вторым обязательным аргументами команды \savebox могут присутствовать необязательные аргументы, имеющие тот же смысл и записывающиеся так же, как необязательные аргументы команды \makebox. Например,

\savebox{\пример}[4cm][r]{Слово}

даст тот же результат, что и

\sbox{\пример}{\makebox[4cm][r]{Слово}}

Наряду с LaTeX'овской командой \usebox есть похожая на нее, но не идентичная, TeX'овская команда \copy. Используется она так:

$$\sbox{\blok}{Рак} Однажды Лебедь, \copy\blok{} и Щука\ldots$$
\sbox{\blok}{Рак}
Однажды Лебедь,
\copy\blok{} и Щука\ldots

Обратите внимание, что при использовании команды \copy имя блоковой переменной не заключается в фигурные скобки! Различие между \copy и \usebox такое же, как между \hbox и \mbox: будучи употребленными внутри абзаца (или, скажем, в аргументе команд \put, \hbox или \mbox ), эти две команды действуют совершенно одинаково, а вот будучи употребленным между абзацами, LaTeX'овское \usebox начинает новый абзац, в то время как TeX'овское \copy просто подверстывает блок к странице, нового абзаца не начиная. Эту разницу следует иметь в виду, когда вы работаете с командой \leaders: выгоднее сверстать блок один раз и записать его в блоковую переменную, а затем в команде \leaders писать просто \copy. Пример:

$$\savebox{\blok}[1cm]{$*$} \hbox to \textwidth {\leaders\copy\blok\hfil}$$
\savebox{\blok}[1cm]{$*$}
\hbox to \textwidth
{\leaders\copy\blok\hfil}

В этой ситуации по TeXническим причинам сказать \usebox нельзя.

Для тех, кто будет читать следующую лекцию, скажем еще об одной конструкции, связанной с блоковыми переменными. Именно, если \blok — блоковая переменная, то можно " измерить" ширину, высоту и глубину блока, записанного в этой переменной, с помощью TeX'овских команд \wd, \ht и \dp. Точнее говоря, сочетания \wd\blok, \ht\blok и \dp\blok можно использовать в точности так же, как TeX'овские параметры со значением длины, значения которых равны ширине, высоте и глубине блока:

$$\sbox{\blok}{12345}\copy\blok\\ \hbox to \wd\blok{\hfil 345}\\ \hbox to \wd\blok{\hfil 45}$$
\sbox{\blok}{12345}\copy\blok\\
\hbox to \wd\blok{\hfil 345}\\
\hbox to \wd\blok{\hfil 45}

Для большинства элементарных приложений в LaTeX'е вполне хватает возможностей измерения блоков, предоставляемых командой \settowidth и ее аналогами, но в лекции 9 нам встретятся ситуации, в которых без \wd не обойтись.

Страницы:

Текст состоит из блоков

Мы уже отмечали, что в процессе набора TeX не принимает во внимание, как буквы будут выглядеть на печати, а лишь учитывает, сколько места надо отвести на каждый символ. Давайте обсудим этот процесс подробнее.

С точки зрения TeX'а, каждая буква представляет собой блок (английский термин: box), т.е. прямоугольник с выделенной точкой отсчета ; горизонтальная прямая, проходящая через точку отсчета, называется базисной линией (английский термин: baseline). Блок характеризуется тремя размерами: шириной, высотой и глубиной. См. рисунок, на котором также изображен блок, соответствующий букве у.

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

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

В приведенных выше примерах мы сталкивались с блоками, которые TeX создает автоматически; в настоящей лекции пойдет речь о командах, предназначенных для создания блоков вручную. Сначала мы расскажем, какие средства для этого предоставляет нам LaTeX, а затем рассмотрим некоторые TeX'овские команды, дающие дополнительные возможности.

Команды LaTeX'а для генерации блоков

Блоки из строки

С одной командой для генерации блоков мы уже знакомы: это команда \mbox. Эта команда создает блок из текста, набираемого в одну строку. Полученный блок рассматривается TeX'ом как одна буква:

$$Проказница мартышка, \mbox{осел, козел} и косолапый мишка\ldots$$
Проказница мартышка,
\mbox{осел, козел} и
косолапый мишка\ldots

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

Теперь, когда мы знаем, что такое TeX'овские блоки, можно признаться, что окружения {picture},{tabular} и {array} тоже генерируют блоки, и именно поэтому создаваемый ими текст воспринимается TeX'ом как одна большая буква.

В аргументе команды \mbox может присутствовать все то же, что может быть в обычном тексте в пределах одной строки: математические формулы, команды смены шрифта или присваивания значений каким-то параметрам, команды для генерации блоков (например, тот же \mbox, или даже окружения {picture} или {array} ) и т.д. Запрещены в аргументе команды \mbox пустые строки или команды \par, выключные математические формулы, окружения, определяющие абзацы специального вида (скажем, {itemize} или {center}), команда \\ и тому подобные вещи, "не вписывающиеся в строку". Если в аргументе команды \mbox происходит смена шрифта, изменение каких-то параметров или определение команд, то по выходе из блока все эти изменения забываются, поскольку фигурные скобки, ограничивающие аргумент команды \mbox, ограничивают также и группу (" глобальные" команды вроде \setcounter сохраняют свое действие и по выходе из блока).

Блок, создаваемый командой \mbox, имеет ширину, равную " естественной" длине строки текста, являющегося его аргументом. Можно также создать блок из строки текста, ширина которого отлична от ее естественной длины. Для этого используется команда \makebox. Эта команда имеет один обязательный аргумент, имеющий такой же смысл, как аргумент команды \mbox, и, кроме того, необязательный аргумент — ширину блока, порождаемого командой:

$$Туда \makebox[5em]{и} обратно$$.
Туда \makebox[5em]{и} обратно.

Как видите, необязательный аргумент ставится перед обязательным; длина в нем может быть указана, как обычно, либо в какой-либо из TeX'овских единиц, либо как параметр со значением длины, возможно — с числовым коэффициентом. Сам текст, являющийся обязательным аргументом команды \makebox, размещается по центру в блоке ширины, указанной в необязательном аргументе. Если указать в необязательном аргументе команды \makebox ширину, меньшую естественной длины строки, то текст выйдет за края блока; поскольку место, отводимое TeX'ом блоку, определяется только тем, каковы ширина, высота и глубина блока, а не тем, какие размеры реально имеет текст, содержащийся в блоке, при этом может возникать наложение одного текста на другой. Например, размеры и точка отсчета блока, создаваемого командой \makebox[1.5em]{123456}, выглядят с точки зрения TeX'а так:

Для ясности мы использовали в этом примере крупный шрифт. А вот как такой "выпирающий за края" блок взаимодействует с окружающим текстом:

$$текст\makebox[1.5em]{123456}текст$$
текст\makebox[1.5em]{123456}текст

Можно также создать блок заданной ширины, в котором текст будет не центрирован, а прижат к правому или левому краю (полиграфисты говорят: " выключен вправо или влево"). Для этого в команде \makebox предусмотрен второй необязательный аргумент - буква l для текста, выключенного влево, или r для текста, выключенного вправо (можно также указать аргумент c - тогда текст будет центрирован, так же, как если бы второго необязательного аргумента не было). Пример:

$$\parindent=0pt \makebox[10em][r]{текст}\\ \makebox[10em][r]{екст}\\ \makebox[10em][r]{кст}\\ \makebox[10em][c]{текст}\\ \makebox[10em][l]{текст}$$
\parindent=0pt
\makebox[10em][r]{текст}\\
\makebox[10em][r]{екст}\\
\makebox[10em][r]{кст}\\
\makebox[10em][c]{текст}\\
\makebox[10em][l]{текст}

Мы установили нулевое значение абзацного отступа, чтобы все строки, включая первую, начинались с самого начала. Кстати, обратите внимание, что у нас получилась верстка с выравниванием без помощи таких вещей, как tabbing или tabular.

У команды \makebox значение ширины блока можно установить равным нулю. Если при этом присутствует необязательный аргумент l, то получится блок нулевой ширины, а текст будет выходить за его пределы вправо (и, стало быть, наложится на последующий текст в строке, если таковой присутствует); если присутствует необязательный аргумент r, то текст будет выходить влево за пределы блока (и тем самым накладываться на предшествующий текст):

$$текст\makebox[0pt][l]{???}текст\\ текст\makebox[0pt][r]{???}текст\\$$
текст\makebox[0pt][l]{???}текст\\
текст\makebox[0pt][r]{???}текст\\

Наряду с r (" прижатый вправо"), l ("прижатый влево") и c ("центрированный"), в качестве второго необязательного аргумента команды \makebox можно использовать и букву s, с которой начинаются английские слова stretched (растянутый) и shrunk (ужатый). Соответственно, при указании такого второго необязательного аргумента текст будет равномерно растянут или сжат до ширины, указанной в первом необязательном аргументе. Если при этом придется превысить предел растяжимости, то появится сообщение Underfull \hbox, а если окажется, что превышен предел сжимаемости, то вы увидите сообщение Overfull \hbox. Чтобы осмысленно применять \makebox с необязательным аргументом s, надо уметь управлять растяжимостью и сжимаемостью промежутков. Как это делать, рассказано в следующем разделе.

До сих пор мы задавали ширину блока в команде \mbox в явном виде. Можно, кроме того, выразить эту ширину через " естественную" ширину текста. Для этого служит команда \width. Вот, например, как сделать, чтобы чтобы ширина блока, получаемого с помощью \makebox, была на 30% больше естественной:

$$\makebox{скоросшиватель}\\[2pt] \makebox[1.3\width][r]{скоросшиватель}$$
\makebox{скоросшиватель}\\[2pt]
\makebox[1.3\width][r]
{скоросшиватель}

Командой \width можно пользоваться только внутри необязательного аргумента \makebox (или \framebox — см. ниже). Не пытайтесь пользоваться ею в качестве параметра со значением длины — ничего хорошего из этого не выйдет.

Блоки из абзацев

Если необходимо создать блок, в котором размещается сверстанный TeX'ом абзац текста, то можно воспользоваться командой \parbox. У этой команды два обязательных аргумента: первый — длина строк в получаемом абзаце, второй — собственно текст. Например, такой текст

$$\parbox{30cm}{ В строку\qquad \parbox{4cm}{вставили целый абзац текста, сверстанного по всем TeX'овским правилам. После этого продолжается}\qquad прерванная строка. }$$
В строку\qquad
\parbox{4cm}
{вставили целый
абзац текста, 
сверстанного
по всем TeX'овским 
правилам.
После этого 
продолжается}\qquad
прерванная строка.

Как видите, базисная линия блока, создаваемого командой \parbox, находится в точности посредине текста. Поэтому команду \parbox удобно использовать для включения больших фрагментов текста в математические формулы. Например, формула

$$\int_a^b f'(x)\,dx=f(b)-f(a)\qquad \parbox{4cm}{для всех функций f, производная которых интегрируема по Риману}$$

получается из такого исходного текста:

$$
  \int_a^b f'(x)\,dx=f(b)-f(a)\qquad
  \parbox{4cm}{для всех функций f,
  производная которых интегрируема
  по Риману}
$$

Если дать команду \parbox с необязательным аргументом, то создаваемый ею блок можно расположить относительно строки и по-иному: чтобы вровень с остальной строкой шла самая верхняя строка абзаца (для этого нужен аргумент t ) или самая нижняя (аргумент b ); можно также указать аргумент c — тогда блок будет расположен по центру, так же, как если бы необязательного аргумента вообще не было. Необязательный аргумент у этой команды должен идти перед обязательными.

Во втором обязательном аргументе команды \parbox, задающем текст, может присутствовать всё то же, что в обычном тексте, в том числе команды для вертикальных пробелов наподобие \vspace, пустые строки, разделяющие абзацы, выключные формулы и т.п. Абзацы, создаваемые командой \parbox, по умолчанию делаются без абзацного отступа и в режиме \sloppy. Если вы хотите чего-то другого, можно прямо внутри аргумента команды \parbox установить нужное вам значение абзацного отступа, параметра \tolerance и т.п.

Можно также указать LaTeX'у высоту, которую должен иметь блок, полученный в результате применения команды \parbox. Для этого используется второй необязательный аргумент, идущий непосредственно после первого. Наряду с явным указанием размера, можно воспользоваться командой \height, обозначающей " естественную" высоту текста, а также командой \totalheight (высота плюс глубина).

Наконец, в команде \parbox можно указать, как именно должен быть расположен текст внутри блока. Для этого используется третий необязательный аргумент, следующий непосредственно после второго. Этот аргумент — буква t, b, c или s. Буква t означает " сверху", b — "снизу", c — "по центру". Если третий необязательный аргумент не указан, то по умолчанию считается, что он совпадает с первым. Если же третьим необязательным аргументом является s, это означает, что текст будет растянут или ужат в соответствии с размером, указанным во втором необязательном аргументе. Если вы не позаботитесь о специальных командах, обеспечивающих такую растяжимость или сжимаемость, то получите сообщение об Overfullе или Underfullе.

В следующем примере блоки, созданные командой \parbox, для наглядности взяты в рамку (с помощью \fbox ):

$$\fbox{% \parbox[b][1.3\height]{2cm}{% Мы едем, едем, едем в далекие края.}}\qquad \fbox{% \parbox[t][1.3\height]{2cm}{% Мы едем, едем, едем в далекие края.}}$$
\fbox{%
\parbox[b][1.3\height]{2cm}{%
Мы едем, едем, едем
в далекие края.}}\qquad
\fbox{%
\parbox[t][1.3\height]{2cm}{%
Мы едем, едем, едем
в далекие края.}}

Команды \height и \totalheight, так же как и \depth, можно использовать только в необязательном аргументе команды \parbox (а также \framebox или \makebox ).

Наряду с \parbox, существует еще один способ создать блок из абзацев. Именно, существует окружение {minipage} (" министраница"), генерирующее блок из текста, расположенного внутри этого окружения; блок состоит из абзацев, ширина которых задается в обязательном аргументе окружения {minipage} (так же, как в команде \parbox ); перед обязательным аргументом этого окружения может стоять необязательный: буква t, b или c, причем смысл этого аргумента опять-таки такой же, как в команде \parbox. Основное отличие minipage от \parbox в том, что к тексту внутри этого окружения можно делать сноски с помощью команды \footnote, причем текст сноски появляется не внизу страницы, а внизу блока, генерируемого окружением minipage. При наборе книги, которую вы читаете, это окружение использовалось для печати примеров.

Текст в рамке; комбинации блоков

В лекции 3 мы уже упоминали про команду \fbox, берущую в рамку фрагмент текста, помещающегося в строку. Наряду с ней есть и команда \framebox, относящаяся к ней так же, как \makebox относится к \mbox: она берет текст в рамку заданного размера, причем текст внутри этой рамки либо центрирует (если необязательного аргумента нет или же задан необязательный аргумент c), либо прижимает к правому или левому краю рамки (если задан необязательный аргумент r или l). Смысл и расположение обязательных и необязательных аргументов у команды \framebox такой же, как и у команды \makebox.

Точнее говоря, первый обязательный аргумент команды \framebox задает не ширину рамки, а ширину текста, помещаемого в эту рамку. Сама же рамка отделена от текста пробелом ширины \fboxsep ; толщина линий в рамке равна \fboxrule. Обоим этим параметрам можно обычным образом присваивать новые значения.

Коль скоро каждый блок, создаваемый LaTeX'овскими командами, рассматривается TeX'ом просто как большая буква, возможны любые, сколь угодно причудливые, комбинации таких "букв". Пусть, например, нам надо взять в рамку абзац текста шириной $$6$$ см, чтобы получилось так:

$$\begin{center}\hbadness 2500 \fbox{% \parbox{6cm}{% Внутри \TeX'овских блоков может присутствовать не только собственно текст или формулы, но и другие блоки, внутри этих блоков - еще блоки, и так далее. Таким образом, блоки могут быть вложены друг в друга, как матрешки.}% } \end{center}$$

Просто поместить этот текст в аргумент команды \fbox не получится, поскольку наш текст в одну строку не укладывается, а команда \fbox, подобно команде \mbox, текстов, не укладывающихся в строку, не переваривает. Поэтому нужно сделать из нашего абзаца блок с помощью команды \parbox и этот блок (т.е. уже "букву") передать в качестве аргумента команде \fbox:

\fbox{%
\parbox{6cm}{%
Внутри TeX'овских блоков может ...
... друг в друга, как матрешки.}%
}

Обратите внимание на знаки процента, которыми заканчиваются первая и предпоследняя строки. Если бы их не было, то рамка отстояла бы от текста больше, чем надо, так как TeX решил бы, что аргумент команды \fbox имеет пробел до и после "буквы", созданной командой \parbox. См.лекцию 1 по поводу использования знака процента для удаления нежелательных пробелов.

Сдвиги относительно базисной линии

Когда при исполнении команды \makebox или \mbox TeX создает блок из меньших блоков (каждая буква, как мы помним, - это блок, из букв составляются слова - тоже блоки; наконец, блоки могут быть заданы в явном виде, в частности, командой \mbox ), то блоки эти размещаются в строке таким образом, что все их точки отсчета расположены на одной высоте (иными словами, их базисные линии продолжают одна другую). Можно, однако, сдвинуть блок по вертикали относительно базисной линии. Для этого удобно воспользоваться LaTeX'овской командой \raisebox. Эта команда требует двух обязательных аргументов. Первый из них - расстояние, на которое сдвигается по вертикали фрагмент текста, второй - сам этот фрагмент текста. Пример:

$$Слово \raisebox{2pt}{подскочило} в строке$$.
Слово \raisebox{2pt}{подскочило}
в строке.

Текст, расположенный во втором обязательном аргументе этой команды, должен удовлетворять тем же требованиям, что и аргумент команды \mbox: в нем могут быть самые разные TeX'овские команды, при условии, что среди них не будет команд типа пустой строки, \par, \\ и тому подобных, которые "не укладываются в строку" (зато в этом тексте, как водится, могут присутствовать любые команды, порождающие блоки, в частности, например, \parbox, а уж в ее аргументе оставляйте пустых строк, сколько душе угодно). Если первый обязательный аргумент команды \raisebox отрицателен, то текст будет, естественно, не поднят, а опущен. Вот, например, как можно определить команду \tex, печатающую эмблему TeX'а:

\newcommand{\TeX}{T\nolinebreak\hspace{-.1667em}\raisebox
            {-.5ex}{E}\nolinebreak\hspace{-.125em}X}

Тут же мы видим и примеры использования отрицательных промежутков для того, чтобы буквы сблизились. Команды \nolinebreak нужны, чтобы не случилось разрыва строки посередине эмблемы.

На самом деле команда \TeX определяется более экономным способом, который требует меньше машинного времени и памяти, но использует не рассматриваемые нами средства TeX'а. Время от времени мы будем приводить определения команд "в переводе с TeX'а на LaTeX".

Кроме вертикального сдвига блоков, команда \raisebox может делать еще одно полезное дело: с ее помощью можно обмануть TeX, заставив его считать, что блок, полученный после сдвига, имеет любую заданную нами высоту и глубину, независимо от того, сколько места реально занимает текст. Именно, эта команда может принимать, наряду с обязательными, необязательные аргументы. Между двумя обязательными аргументами можно указать необязательный аргумент — высоту, которую, по мнению TeX'а, должен иметь сдвинутый блок. Кроме того, после первого необязательного аргумента может стоять второй — глубина, которую, по мнению TeX'а, будет иметь сдвинутый блок. Вот пример:

$$Строка.\\ Вторая \raisebox{7pt}[1pt][10pt]{Ы}\\ Третья строка$$.
Строка.\\
Вторая
\raisebox{7pt}[1pt][10pt]{Ы}\\
Третья строка.

Буква Ы, поднятая на 7 пунктов над строкой, наложилась на первую строку, поскольку в первом необязательном аргументе команды \raisebox мы приказали TeX'у считать, что блок, образованный поднятой буквой Ы, имеет высоту всего лишь один пункт (стало быть, возвышается над базисной линией второй строки меньше, чем любая буква), и соответственно TeX не сделал дополнительного интервала между первой и второй строками. С другой стороны, третья строка отодвинулась от второй, поскольку во втором необязательном аргументе команды \raisebox мы велели TeX'у считать, что глубина блока, образованного поднятой буквой Ы, равна целым десяти пунктам, и TeX послушно оставил дополнительное место, чтобы этот блок не наложился на третью строку!

Иногда разумно использовать команду \raisebox даже с нулевым обязательным аргументом, только для того, чтобы менять (в глазах TeX'а) высоту и/или глубину блока, не сдвигая его относительно базисной линии. В лекции 9 мы увидим пример такого использования этой команды.

Команда \hbox

Возможности, предоставляемые LaTeX'ом для генерации блоков, достаточны для простых приложений, но в более серьезных случаях их не хватает. В этом и следующем разделах мы рассмотрим более гибкие средства, предоставляемые для этой цели непосредственно языком TeX и макропакетом Plain - TeX. Мы не будем пытаться описать все TeX'овские команды для генерации блоков (книгу [2] ничто заменить не может), но сообщим тот минимум сведений, который необходим для модификации LaTeX'овского стандартного оформления, о чем пойдет речь в следующей лекции. Подчеркнем, что всеми описываемыми в этом и следующем разделах TeX'овскими средствами можно пользоваться в LaTeX'овских исходных текстах.

Прежде всего давайте вспомним, что в каждый момент трансляции исходного текста TeX находится в одном из трех следующих режимов: горизонтальном (в процессе верстки абзаца), вертикальном (между абзацами), или математическом (в процессе набора математической формулы); при появлении первой же буквы или LaTeX'овской команды для генерации блока или линейки (к таковым относятся \mbox, \makebox, \fbox, \framebox, окружения {array}, {tabular} или {picture}, а также команда \ruleНо не \hrule или \vrule: это команды TeX'а, а не LaTeX'а. ) TeX из вертикального режима выходит и начинает очередной абзац.

Одна из основных TeX'овских команд для генерации блоков называется \hbox. В своем простейшем виде она полностью аналогична LaTeX'овской команде \mbox, с одним важным отличием: в вертикальном режиме команда \hbox не начинает нового абзаца, а только добавляет сгенерированный ею блок (т. е.\ фактически строку) к уже сверстанной части страницы. Внутри абзаца (в горизонтальном режиме) команда \hbox действует точно так же, как и \mbox. Вот пример:

$$На странице \hbox{уже} присутствует абзац текста. После того, как он кончится, TeX{} перейдет в вертикальный режим. \hbox{Строка} \hbox{Еще строка} Только теперь начинается новый абзац.$$
На странице \hbox{уже}
присутствует абзац текста.
После того, как он
кончится, TeX{} перейдет в
вертикальный режим.

\hbox{Строка} \hbox{Еще строка}
Только
теперь начинается новый абзац.

Сравните с тем, что было бы при использовании LaTeX'овской команды \mbox вместо \hbox:

$$На странице уже присутствует абзац текста. После того, как он кончится, TeX перейдет в вертикальный режим. \mbox{Эти слова} сразу начинают новый абзац.$$
На странице уже присутствует
абзац текста. После того, как
он кончится, TeX перейдет
в вертикальный режим.

\mbox{Эти слова} сразу
начинают новый абзац.

Растяжимые интервалы

До сих пор шла речь о важных, но непринципиальных различиях между TeX'овским \hbox и LaTeX'овским \mbox. Теперь поговорим о дополнительных возможностях, предоставляемых TeX'овской командой.

Команда \hbox "в чистом виде" создает блок, ширина которого равна естественной длине текста, являющегося ее аргументом. Кроме этого, она может создавать блоки любой заданной ширины. Для этого нужно сказать

\hbox to {ширина}{текст}

Здесь {ширина}должна быть выражена в воспринимаемых TeX'ом единицах длины: это может быть, например, 20pt, или 2.3cm, или, например, 0.12\textwidth - параметр со значением длины (возможно, с коэффициентом) тоже годится. Между to и обозначением ширины, а также между обозначением ширины и открывающей фигурной скобкой могут быть пробелы - TeX их проигнорируетПустых строк, однако, быть не должно.. Наконец, отсутствие backslash в слове to не является опечаткой: это не команда, а одно из "ключевых слов" TeX'а (подобно ключевым словам plus и minus, с которыми мы вскоре снова встретимся, или width и height, с которыми мы уже встречались в разделе, посвященном линейкам). Давайте опробуем эту новую возможность команды \hbox:

$$\hbox to 3cm {Два слова}$$
\hbox to 3cm {Два слова}

Если вы опробовали этот пример на вашем компьютере, то заметили, что на экране появилось сообщение

Underfull \hbox

Дело в том, что пробел между словами "Два" и " слова" не может растянуться настолько, чтобы наш блок имел ширину три сантиметра; в ситуациях, когда пробел насильно заставляют растянуться больше, чем положено, возникает сообщение об Underfull'е, как это было объяснено в разд. 3.6.6.

Можно, однако, заставить TeX создать блок требуемой ширины " без скандала". Для этого в том промежутке, который мы хотим растянуть, надо поставить команду \hfil:

$$\hbox {Два слова}\\ \hbox {Два \hfil слова}\\ \hbox to 2cm {Два \hfil слова}\\ \hbox to 3cm {Два \hfil слова}\\ \hbox to 4cm {Два \hfil слова}$$
\hbox {Два слова}\\
\hbox {Два \hfil слова}\\
\hbox to 2cm {Два \hfil слова}\\
\hbox to 3cm {Два \hfil слова}\\
\hbox to 4cm {Два \hfil слова}

Если мы не указываем явно ширину блока, а предоставляем TeX'у создать блок "естественной" ширины, то команда \hfil никакого действия не оказывает; если промежуток для достижения требуемой ширины надо растянуть, то растяжение на требуемое расстояние будет проведено в том месте, где стоит команда \hfil.

Если в аргументе команды \hbox присутствует не одна команда \hfil, а несколько, то растяжение произойдет на месте каждой из этих команд, причем размер этого растяжения будет распределен между командами \hfil равномерно: если необходимо превысить естественную ширину блока на $$5$$ \,см, а в аргументе команды \hbox стоят два \hfil, то на месте каждого из них будет добавлен пробел в $$2{,}5$$ см. Вот пример с несколькими \hfil:

$$\hbox to 4cm{Раз \hfil два \hfil три}$$
\hbox to 4cm
{Раз \hfil два \hfil три}

В частности, если \hfil стоит справа или слева от текста, то весь текст будет прижат влево или вправо, поскольку \hfil отмечает то единственное место, в котором интервалы могут растягиваться; если же две команды \hfil стоят по обе стороны от текста, то текст внутри блока будет центрирован, поскольку дополнительное растяжение поделится между двумя \hfil поровну:

$$\hbox to 0.7\textwidth {Слева\hfil} \hbox to 0.7\textwidth {\hfil Справа} \hbox to 0.7\textwidth {\hfil В центре\hfil}$$
\hbox to 0.7\textwidth
{Слева\hfil}
\hbox to 0.7\textwidth
{\hfil Справа}
\hbox to 0.7\textwidth
{\hfil В центре\hfil}

Можно считать, что на месте каждого \hfil в строку вставляется пружина; все эти пружины имеют одинаковую жесткость, в свободном состоянии все они имеют нулевую ширину, и все эти пружины могут сколь угодно широко растягиваться.

Наряду с \hfil существует команда \hfill, также задающая бесконечно растяжимые пробелы, причем эта растяжимость "в бесконечное число раз больше", чем у пробелов, задаваемых \hfil. Если в аргументе команды \hbox присутствуют \hfil и \hfill совместно, то все растяжения происходят только за счет "более растяжимых" \hfill:

$$\hbox to 4cm{\hfil Слово\hfil}\\ \hbox to 4cm{\hfill Слово\hfil}\\ \hbox to 4cm{\hfil Слово\hfill}$$
\hbox to 4cm{\hfil Слово\hfil}\\
\hbox to 4cm{\hfill Слово\hfil}\\
\hbox to 4cm{\hfil Слово\hfill}

Лидеры

В оглавлении к этой книге (и ко многим другим тоже) место между названием раздела и номером страницы заполняется рядом из точек. Это можно сделать с помощью LaTeX'овской команда \dotfill. Она работает так же, как и \hfill, с той разницей, что пробел, образующийся в результате действия этой команды, заполняется точками:

$$\hbox to 3cm{А\dotfill Б}$$
\hbox to 3cm{А\dotfill Б}

Кроме этого, есть LaTeX'овская команда \hrulefill, которая также действует аналогично команде \hfill и при этом заполняет пробел линейкой:

$$\hbox to 5cm{1\hrulefill 2\hrulefill 3}$$
\hbox to 5cm{1\hrulefill
2\hrulefill 3}

В TeXнической терминологии такие заполнители называют лидерами (leaders).

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

$$\hbox to 5cm{1\leaders \hbox{Ъ}\hfil 2}$$
\hbox to 5cm{1\leaders
\hbox{Ъ}\hfil 2}

Если бы мы хотели, чтоб буквы Ъ шли не вплотную, можно было бы, например, вместо "Ъ" написать так:

\hbox to 2em{\hfil Ъ\hfil}

В общем случае применяйте команду \leaders так:

\leaders $\langle$
\textit{блок}$\rangle$ $\langle\mbox{\cs(hfil)
\textit{или} \cs(hfill)}\rangle$

Здесь $$\langle блок\rangle$$ - это любая TeX'овская команда для генерации блока, например, \hbox, с которой мы уже познакомились, или \vbox или \copy, о которых еще пойдет речь. Команды LaTeX'а ( \mbox, \makebox, \parbox и т.п.) применять в этом контексте нельзя; если, тем не менее, хочется воспользоваться их возможностями, то их надо " спрятать" в \hbox, написав, например,

\hbox{\makebox[3em][r]{...}}

Между командой для генерации блока и командой \hfil или \hfill может быть пробел (например, конец строки). Команда \leaders работает так: выделяется столько свободного места, сколько получилось бы, если бы стояло просто \hfil или \hfill, а затем это место заполняется идущими вплотную друг к другу копиями $$\langle блок\rangle$$ столько раз, сколько этот блок поместится по ширине на выделенное место (если ширина свободного места меньше ширины блока, то ни разу).

С помощью команды \leaders можно также изменить толщину линейки, заполняющей свободное место. Именно, команда \hrulefill является по существу сокращением от

\leaders\hrule\hfill

Если же мы скажем, например,

\leaders\hrule height 1pt \hfill

то линейка будет иметь толщину 1 пункт, вместо принятых по умолчанию 0.4 пункта. Можно также написать \hfil вместо \hfill, с очевидными последствиями.

Клей

Выше мы рассмотрели команды \hfil и \hfill, которые действуют подобно вставленным в строку пружинам. Можно вставлять в строку пружины с самыми разнообразными свойствами, указав LaTeX'овской команде \hspace аргумент, содержащий plus- или minus-компоненту (в разд.3.9.4 мы упоминали об этой возможности, но в тот момент у нас еще не было серьезных примеров). Именно, если вы скажете

\hspace{"$x$ plus $y$ minus $z$"}

где $$x$$, $$y$$ и $$z$$ - длины, то вставите в текст пружину, которая в свободном состоянии имеет длину $$x$$, может увеличивать свою длину на $$y$$ и уменьшать свою длину на $$z$$ (в отличие от пружин, встречающихся в жизни, может выполняться неравенство $$x<z$$, и, того пуще, длины $$y$$ и $$z$$ могут быть отрицательными, но мы не будем объяснять, как TeX поведет себя в столь странной ситуации)Если мы заставим такую пружину растянуться или сжаться больше, чем сказано, то получим сообщение "Underfull \hbox " или "Overfull \hbox "; см.\ ниже. Здесь plus и minus - это, как мы помним, очередные ключевые слова TeX'а, наподобие to, width и height. Если мы создаем блок естественной ширины, то команда \hspace с таким аргументом создаст пробел размером $$x$$ ; если же мы в команде \hbox попросим TeX создать блок, ширина которого отличается от естественной, то для достижения требуемой ширины размеры пробелов будут изменяться. В TeXнической терминологии эти "пружины" называются клеем (Дональд Кнут отмечает, что название "клей" неудачно, но менять его поздно, поскольку оно, по его словам, "уже прилипло"). Длины $$y$$ и $$z$$, указанные после ключевых слов plus и minus, называются plus- и minus- компонентами клея. Длина $$x$$ называется естественным размером клея. С этой точки зрения команда \hfil также помещает в строку клей - с бесконечной растяжимостью и нулевым естественным размером.

Опишем более точно, как именно растягивается или сжимается клей при выполнении команды \hbox to ... Для простоты предположим дополнительно, что plus- и minus- компоненты клея всюду неотрицательны и что в строке отсутствует клей с бесконечной растяжимостью или сжимаемостью (в частности, в строке нет \hfil 'ов или \hfill 'ов; про клей с бесконечной сжимаемостью речь пойдет ниже). В этом случае TeX вычисляет "естественную ширину" блока, складывающуюся из ширин составляющих его элементов и естественных размеров клея, и сравнивает ее с требуемой шириной блока, указанной в команде \hbox после ключевого слова to. Если эти две ширины совпали, то все пробелы будут иметь естественный размер. Если требуемая ширина больше естественной, то TeX вычисляет, насколько больше, после чего "разверстывает" эту добавку между всеми пробелами пропорционально величинам plus - компонент клея в этих пробелах.

Вот пример. Предположим, мы создаем блок с помощью команды

\hbox to $a$ {А\hspace{0pt plus 2em}%
Б\hspace{1cm plus 1em minus 2mm}В}

где величина $$a$$ на $$13$$ мм больше суммы ширин букв А, Б и В, то пробел между А и Б будет равен $$2\,\rm мм$$, а пробел между Б и В - $$11\,\rm мм$$, поскольку plus - компонента клея между А и Б в два раза больше, чем plus - компонента клея между Б и В (и никакого другого клея в строке нет, так что ничего более растянуть нельзя). Если требуемая ширина меньше естественной, то уменьшение длины также распределяется между всеми элементами клея пропорционально величинам их minus-компонент. Если продолжить аналогию между TeX'овским клеем и пружинами, то можно сказать, что жесткость пружины при растяжении обратно пропорциональна величине plus-компоненты.

В приведенном примере оба пробела в блоке были созданы вручную командой \hspace ; если же в аргументе команды \hbox присутствуют пробелы, то следует учесть, что эти пробелы также, как мы объясняли ранее, обладают растяжимостью и сжимаемостью, которая также берется в расчет.

В случае, когда пробелы надо растягивать и требуемое растяжение блока больше, чем сумма plus - компонент всех элементов клея, на экран и в log -файл выдается знакомое вам сообщение Underfull \hbox ; если пробелы надо уменьшать и величина, на которую надо уменьшить ширину блока, меньше, чем сумма minus - компонент всех элементов клея, то выдается не менее знакомое сообщение Overfull \hbox.

Все сказанное относилось к случаю, когда бесконечно растяжимого клея в аргументе команды \hbox нет. Если же таковой присутствует (например, есть команда \hfil ) и пробелы надо растягивать, то растяжимость клея с конечными значениями plus -компонент утрачивается: соответствующие интервалы будут иметь естественный размер (что бы ни было написано в аргументе команды \hspace после plus), а все растяжения будут происходить только за счет команд \hfil. При этом сообщение об Underfull'е выдаваться не будет, как бы ни растянулись пробелы. Аналогично, если пробелы надо ужимать и присутствует клей с бесконечной сжимаемостью, все уменьшения пробелов произойдут только за его счет и никогда не будет выдано сообщения об Overfull'е.

Если в аргументе команды \hbox присутствуют команды \hfil и \hfill совместно, то при необходимости растягивать пробелы учитывается только \hfill, в то время как "в бесконечное число раз менее растяжимый" \hfil в расчет не берется (не говоря уж о клее с конечной растяжимостью):

$$\hbox to 4cm{\hfil Блоки и клей\hfil}\\ \hbox to 4cm{\hfil Блоки и клей\hfill}\\ \hbox to 4cm{\hfill Блоки и клей\hfill}$$
\hbox to 4cm
{\hfil Блоки и клей\hfil}
\hbox to 4cm
{\hfil Блоки и клей\hfill}
\hbox to 4cm
{\hfill Блоки и клей\hfill}

Ранее мы упоминали о том, что в аргументе команды \vspace может (вместо длины с plus- и/или minus-компонентой) стоять команда \fill (возможно, с коэффициентом). Как мы теперь понимаем, \vspace с таким аргументом также задает бесконечно растяжимый клей. Точнее говоря, \vspace{\fill} действует так же, как \hfill, в то время как команда \vspace{0.3\fill} задает клей, растяжимость которого составляет 30% от растяжимости \hfill (тем не менее, этот клей также "бесконечно растяжим" в том отношении, что его присутствие отменяет растяжимость \hfil 'ов и клея с конечными plus - компонентами).

Бесконечно сжимаемые интервалы

Мы уже два раза упомянули про клей с бесконечной сжимаемостью. Настало время объяснить, какими командами его создавать. Из многих способов укажем один, наиболее часто встречающийся. Команда \hss вставляет в строку клей, естественный размер которого равен нулю, и который при этом обладает бесконечной растяжимостью (подобно \hfil ) и бесконечной сжимаемостью. Типичное применение такого "бесконечно сжимаемого" клея — создавать блоки, ширина которых меньше реального размера текста, или блоки с наложением текстов. В самом деле, посмотрите на такой пример:

$$\hbox to 50pt {Кот\hss Пес}\\ \hbox{Кот\hss Пес}\\ \hbox to 30pt {Кот\hss Пес}\\ \hbox to 15pt {Кот\hss Пес}\\ \hbox to 0pt {Кот\hss Пес}$$
\hbox to 50pt {Кот\hss Пес}
\hbox{Кот\hss Пес}
\hbox to 30pt {Кот\hss Пес}
\hbox to 15pt {Кот\hss Пес}
\hbox to 0pt {Кот\hss Пес}

Если мы просим сделать ширину блока больше естественной, команда \hss действует так же, как и \hfil ; когда мы создаем блок с естественной шириной, слова "Кот" и " Пес" стоят вплотную друг к другу (естественная ширина клея, созданного \hss, равна нулю). Интересные вещи начинаются, когда мы просим, чтобы ширина была $$30\,\rm pt$$ (что меньше естественной). Интервал между словами при этом приходится уменьшить; поскольку его естественный размер равен нулю, то после уменьшения интервал становится отрицательным, т. е. слово " пес" сдвигается влево (накладываясь на слово "Кот"), причем сдвигается так, чтобы ширина блока (т. е. расстояние от начала слова "Кот" до конца слова "Пес") равнялась требуемым $$30\,\rm pt$$. Когда же мы наконец просим, чтобы ширина блока равнялась нулю, слову "Пес" приходится сдвинуться влево настолько, чтобы расстояние от его конца до начала слова "Кот" равнялось нулю - иными словами, кот и пес меняются местами! Заметим, кстати, что точка отсчета всех наших блоков совпадает с точкой отсчета буквы К из слова "Кот".

Еще один пример использования \hss: как создать блок, точка отсчета которого будет находиться в правом, а не левом конце текста (мы столкнулись с этой проблемой в лекции 5)? Ответ: надо сказать

\hbox to 0pt{\hss текст}

и все будет в порядке. В самом деле, \текст имеет ширину, отличную от нуля; чтобы блок имел в итоге нулевую ширину, приходится "уменьшать" тот интервал, где стоит \hss ; так как интервал уже нулевой, то это уменьшение сводится к тому, что текст сдвигается влево до тех пор, пока расстояние между его концом и точкой отсчета не станет равным нулю - а это и означает, что правый конец текста стал его точкой отсчета. В лекции 5 мы сказали, что эта проблема решается с помощью TeX'овской команды \llap, а теперь мы видим, как ее можно определить:

\newcommand{\llap}[1]{\hbox to 0pt{\hss #1}}

Кстати говоря, именно так она и определяется.

А если сказать

\hbox to 0pt{текст \hss}

то что, спрашивается, будет? Ответ: на сей раз будет уменьшаться интервал после текста; стало быть, сам текст никуда не сдвинется, но после него будет сделан такой "отрицательный пробел", чтобы суммарная ширина равнялась нулю. Иными словами, TeX будет просто считать, что ширина блока равняется нулю - мы обманули TeX, убедив его, что наш текст не занимает места по горизонтали! Для такого обмана (к нему приходится прибегать нередко) предусмотрена специальная TeX'овская команда \rlap, определяемая так:

\newcommand{\rlap}[1]{\hbox to 0pt{#1\hss}}

Все это также напоминает ситуацию с командой \lefteqn — и напоминает не случайно, поскольку эта команда определяется фактически так:

\newcommand{\lefteqn}[1]{\rlap{$\displaystyle #1$\hss}}

Еще раз о линейках

В аргументе команды \hbox может присутствовать и TeX'овская команда \vrule. Ее ценность в том, что она автоматически создает линейку, высота и глубина которой равна высоте и глубине объемлющего блока (ширина этой линейки будет по умолчанию равна $$0{,}4$$ пункта). Как объяснялось в разд. 3.10 , можно задать в явном виде ширину линейки с помощью ключевого слова width, высоту - с помощью ключевого слова height, а также (о чем в лекции 3 не говорилось) глубину с помощью ключевого слова depth (эти три ключевых слова могут следовать после \vrule в произвольном порядке). Приведем один пример использования \vrule внутри \hbox.

$$\begin{flushleft} \hbox{% \vrule\hspace{.5em}\parbox{.9\textwidth}% {Иногда используется следующий способ выделения текста: абзац набирается с некоторым отступом от левого поля, а слева от него, вровень с левым полем, печатается вертикальная линейка.}} \end{flushleft}$$

Предыдущий абзац в исходном тексте выглядел так:

\begin{flushleft}
\hbox{%
\vrule\hspace{.5em}\parbox{.9\textwidth}%
{Иногда используется следующий способ выделения текста:
абзац набирается с некоторым отступом от левого поля,
а слева от него, вровень с левым полем, печатается
вертикальная линейка.}}
\end{flushleft}

Этот текст нуждается в некоторых пояснениях. Во-первых, в последней строке первая из фигурных скобок закрывает аргумент команды \parbox, а вторая - \hbox. Во-вторых, мы воспользовались окружением \flushleft, чтобы LaTeX сам позаботился о разумных отступах до и после абзаца. Параметр \textwidth означает, как мы помним, ширину страницы. Теперь рассмотрим, что присутствует внутри \hbox. Сначала там идет линейка, затем отступ на $$0.5\,\rm em$$, и затем — огромная " буква", созданная командой \parbox. Согласно общему правилу, высота и глубина линейки, заданной командой \vrule, равна высоте и глубине объемлющего блока, а они в нашем случае совпадают с высотой и глубиной "огромной буквы" (ведь кроме нее, другого текста в нашем \hbox нет). Тем самым линейка получается как раз нужных размеров, что и требовалось!

Обратите еще внимание на знак процента после \hbox — без него получилось бы, что аргумент команды \hbox начинается с пробела, соответственно и линейка начиналась бы не с начала, а после пробела .

На самом деле в предыдущем примере было бы лучше, если бы правый край выделенного абзаца шел вровень с правым краем остального текста. Чтобы добиться этого, надо первый аргумент команды \parbox не взять с потолка, а вычислить. Для этого нам понадобятся переменные со значением длины. Предполагая, что мы определили с помощью \newlength переменные \shirina и \raznost, сделаем вот что:

\begin{flushleft}
\shirina=\textwidth
\settowidth{\raznost}{\vrule\hspace{.5em}}
\addtolength{\shirina}{-\raznost}
\noindent\hbox{%
\vrule\hspace{.5em}\parbox{\shirina}%
{Иногда используется ...
... линейка.}}
\end{flushleft}

Мы воспользовались командой \settowidth, чтобы найти размер, который занимает линейка вместе с пробелом. Кстати, если просто написать \hbox{\vrule\hspace{.5em}}, то на печати мы ничего не увидим (внутри \hbox 'а никакого текста нет, так что высота и глубина линейки равна нулю и она тем самым невидима); однако же эта команда создаст пробел, величина которого равна 0.4pt плюс 0.5em. Заключительное замечание: поскольку {flushright}, как и всякое окружение, ограничивает группу, все наши манипуляции с параметрами \shirina и "\raznost" забудутся по выходе из этого окружения.

Команда \vbox

Теперь рассмотрим вторую основную команду TeX'а для генерации блоков — команду \vbox. Эта команда создает блок, обрабатывая текст в вертикальном режиме. Вот первый пример:

$$\vbox{\hbox{Слово} \hbox{Еще слово}}$$
\vbox{\hbox{Слово}
\hbox{Еще слово}}

Получаемый блок имеет вид:

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

Прежде чем идти дальше, обсудим, что может содержаться в аргументе команды \vbox. Там могут присутствовать любые TeX'овские команды, допустимые между абзацами (т.е. в вертикальном режиме): команды \vspace, команды смены шрифта, присваивания значений различным параметрам, команды \newcommand и \renewcommand и т.п. Что же касается команд, которым соответствует что-либо на печати, то будем считать, что из них в аргументе \vbox возможны только TeX'овские команды \hbox, \vbox и \hrule, а также \copy, о которой речь пойдет позже. В частности, недопустим ни текст, ни LaTeX'овские команды \mbox, \parbox, \rule и т.п. Если вам требуется воспользоваться возможностями таких команд, "прячьте" их в \hbox, например, так:

\hbox{\raisebox{1pt}[2em][3em]{...}}

На самом деле в аргументе команды \vbox может находиться и обычный текст; при появлении первой же буквы или, скажем, команды \mbox или другой команды LaTeX'а для генерации блоков TeX переходит в горизонтальный режим, который продолжается до команды, завершающей абзац ( \par или пустой строки). Мы не будем вдаваться в детали; для тех приложений, которые мы имеем в виду, достаточно использовать команду \vbox так, как было предписано выше.

Когда TeX при выполнении команды \vbox составляет блоки друг с другом, он располагает их так, чтобы их базисные линии были, по возможности, на равных расстояниях друг от друга, так что обычно между блоками будет присутствовать дополнительный пробел. С другой стороны, линейки, созданные командой \hrule, приставляются к блокам без дополнительного пробела. Чтобы при этом линейка не оказалась вплотную к тексту, удобно в соответствующий блок вставить \strut. Следующий пример призван пояснить сказанное:

$$\parindent=0pt Неудачно:\\ \vbox{\hbox{Два слова} \hrule} Лучше так:\\ \vbox{\hbox{\strut Два слова} \hrule}$$
Неудачно:\\
\vbox{\hbox{Два слова}
      \hrule}

Лучше так:\\
\vbox{\hbox{\strut Два слова}
     \hrule}

Как обычно, \vbox посреди абзаца ведет себя просто как большая буква. Обратите также внимание, что мы не пытались убрать лишний пробел между \hbox и \hrule: в вертикальном режиме пробелы никакого влияния на текст не оказывают.

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

$$\vbox{\hrule \hbox{\vrule\,\strut Текст в рамке\,\vrule} \hrule}$$
\vbox{\hrule
\hbox{\vrule\,\strut
Текст в рамке\,\vrule}
\hrule}

По-прежнему мы используем \strut, чтобы горизонтальные линейки не подходили слишком близко к тексту (и \ для той же цели по горизонтали).

Блоковые переменные

В тех случаях, когда один и тот же фрагмент текста (например, фрагмент псевдорисунка, являющийся аргументом команды \multiput ) используется многократно, бывает полезно сверстать этот фрагмент раз и навсегда, а затем просто повторять его: это сэкономит как количество нажатий на клавиши, так и машинное время. Использование макроопределения в данном случае времени не сэкономит: если мы напишем, например,

\newcommand{\abcd}{\parbox{6cm}%
{Когда в товарищах согласья нет,
на лад их дело не пойдет, и выйдет
из него не дело — только м\'ука.}}

то при каждой обработке команды \abcd это макроопределение будет заново развертываться, и TeX будет заново находить переносы и места разрыва строк в одном и том же отрывке из " Лебедя, рака и щуки". Чтобы не заставлять TeX много раз повторять идентичные операции по верстке текста, надо сделать так. Во-первых, определим "блоковую переменную", которая будет хранить сверстанный фрагмент текста. Это делается с помощью команды \newsavebox. Единственный аргумент этой команды - имя новой блоковой переменной, которое должно удовлетворять тем же условиям, что любые имена TeX'овских команд: либо backslash с одной не-буквой, либо backslash с последовательностью букв. Имя новой блоковой переменной не должно совпадать с именем уже существующей команды или переменной длины (если вы попытаетесь нарушить это правило, LaTeX выдаст сообщение об ошибке). Во-вторых, присвоим нашей блоковой переменной значение — блок, и будем в дальнейшем этот блок использовать.

Давайте приведем пример того, как можно этим пользоваться. Выше мы приводили пример псевдорисунка — наклонной решетки, и там же мы отметили, что экономнее было бы создать наклонный отрезок раз и навсегда, а затем только повторять его. Теперь мы можем объяснить, как это сделать. Создадим блоковую переменную под названием \blok, написав в преамбуле следующее:

\newsavebox{\blok}

Теперь сверстаем тот текст, который будет храниться в нашей блоковой переменной, и запишем его в эту переменную. Для этих целей используется команда \sbox с двумя обязательными аргументами: первый — имя блоковой переменной, второй — текст, который в нее записывается. Итак:

\sbox{\blok}{\line(1,5){10}}

А теперь можно воспользоваться нашей блоковой переменной. Чтобы напечатать содержимое блоковой переменной, используется команда \usebox с одним обязательным аргументом — именем переменной. В нашем случае мы используем блоковую переменную в аргументе команды \multiput:

$$\newsavebox{\blok} \sbox{\blok}{\line(1,5){10}} \parindent=0pt \begin{picture}(100,50) \multiput(0,0)(10,0){10}% {\usebox{\blok}} \multiput(0,0)(2,10){6}% {\line(1,0){90}} \end{picture}$$
\begin{picture}(100,50)
\multiput(0,0)(10,0){10}%
{\usebox{\blok}}
\multiput(0,0)(2,10){6}%
{\line(1,0){90}}
\end{picture}

Можно было бы сделать аналогичный трюк и с горизонтальными линейками решетки, но большой экономии это не даст: горизонтальные и вертикальные линейки на псевдорисунках LaTeX не собирает из отдельных символов, а создает "в один присест" с помощью команд \hrule и \vrule, что и так достаточно быстро.

Текст, присутствующий в аргументе команды \sbox, будет сверстан в виде блока так, как если бы этот текст был передан в качестве аргумента команде \hbox или \mbox. Тем самым в аргументе \sbox может быть все то же, что может присутствовать в аргументе \hbox или \mbox. Если команда \sbox была дана внутри группы, то по выходе из этой группы содержимое блоковой переменной забудется.

Наряду с командой \sbox есть еще и команда \savebox, относящаяся к ней примерно так же, как \makebox относится к \mbox: между первым и вторым обязательным аргументами команды \savebox могут присутствовать необязательные аргументы, имеющие тот же смысл и записывающиеся так же, как необязательные аргументы команды \makebox. Например,

\savebox{\пример}[4cm][r]{Слово}

даст тот же результат, что и

\sbox{\пример}{\makebox[4cm][r]{Слово}}

Наряду с LaTeX'овской командой \usebox есть похожая на нее, но не идентичная, TeX'овская команда \copy. Используется она так:

$$\sbox{\blok}{Рак} Однажды Лебедь, \copy\blok{} и Щука\ldots$$
\sbox{\blok}{Рак}
Однажды Лебедь,
\copy\blok{} и Щука\ldots

Обратите внимание, что при использовании команды \copy имя блоковой переменной не заключается в фигурные скобки! Различие между \copy и \usebox такое же, как между \hbox и \mbox: будучи употребленными внутри абзаца (или, скажем, в аргументе команд \put, \hbox или \mbox ), эти две команды действуют совершенно одинаково, а вот будучи употребленным между абзацами, LaTeX'овское \usebox начинает новый абзац, в то время как TeX'овское \copy просто подверстывает блок к странице, нового абзаца не начиная. Эту разницу следует иметь в виду, когда вы работаете с командой \leaders: выгоднее сверстать блок один раз и записать его в блоковую переменную, а затем в команде \leaders писать просто \copy. Пример:

$$\savebox{\blok}[1cm]{$*$} \hbox to \textwidth {\leaders\copy\blok\hfil}$$
\savebox{\blok}[1cm]{$*$}
\hbox to \textwidth
{\leaders\copy\blok\hfil}

В этой ситуации по TeXническим причинам сказать \usebox нельзя.

Для тех, кто будет читать следующую лекцию, скажем еще об одной конструкции, связанной с блоковыми переменными. Именно, если \blok — блоковая переменная, то можно " измерить" ширину, высоту и глубину блока, записанного в этой переменной, с помощью TeX'овских команд \wd, \ht и \dp. Точнее говоря, сочетания \wd\blok, \ht\blok и \dp\blok можно использовать в точности так же, как TeX'овские параметры со значением длины, значения которых равны ширине, высоте и глубине блока:

$$\sbox{\blok}{12345}\copy\blok\\ \hbox to \wd\blok{\hfil 345}\\ \hbox to \wd\blok{\hfil 45}$$
\sbox{\blok}{12345}\copy\blok\\
\hbox to \wd\blok{\hfil 345}\\
\hbox to \wd\blok{\hfil 45}

Для большинства элементарных приложений в LaTeX'е вполне хватает возможностей измерения блоков, предоставляемых командой \settowidth и ее аналогами, но в лекции 9 нам встретятся ситуации, в которых без \wd не обойтись.

Вернуться к учебному плану