以下 MWE 显示 2 个嵌套框。对齐是通过引用内部框(通过节点名称“inbox”)来完成的
\documentclass[12pt, a4paper]{scrartcl}
\usepackage{tikz}
\begin{document}
Before
\begin{tikzpicture}[baseline=(inbox.base)]%
\node[draw,rounded corners](outbox) {%
\begin{tikzpicture}[scale=1]%
\node[draw,rectangle](inbox){\textcolor{gray}{in}};
\end{tikzpicture}
};
\end{tikzpicture}
After
\end{document}
但替换baseline=(inbox.base)
会baseline=(outbox.base)
产生编译错误:包 pgf 错误:没有已知的名为 outbox 的形状。
有人能给我解释一下吗?
顺便问一下,像我一样将节点嵌套在节点内是正确的方法吗?
答案1
首先回答更重要的问题:不,嵌套 tikzpictures 是不是正确的方法。实现您想要的效果的最简单方法是使用库fit
。以下是示例:
\documentclass[12pt, a4paper]{scrartcl}
\usepackage{tikz}
\usetikzlibrary{fit}
\begin{document}
Before
\begin{tikzpicture}[baseline=(inbox.base)]%
\node[draw,rectangle](inbox){\textcolor{gray}{in}};
\node[draw,rounded corners,fit=(inbox)](outbox) {%
};
\end{tikzpicture}
After
\end{document}
这里的一般原则是,TikZ/PGF 不需要知道您希望指定的层次结构(即inbox
内部outbox
),它只需要知道它们在定位方面如何关联。因此,您先弄清楚inbox
,然后outbox
围绕它放置。TikZ 很高兴,因为它知道将东西放在哪里。如果您真的,真的需要有一个层次结构,我们使用matrix
节点类型。
tikzpicture
现在来解释一下哪里出了问题。这都是因为意味着堆叠在一起,因此无需考虑分组或作用域。应该只有一个tikzpicture
(或\tikz
)包含所有元素,这就是代码所期望的。这是一个很好的例子(我可能会多次引用它来解释为什么这是一个坏主意,因为它经常出现)。
让我们看一下关键命令:baseline
外部的选项tikzpicture
。这表示“我希望以下点位于周围文本的基线上。”。问题在于 TikZ(或者更确切地说,PGF)在绘制图片之前不知道该点在哪里。所以它必须说“好的,我会记住那个点,在图片结束时我会解决它。”。所以现在它开始做它的工作,弄清楚图片,最后计算您指定的点的坐标。
这就是范围问题出现的地方。该baseline
选项设置了一些宏,这些宏将作为 中发生的事情的一部分进行评估\end{tikzpicture}
。如果宏为空,则不会发生任何事情。如果它不为空,PGF 会使用它来计算基线。在文档开始时,宏为空。由于\begin{tikzpicture} ... \end{tikzpicture}
发生在组内,因此在选项中将其设置为\begin{tikzpicture}
不会改变其他图片的情况除非他们属于同一组。所以这里发生的事情是内tikzpicture 继承了baseline
外部命令,并大声抱怨,因为它不知道在哪里outer
!。当内图完成时,outer
节点尚未定位。
您可以说应该\begin{tikzpicture}
清除其组内的宏(这不会影响外部图片,因为它在外部组中)。但这意味着您不能\tikzset{baseline=0pt}
在开始时就说并将其应用于文档中的所有图片 - 这比嵌套更有用tikzpicture
。所以这是一个特征,不是漏洞。
为了验证这一点,运行以下代码:
\documentclass[12pt, a4paper]{scrartcl}
\usepackage{tikz}
\makeatletter
\def\helpme#1{%
\message{#1}%
\show\pgf@sh@ns@outbox
\show\pgf@baseline
}
\makeatother
\begin{document}
Before
\begin{tikzpicture}[baseline=(outbox.base)]%
\helpme{Start of picture:}
\node[draw,rounded corners](outbox) {%
\helpme{Start of node:}
\begin{tikzpicture}[scale=1]%
\helpme{Start of inner picture:}
\node[draw,rectangle](inbox){\textcolor{gray}{in}};
\end{tikzpicture}
\helpme{After inner picture:}
};
\helpme{End of picture:}
\end{tikzpicture}
After
\end{document}
我承认,诊断程序有点粗糙,但它们显示了正在发生的事情。实际上,您不需要运行它,因为我将输出(精简版)放在这里:
Start of picture:
> \pgf@sh@ns@outbox=undefined.
> \pgf@baseline=macro:
->\tikz@scan@one@point \pgfutil@firstofone (outbox.base).
Start of node:
> \pgf@sh@ns@outbox=undefined.
> \pgf@baseline=macro:
->\tikz@scan@one@point \pgfutil@firstofone (outbox.base).
Start of inner picture:
> \pgf@sh@ns@outbox=undefined.
> \pgf@baseline=macro:
->\tikz@scan@one@point \pgfutil@firstofone (outbox.base).
! Package pgf Error: No shape named outbox is known.
l.20 \end{tikzpicture}
After inner picture:
> \pgf@sh@ns@outbox=undefined.
> \pgf@baseline=macro:
->\tikz@scan@one@point \pgfutil@firstofone (outbox.base).
End of picture:
> \pgf@sh@ns@outbox=macro:
->rectangle.
> \pgf@baseline=macro:
->\tikz@scan@one@point \pgfutil@firstofone (outbox.base).
注意,\pgf@sh@ns@outbox
只有在节点被充分定义(这就是直接地导致错误,因为它用于测试节点是否已声明)。请注意,错误发生在内图片完成,而不是外面的。还要注意的是\pgf@baseline
,自始至终,包括里面的图片。
这个故事的寓意是:不要嵌套 tikzpictures。它们不喜欢这样。
答案2
如果您为节点指定基线,错误就会消失,outbox
这里指的是inbox.base
:
\documentclass[12pt, a4paper]{scrartcl}
\usepackage{tikz}
\begin{document}
Before
\begin{tikzpicture}[baseline=(outbox.base)]%
\node[draw,rounded corners,baseline=(inbox.base)](outbox) {%
\begin{tikzpicture}[scale=1]%
\node[draw,rectangle](inbox){\textcolor{gray}{in}};
\end{tikzpicture}
};
\end{tikzpicture}
After
\end{document}