[Tex/LaTex] Using TikZ, how to draw a box having an adjustable width

boxestikz-pgf

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.

Best Answer

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}

result

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