指定传递样式的简单方法是使用语法“my style={foo}”

指定传递样式的简单方法是使用语法“my style={foo}”

我想提供一个类似的界面:

\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}

相关内容