tikz:如何在嵌套节点中引用节点

tikz:如何在嵌套节点中引用节点

以下 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}

在此处输入图片描述

相关内容