我想提供一个类似的界面:
\myNode{content=My content, style node={fill=red}}
虽然提供一个我们使用的接口很容易style node/.style={}
,但我很难找到一种优雅的方式来以这种方式指定样式,特别是如果我在函数内部定义参数时。我找到了一个解决方案,但它相当复杂,涉及第二个虚拟样式和 expl3……所以我想我遗漏了一些明显的东西。有没有更简单的解决方案?
理想情况下,我希望能够说这style node={…}
就像style node/.style={}
。
梅威瑟:
\documentclass[options]{article}
\usepackage{tikz}
\usepackage{etoolbox}
\begin{document}
\ExplSyntaxOn
% Otherwise I need to double the number of hashes
\cs_generate_variant:Nn \str_replace_all:Nnn { Nnx }
\cs_generate_variant:Nn \tl_rescan:nn { nv }
\cs_set:Nn \str_set_double_hash_robust:Nn {
\str_set:Nn {#1} {#2}
\str_replace_all:Nnx {#1} { #### } { \c_hash_str }
}
\NewDocumentCommand{\robExtRescanDoubleHashRobust}{m}{
\str_set_double_hash_robust:Nn \l_robExt_tmp_str {#1}
\tl_rescan:nv {}{ l_robExt_tmp_str }
}
\ExplSyntaxOff
\makeatletter
\NewDocumentCommand{\myNode}{m}{
\pgfkeys{
/test/.cd,
content node/.store in=\myContent,
content node=Default,
style node aux/.style={},
style node/.code={%
\robExtRescanDoubleHashRobust{%
\pgfkeysalso{%
/test/style node aux/.style={##1}%
}%
}
},%
% /test/style node aux/.style={##1}},%
#1,
}
\node[draw, /test/style node aux]{\myContent};
}
\makeatother
\begin{tikzpicture}
\myNode{
content node=Yes,
style node={
rounded corners,
draw,
test/.style={fill=#1},
test=red,
}
}
\end{tikzpicture}
\end{document}
答案1
如果您本身不应该接受任何参数,最简单的解决方案style node aux
是使用.estyle
处理程序而不是.style
进行设置,然后嵌套\unexpanded
:
\documentclass[]{article}
\usepackage{tikz}
\usepackage{etoolbox}
\begin{document}
\makeatletter
\pgfkeys{
/test/.cd,
content node/.store in=\myContent,
style node/.code = {%
\pgfkeysalso{/test/style node aux/.estyle=\unexpanded{#1}}%
},
% a .style is internally a .code with `\pgfkeysalso{<stuff>}`.
% a .code is set up using `\pgfkeysdef{\pgfkeyscurrentpath}{#1}`
% and `\pgfkeysdef` sets up an internal value in `\pgfkeyscurrentpath/.@body`
% Unfortunately the developers of `pgfkeys` decided that the `.@body` of an
% `estyle` should also get the expanded tokens, which makes it much harder
% adding to it in a generic way (provided that the adding is also done with an
% `\edef`). I have no idea what should be easier with this behaviour, but it
% is what it is. The result is, that the following is not a generic `.eappend
% style`, but works for our `style node`.
addstyle node/.code = {%
\begingroup
\pgfkeysgetvalue{/test/style node aux/.@body}\mytmp
\ifx\mytmp\relax
\PackageError{my-pgfkeys-extension}{Not a style: \pgfkeysgetvalue}{}%
\let\mytmp\empty
\fi
\def\mytmpB##1%
{%
\endgroup
\pgfkeysedef{/test/style node aux}
{\unexpanded{##1}\noexpand\pgfkeysalso{\unexpanded{#1}}}%
}%
\expandafter\mytmpB\expandafter{\mytmp}%
},
}
\NewDocumentCommand{\myNode}{m}{
\pgfkeys{
/test/.cd,
content node=Default,
style node aux/.style={},%
#1%
}
\node[draw, /test/style node aux]{\myContent};
}
\makeatother
\begin{tikzpicture}
\myNode{
content node=Yes,
style node={
test/.style={fill=#1},
test=red,
},
addstyle node={rounded corners}
}
\end{tikzpicture}
\end{document}
以下是上述代码的简化版本addstyle node
。其工作原理是将定义保存在单独的数据容器中,而不是使用pgfkeys
' 数据存储(因为这样我们就可以完全控制我们的数据存储并可以重复使用它)。
\documentclass[]{article}
\usepackage{tikz}
\usepackage{etoolbox}
\begin{document}
\makeatletter
\newcommand*\test@stylenode{}
\pgfkeys{
/test/.cd,
content node/.store in=\myContent,
style node/.code = {%
\edef\test@stylenode{\unexpanded{#1}}%
\pgfkeysalso{/test/style node aux/.estyle=\unexpanded{#1}}%
},
addstyle node/.code = {%
\edef\test@stylenode{\unexpanded\expandafter{\test@stylenode,#1}}%
\pgfkeysalso{/test/style node aux/.estyle=\unexpanded\expandafter{\test@stylenode}}%
},
}
\NewDocumentCommand{\myNode}{m}{
\pgfkeys{
/test/.cd,
content node=Default,
style node aux/.style={},%
#1%
}
\node[draw, /test/style node aux]{\myContent};
}
\makeatother
\begin{tikzpicture}
\myNode{
content node=Yes,
style node={
test/.style={fill=#1},
test=red,
},
addstyle node={rounded corners}
}
\end{tikzpicture}
\end{document}
答案2
我不知道这是否满足你的要求,因为我不清楚所涉及的所有因素(或在哪里正是您想要避免重复哈希值)。
下面使用了简化版本expl3
。我不确定重新扫描标记是否是最好的方法,但它似乎在最少的测试用例中有效。
\documentclass[border=10pt]{standalone}
\usepackage{tikz}
\begin{document}
\ExplSyntaxOn
% Otherwise I need to double the number of hashes
\NewDocumentCommand{\robExtRescanDoubleHashRobust}{m}{
\tl_rescan:nn {} {#1}
}
\ExplSyntaxOff
\pgfqkeys{/test}{%
content node/.store in=\myContent,
content node=Default,
style node aux/.style={},
style node/.code={%
\robExtRescanDoubleHashRobust{%
\pgfqkeysalso{/test}{%
style node aux/.style={#1}%
}%
}
},
/test/.code={%
\pgfkeys{/test/.cd,#1}%
},
/test/.search also={/tikz,/pgf},% usually a good idea
}
\NewDocumentCommand{\myNode}{m}{%
\begingroup
\pgfkeys{%
/test={#1},
}
\node[draw, /test/style node aux]{\myContent};
\endgroup
}
\begin{tikzpicture}
\myNode{}
\myNode{%
yshift=10mm,
content node=Yes,
style node={%
rounded corners,
draw,
test/.style={fill=#1},
test=red,
}
}
\scoped[yshift=20mm]{\myNode{}}
\myNode{%
content node=no,
style node={test/.style={fill=#1},test=green,double,font=\bfseries},
yshift=30mm,
}
\end{tikzpicture}
\end{document}\documentclass[border=10pt]{standalone}
\usepackage{tikz}
\begin{document}
\ExplSyntaxOn
% Otherwise I need to double the number of hashes
\NewDocumentCommand{\robExtRescanDoubleHashRobust}{m}{
\tl_rescan:nn {} {#1}
}
\ExplSyntaxOff
\pgfqkeys{/test}{%
content node/.store in=\myContent,
content node=Default,
style node aux/.style={},
style node/.code={%
\robExtRescanDoubleHashRobust{%
\pgfqkeysalso{/test}{%
style node aux/.style={#1}%
}%
}
},
/test/.code={%
\pgfkeys{/test/.cd,#1}%
},
/test/.search also={/tikz,/pgf},% usually a good idea
}
\NewDocumentCommand{\myNode}{m}{%
\begingroup
\pgfkeys{%
/test={#1},
}
\node[draw, /test/style node aux]{\myContent};
\endgroup
}
\begin{tikzpicture}
\myNode{}
\myNode{%
yshift=10mm,
content node=Yes,
style node={%
rounded corners,
draw,
test/.style={fill=#1},
test=red,
}
}
\scoped[yshift=20mm]{\myNode{}}
\myNode{%
content node=no,
style node={test/.style={fill=#1},test=green,double,font=\bfseries},
yshift=30mm,
}
\end{tikzpicture}
\end{document}
或者,您可以使用 TeX 原语来代替expl3
。
\documentclass[border=10pt]{standalone}
\usepackage{tikz}
\begin{document}
\pgfqkeys{/test}{%
content node/.store in=\myContent,
content node=Default,
style node aux/.style={},
style node/.code={%
\scantokens{%
\pgfqkeysalso{/test}{%
style node aux/.style={#1}%
}%
}
},
/test/.code={%
\pgfkeys{/test/.cd,#1}%
},
/test/.search also={/tikz,/pgf},% usually a good idea
}
\NewDocumentCommand{\myNode}{m}{%
\begingroup
\pgfkeys{%
/test={#1},
}
\node[draw, /test/style node aux]{\myContent};
\endgroup
}
\begin{tikzpicture}
\myNode{}
\myNode{%
yshift=10mm,
content node=Yes,
style node={%
rounded corners,
draw,
test/.style={fill=#1},
test=red,
}
}
\scoped[yshift=20mm]{\myNode{}}
\myNode{%
content node=no,
style node={test/.style={fill=#1},test=green,double,font=\bfseries},
yshift=30mm,
}
\end{tikzpicture}
\end{document}
答案3
这里有两个解决方案。它们没有你想要的确切语法,但我希望它们有用。
一种解决方案是使用\tikzstyle
定义自定义样式。
\tikzstyle{mynode} = [draw, fill=red]
\begin{tikzpicture}
\draw (0, 0) node[mynode, ...](A){Yes};
\end{tikzpicture}
另一个解决方案是使用\newcommand
定义宏。
\newcommand{\mynode}[2]{
node[#1](){#2}
}
\begin{tikzpicture}
\draw (0, 0) \mynode{draw, fill=red}{Yes};
\end{tikzpicture}