Using \savebox within a tikzpicture environment seems wipe out the content of the \savebox. In the MWE below, the following macros define, measure and display the size of a \savebox:

\newcommand*{\DefineBoxAndItSize}{%
    \savebox\tempboxA{Hg}%
    %% https://tex.stackexchange.com/a/11945/4301
    \setlength\SizeOfBox{\dimexpr\ht\tempboxA+\dp\tempboxA\relax}%
}%
\newcommand*{\ShowBoxAndSize}{%
    Box \fbox{\usebox{\tempboxA}} is \printlength{\SizeOfBox}%
}

As long as \DefineBoxAndItSize is invoked outside of a tikzpicture, using \ShowBoxAndSize both outside (first line of output) and inside a tikzpicture environment (second line of output) works fine.

However, the third line invokes \DefineBoxAndItSize inside a tikzpicture before \ShowBoxAndSize, which ends up making the box empty.

enter image description here

Question:

How can I define a \savebox within a tikzpicture environment?

Code:

\documentclass[10pt]{article}
\usepackage{tikz}
\usepackage{printlen}

\newsavebox{\tempboxA}
\newlength{\SizeOfBox}

\fboxsep=0pt

\newcommand*{\DefineBoxAndItSize}{%
    \savebox\tempboxA{Hg}%
    %% https://tex.stackexchange.com/a/11945/4301
    \setlength\SizeOfBox{\dimexpr\ht\tempboxA+\dp\tempboxA\relax}%
}%
\newcommand*{\ShowBoxAndSize}{%
    Box \fbox{\usebox{\tempboxA}} is \printlength{\SizeOfBox}%
}

\begin{document}
    \DefineBoxAndItSize%
    \noindent
    Outside TikZ: \ShowBoxAndSize.

    \medskip\noindent
    \begin{tikzpicture}[inner sep=0pt, anchor=east]
        \node at (0,0) {Use inside TikZ: \ShowBoxAndSize.};
    \end{tikzpicture}%

    \medskip\noindent
    \begin{tikzpicture}[inner sep=0pt, anchor=east]
        \DefineBoxAndItSize% <--- What is wrong with this?

        \node at (0,-1) {Define inside TikZ: \ShowBoxAndSize.};
    \end{tikzpicture}%
\end{document}
  • 2
    outside nodes the font is \nullfont. – Ulrike Fischer Nov 13 at 21:43
  • the box is saved, but it saves the same text that it would typeset if you used that text at that point. (look in the log for missing character messages) – David Carlisle Nov 13 at 21:52
  • I guess this is the same as tex.stackexchange.com/q/448576/121799 – marmot Nov 13 at 21:54
  • @marmot: Yep. Using \begin{pgfinterruptpicture} \DefineBoxAndItSize \end{pgfinterruptpicture} works. You want to post an answer? Not sure I would imemdiately have seen this as a related issue had I seen the referenced question. – Peter Grill Nov 13 at 22:09
  • @PeterGrill Have you also seen this question? It seems to be slightly closer to yours, and the OP added \begin{pgfinterruptpicture} ... \end{pgfinterruptpicture} to their macro (as well). I agree that your question is not a precise duplicate. I can add an answer, but I also think there would be nothing wrong if you answer your own question. Please let me know what you like better. – marmot Nov 13 at 22:16
up vote 12 down vote accepted

Background: TikZ happens to gobble text unless it is an argument of a node. Even though this is sort of well known, this also has less obvious implications. In particular, saveboxes may end up being empty. This has already lead to confusion here and here. In the latter post, the OP solves the issue by wrapping their macro in \begin{pgfinterruptpicture} and \end{pgfinterruptpicture}.

The next step of sophistication, which may or may not deserve a new answer, might then be to wrap the savebox definition in an \begin{pgfinterruptpicture} and \end{pgfinterruptpicture} only if the macro is called inside a tikzpicture environment. To this end, the tests of this post and this post are employed. (Let me remark that the \IfInTikzPic is a bit unusual in that its first argument is the action that is to be taken if one is not in a tikzpicture environment. Whether or not this is related to the author driving on the other side of the road, I don't know. ;-)

\documentclass[10pt]{article}
\usepackage{tikz}
\usepackage{printlen}

\newsavebox{\tempboxA}
\newlength{\SizeOfBox}

\fboxsep=0pt

\makeatletter% from https://tex.stackexchange.com/a/458855/121799
\newcommand{\IfInTikzPic}{% https://tex.stackexchange.com/a/121309/4301
  \ifx\pgfpictureid\@undefined
    \expandafter\@firstoftwo
     \else
    \expandafter\@secondoftwo
    \fi
}
\makeatother


\newcommand*{\DefineBoxAndItSize}{%
\IfInTikzPic{\savebox\tempboxA{Hg}%
% https://tex.stackexchange.com/a/11945/4301
\setlength\SizeOfBox{\dimexpr\ht\tempboxA+\dp\tempboxA\relax}%
}{\begin{pgfinterruptpicture}%
\savebox\tempboxA{Hg}%
% https://tex.stackexchange.com/a/11945/4301
\setlength\SizeOfBox{\dimexpr\ht\tempboxA+\dp\tempboxA\relax}%
\end{pgfinterruptpicture}}
}%
\newcommand*{\ShowBoxAndSize}{%
    Box \fbox{\usebox{\tempboxA}} is \printlength{\SizeOfBox}%
}

\begin{document}
    \DefineBoxAndItSize%
    \noindent
    Outside TikZ: \ShowBoxAndSize.

    \medskip\noindent
    \begin{tikzpicture}[inner sep=0pt, anchor=east]
        \node at (0,0) {Use inside TikZ: \ShowBoxAndSize.};
    \end{tikzpicture}%

    \medskip\noindent
    \begin{tikzpicture}[inner sep=0pt, anchor=east]
        \DefineBoxAndItSize% <--- What is wrong with this?

        \node at (0,-1) {Define inside TikZ: \ShowBoxAndSize.};
    \end{tikzpicture}%
\end{document}

enter image description here

I'll be happy to remove this answer if people feel that this question is a duplicate and thus does not deserve a separate answer. (However, at the time of writing this, I am reputation capped, so the reason is certainly not to harvest reputation points, which it is in none of my posts.)

EDIT: Fixed a space, big thanks to Phelype Oleinik!

  • 2
    Deserves one upvote solely for the remark on \IfInTikzPic. Brilliant! (and for the answer, of course). One comment: I'd add a % after \begin{pgfinterruptpicture} to align the last sentence. – Phelype Oleinik Nov 13 at 22:57
  • 1
    Yes, it is rather well know, until you encounter an error and spend time trying to figure out what is going on, without remembering that detail! :-( – Peter Grill Nov 13 at 23:47
  • @marmot: Nah, its fine. I just end up asking too many embarrassing questions!!! As always, I continue to blame it on lack of sleep. – Peter Grill Nov 13 at 23:51
  • 1
    @PeterGrill Yes, nothing is better than a good amount of hibernation time. (And no, I don't think it is an embarrassing question. I just happen to have come across this a few months earlier.) Ah, I also edited the answer. – marmot Nov 13 at 23:53

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.