使用节点文本作为宏的参数

使用节点文本作为宏的参数

我想创建一个 TikZ 样式,使用包\contour{<colour>}{<text>}中的宏为节点文本添加粗轮廓contour(如问题的答案中所示TikZ:文本周围有光晕?),即我想定义一种风格,halo以便

\node [halo] {Text};

相当于

\node {\contour{red}{Text}};

我的问题是我无法告诉 TikZ 使用节点文本作为宏的参数。

font选项仅适用于类似的开关\itshape(与相反\textit{},后者要求在参数中提供斜体文本)。

有两个键execute at begin node={<code>}execute at end node={<code>}可用于在节点的开头和结尾调用代码,但我无法\contour使用execute at begin node={\contour{red{}和拆分命令,execute at end node={}}因为括号不匹配。{\bgroup}替换\egroup会失败Missing } inserted

以下是可供玩的 MWE:

\documentclass{article}

\usepackage{tikz}
\usepackage[outline]{contour}
\contourlength{1.2pt}


\begin{document}

    \begin{tikzpicture}
    \node {\contour{red}{Text}};
%    \node [font=\contour{red}{}] {Text}; % Doesn't change the text
%    \node [execute at begin node={\contour{red}{},execute at end node={}}] {Text};  % Fails with ``Runaway argument?''
%    \node [execute at begin node={\contour{red}\bgroup},execute at end node={\egroup}] {Text};  % Fails with ``Missing } inserted''
    \end{tikzpicture}
\end{document}

答案1

在查看源代码contour(至少在pdftex驱动程序部分)后,我发现它将文本排版两次,一次用于轮廓,一次正常。内容必须很短(即不是\long),并且以限制水平模式。问题是 TikZ 将节点内容作为框而不是宏参数处理。这通常非常好,因为它允许节点中的逐字内容等,但不允许直接访问和\contour其他宏所需的未排版内容。

请注意,\contour如果您使用 ,则部分适用于盒装内容\unhbox。问题是您需要它两次并且无法更改颜色!因此,要么两者都具有相同的颜色,这使得轮廓不太有用,要么您只有轮廓没有真正的文本。我修补了contour源代码(仅供pdftex参考)以便您到达那里:

% (uncomment the `%` lines to enable typesetting of the real text, but in the same color than the contour)
\documentclass{article}

\usepackage{tikz}
\usepackage[outline]{contour}
\contourlength{.1pt}

\makeatletter
\def\tikzcontour#1{%
    \begingroup
    \color{#1}%
    %\def\contourcolor{#1}%
    \begin{lrbox}{\@tempboxa}%
}
% Mostly taken from `\@contour@outline` from `contour`s `pdftex.cnt` driver file:
% Work with pdftex only
\def\endtikzcontour{%
    \end{lrbox}%
    %\setbox0=\hbox{\usebox\@tempboxa}%
    \begingroup
    \setlength\con@length{\con@base@length}%
    \setlength\con@length{2\con@length}%
    \setlength\con@length{0.99626400996\con@length}%
    %\color{\contourcolor}%
    \con@coloroff
    \pdfliteral{%
      q
      1 j
      1 J
      1 Tr
      \strip@pt\con@length\space w
    }%
    %\rlap
    \mbox% change back to `\rlap` when "real" text is drawn
    {\unhbox\@tempboxa}%
    \pdfliteral{%
      Q
    }%
    \endgroup
    %\unhbox0
    \endgroup
}
\makeatother

\begin{document}
    \begin{tikzpicture}
    \node [execute at begin node={\tikzcontour{red}},execute at end node={\endtikzcontour}] {Text};
    \end{tikzpicture}
\end{document}

得出:

结果


但是,可以使用与我的collcell包收集单元内容相同的技术来收集 TikZ 节点的内容tabular,即跳过内部代码头并逐个标记地读取它,直到到达末尾。

这里有一些概念验证的快速解决方案,它重用了 中的代码collcell。请勿\collectcell与同一文件中的表一起使用。有时间的话,我会编写一个专用的、更稳定的解决方案。

\documentclass{article}

\usepackage{tikz}
\usepackage[outline]{contour}
\contourlength{.05em}
\usepackage{collcell}

\makeatletter

\def\collect@cell@look@{%
  \cc@case
    \@sptoken{%
      \edef\collect@cell@spaces{\collect@cell@spaces\space}%
      \collect@cell@eatspace
    }%
    \bgroup{\collect@cell@group}%
    \egroup{\afterassignment\collect@cell@end\let\@let@token=}%
    %\egroup{\collect@cell@end}%
    \default{\collect@cell@arg}%
  \endcc@case
}

\def\tikzcontour#1#2{\@tikzcontour{#1}#2\@endtikzcontour}
\def\@tikzcontour#1#2\ignorespaces#3\@endtikzcontour{%
          \bgroup%
            \ifx\tikz@textcolor\pgfutil@empty%
            \else%
              \pgfutil@colorlet{.}{\tikz@textcolor}%
            \fi%
            \pgfsetcolor{.}%
            \setbox\tikz@figbox=\box\pgfutil@voidb@x%
            \tikz@uninstallcommands%
            \tikz@halign@check%
            \contour{#1}{\ignorespaces #3\unskip}%
            \egroup
            \tikz@fig@collectresetcolor%
        }
\let\collcell@afteruser=\empty
\makeatother

\tikzset{contour/.style={execute at begin node={\collectcell{\tikzcontour{#1}}\ignorespaces}}}

\begin{document}
    \begin{tikzpicture}
        \node [draw,green,contour=red,circle] {Text};
    \end{tikzpicture}
\end{document}

结果 2

相关内容