# Using TikZ, how do I draw a box having an adjustable width?

I want to box text using TikZ and adjust the box width such that the text is appropriately put on different lines within the box. I also want the text on each to be centered within the box. As this is my first experience using TikZ, I'm a bit lost as to what can and cannot be done. This is what I have tried so far:

\documentclass{book}
\usepackage{tikz}

\begin{document}
\newlength{\myboxwidth}
\newcommand{\MyBox}[3][XXX]{
\settowidth{\myboxwidth}{#1} % THIS DOESN'T WORK
%\setlength{\myboxwidth}{20mm} % THIS WORKS
\draw (#2)
%\pgfextra{\setlength{\myboxwidth}{20mm}} % THIS WORKS
%\pgfextra{\settowidth{\myboxwidth}{#1}}  % THIS DOESN'T WORK
node
[rectangle,draw,minimum width=2em,minimum height=2em,
text width=\myboxwidth,
text centered, inner sep=1ex] {#3};
}

\begin{tikzpicture}
\MyBox[animals]{0,0}{animals cats \& dogs}
\MyBox[trees]{3,0}{trees oak aspen}
\end{tikzpicture}
\end{document}


In the left-hand box, I want "animals" on the first line and "cats & dogs" on the next, while in the right-hand box every word must be on its own line. Why is it that specifying \myboxwidth with an explicit length like 20mm works but asking LaTeX, which is what I'm using, to evaluate the word length fails? Each of the lines followed by a THIS WORKS or THIS DOESN'T WORK comment have been tried one at a time.

In addition to the above, I've tried using {\parbox{\myboxwidth}{#3}} instead of just {#3} and I've also tried the obvious line-splitting with \\ without success. Can anyone help please?

Oh, and placing the \settowidth command before \begin{tikzpicture} works too.

-
If you indent lines by 4 spaces, then they are marked as a code sample. You can also highlight the code and click the "code" button (with "{}" on it). – Caramdir Jun 9 '11 at 15:13

PGF math has a width function that measures the width of its parameter. It can be accessed with \pgfmathparse{width("some text")} or \pgfmathwidth{"some text"}. The result is then stored in \pgfmathresult.

I think text centered is a depreciated option. Using align=center instead makes \\ work as expected.

\documentclass{book}
\usepackage{tikz}

\begin{document}
\newcommand{\MyBox}[3][XXX]{
\pgfmathwidth{"#1"}
% store the result before it gets overwritten by some internal call to \pgfmath....
\let\myboxwidth\pgfmathresult
\draw (#2)
node
[rectangle,draw,minimum width=2em,minimum height=2em,
text width=\myboxwidth,
text centered, inner sep=1ex] {#3};
}

\begin{tikzpicture}
\MyBox[animals]{0,0}{animals cats \& dogs}
\MyBox[trees]{3,0}{trees oak aspen}

\draw (0,-2) node
[rectangle, draw, align=center, inner sep=1ex] {animals\\ cats \& dogs};
\draw (3,-2) node
[rectangle, draw, align=center, inner sep=1ex] {trees\\ oak aspen};
\end{tikzpicture}
\end{document}


Both of these solutions only work with TikZ/PGF version 2.10 (and higher).

-
This work just as I want it to. But why is it that \pgfmathwidth cannot be used directly but has to be passed on to \myboxwidth? – Luis Costa Jun 9 '11 at 15:39
The align=center is even better as now I don't have to evaluate the text width. Brilliant. – Luis Costa Jun 9 '11 at 15:51
@Luis: All the pgf-math macros don't return the value but set \pgfmathresult to the result of the combination. I guess this avoids some potential problems. – Caramdir Jun 9 '11 at 15:53
I noticed the explanatory question to my \pgfmathwidth comment only now.:-) – Luis Costa Jun 9 '11 at 15:56

Just a little change in Caramdir's solution. Use text width=\widthof{#1}. The results are the same.

\documentclass{book}
\usepackage{tikz}

\begin{document}
\newcommand{\MyBox}[3][XXX]{
\draw (#2)
node
[rectangle,draw,minimum width=2em,minimum height=2em,
text width=\widthof{#1}, %<---- Change here
text centered, inner sep=1ex] {#3};
}

\begin{tikzpicture}
\MyBox[animals]{0,0}{animals cats \& dogs}
\MyBox[trees]{3,0}{trees oak aspen}

\draw (0,-2) node
[rectangle, draw, align=center, inner sep=1ex] {animals\\ cats \& dogs};
\draw (3,-2) node
[rectangle, draw, align=center, inner sep=1ex] {trees\\ oak aspen};
\end{tikzpicture}
\end{document}

-
Thanks, this is a very useful tip. I see that tikz/pgf is very powerful and flexible, to say the least. – Luis Costa Jun 13 '11 at 7:01
\documentclass{book}
\usepackage{calc,array}
\newcolumntype{C}[1]{>{\centering}b{\widthof{#1}}}
\newcommand\MyBox[2][XXX]{%
\fbox{\tabular[b]{C{#1}} #2 \endtabular}}
\begin{document}

foo

I've done this as well using PSTricks, but I wanted to do this now specifically using tikz. You can do it also by saying \settowidth{\myboxwidth}{some} \fbox{\parbox{\myboxwidth}{some text}}. – Luis Costa Jun 9 '11 at 16:14