可能重复:
如何从 pgfkeys 样式元素中提取值
假设我已经定义了以下 TikZ 样式:
\tikzset{
mystyle/.style={draw, fill=green, node distance=3mm}
}
我想要绘制以下图片:
为了绘制这个,我使用了以下代码:
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc, positioning}
\begin{document}
\begin{tikzpicture}[%
mystyle/.style={draw, node distance=3mm}
]
\node [mystyle] (n1) {1};
\node [mystyle, right=of n1] (n2) {2};
\node at ([yshift=-3mm] $(n1.south) !0.5! (n2.south)$) [mystyle, below] (n3) {3};
\end{tikzpicture}
\end{document}
虽然它可以工作,但它的问题在于距离(3mm)被定义了两次——一次在样式中,一次在图形本身中。
之前,我通过创建一个定义距离的新维度寄存器来解决这个问题,但是我希望能够直接从样式中提取值。例如,我想要这样的东西:
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc, positioning}
\begin{document}
\begin{tikzpicture}[%
mystyle/.style={draw, node distance=3mm}
]
\node [mystyle] (n1) {1};
\node [mystyle, right=of n1] (n2) {2};
\node at ([yshift=-\styleproperty{mystyle/node distance}] $(n1.south) !0.5! (n2.south)$) [mystyle, below] (n3) {3};
\end{tikzpicture}
\end{document}
这可能实现吗?
答案1
感谢 Ryan Reich 最出色的 PGFKeys 跟踪包(位于我如何调试 pgfkeys?),我发现该密钥node distance
将其值存储在宏中\tikz@node@distance
。这意味着它无法通过 pgfkeys 的“标准通道”(即\pgfkeyvalueof
)访问。此外,由于宏名称@
中包含 s,因此无法按原样使用它。所以我们必须定义一个包装器来获取此宏的值。
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc,positioning}
% This bit was how I found out what was going on
%\usepackage{trace-pgfkeys}
%\pgfkeystracelevel{verbose}
%\tikzset{node distance=3mm}
%\pgfkeystracelevel{silent}
\makeatletter
\def\getnodedistance{\tikz@node@distance}
\makeatother
\begin{document}
\begin{tikzpicture}[%
mystyle/.style={draw, node distance=3mm}
]
\node [mystyle] (n1) {1};
\node [mystyle, right=of n1] (n2) {2};
\node [mystyle, below] at ([yshift=-\getnodedistance]$(n1.south) !0.5! (n2.south)$) (n3)
{3};
\end{tikzpicture}
\end{document}
这种方法不容易推广,但那是因为pgfkeys
他们可以对传递的值做任何他们想做的事情,包括将它们存储在任意宏中。有时你很幸运,他们会将它们存储在键中,在这种情况下这\pgfkeysvalueof{full key name}
就是你想要的。如果使用通用宏,那么你必须使用该宏来访问它。
(另一种方法是向原始键调用添加一些代码,以将值存储在可以使用的另一个宏中。如果键以某种非平凡的方式使用参数,从而难以提取原始值,我会使用此方法。)
注意:由于作业node distance=3mm
是当地的,您需要确保在调用宏mystyle
之前调用该键。这就是我将部分移至坐标计算之前的原因。如果您希望能够在文档中更早地指定,我会以另一种方式完成所有操作:将存储在单独的键中,然后让和访问此键。类似于:\getnodedistance
[mystyle,below]
3mm
3mm
node distance
yshift
\tikzset{
my global node distance/.initial=3mm,
mystyle/.style={
draw,
node distance=\pgfkeysvalueof{/tikz/my global node distance}
}
}
...
\node [mystyle,below] at ([yshift=-\pgfkeysvalueof{/tikz/my global node distance]...
编辑(打击乐手):
以下是在样式声明中包含宏赋值的另外两种方法
1)提供一个长度宏名选项,将节点距离的值直接保存到该宏名中(在本例中mynodedist
)。
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc,positioning}
\makeatletter
\tikzset{ mystyle/.style={draw, node distance=3mm, save node distance to=mynodedist},
save node distance to/.code={\expandafter\newdimen\csname#1\endcsname%
\advance\csname#1\endcsname by \tikz@node@distance }
}
\makeatother
\begin{document}
\begin{tikzpicture}
\node [mystyle] (n1) {1};
\node [mystyle, right=of n1] (n2) {2};
\node [mystyle, below] at ([yshift=-\mynodedist ]$(n1.south) !0.5! (n2.south)$) (n3) {3};
\end{tikzpicture}
\end{document}
2)您可以对同一组键进行常规style=
和code=
分配,以实现更规范的键值配对,这归结为仅修改
\makeatletter
\tikzset{ mystyle/.style={draw, node distance=3mm},
mystyle/.add code={}{\def\mynodedist{\tikz@node@distance}}
}
\makeatother
答案2
这个问题很有趣,因为 Andrew 和 percusse 给出了关于 的有趣信息\tikz@node@distance
。我认为在这种情况下没有必要直接从样式中提取值。如何提取很有趣,但最好避免这样做,因为 TikZ 为您提供了所有工具。
我不太喜欢定位库,但如果你使用它,我认为更好的方法是一直使用它直到代码结束。node distance
在这种情况下,你想使用当前的值,我认为below=of
更可取!(而不是yshift
)
我认为下一个代码给出了你想要实现的目标
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc, positioning}
\begin{document}
\begin{tikzpicture}[%
every node/.style = {draw},
node distance = 3mm
]
\node (n1) {1};
\node [right=of n1] (n2) {2};
\path let \p1 = ($(n1.south) !0.5! (n2.south)$) in node[below=of \p1] (n3) {3};
% more simpler : \node[below= of $(n1.south) !0.5! (n2.south)$] (n3) {3}; % (percusse)
\end{tikzpicture}
\end{document}