动机
如标题所述,我试图定义一个命令,能够从颜色列表作为输入,创建一个颜色编号的列表。这是手动完成的 TikZ 中的箭头坐标
前期工作
我尝试在网站上搜索与该问题相关的问题,例如如何在 foreach 循环中定义宏并在迭代之间和循环后产生效果而不使用全局?, 如何在 foreach 循环中定义宏并在迭代之间和循环后产生效果而不使用全局?(尤其是 Martin 评论中显示的解决方案)。但是当定义基于\@namedef
最小非工作示例
这是我尝试过的:
\documentclass[11pt,a4paper]{article}
\usepackage{tikz}
\makeatletter
\newcommand{\setcolorlist}[1]{
\foreach \listitem [count=\i] in {#1}{
\global\let\@tempa\@namedef{color@\i}{\listitem}
}
\@tempa
}
% Command in which colors are necessary
\newcommand{\drawcoloredarrows}[1]{
\foreach \i in {#1}{
\edef\mycolor{\@nameuse{color@\i}}
\draw[\mycolor,-stealth] (0,-\i)--(2,-\i);
}
}
\makeatother
\begin{document}
\setcolorlist{red,cyan,blue,green}
\begin{tikzpicture}
\drawcoloredarrows{1,...,4}
\end{tikzpicture}
\end{document}
得到:
如何运作
它的工作方式如下:
\documentclass[11pt,a4paper]{article}
\usepackage{tikz}
\makeatletter
\@namedef{color@1}{red}
\@namedef{color@2}{cyan}
\@namedef{color@3}{blue}
\@namedef{color@4}{green}
\newcommand{\setcolorlist}[1]{
\foreach \listitem [count=\i] in {#1}{
\global\let\@tempa\@namedef{color@\i}{\listitem}
}
\@tempa
}
% Command in which colors are necessary
\newcommand{\drawcoloredarrows}[1]{
\foreach \i in {#1}{
\edef\mycolor{\@nameuse{color@\i}}
\draw[\mycolor,-stealth] (0,-\i)--(2,-\i);
}
}
\makeatother
\begin{document}
%\setcolorlist{red,cyan,blue,green}
\begin{tikzpicture}
\drawcoloredarrows{1,...,4}
\end{tikzpicture}
\end{document}
得到:
答案1
用这个宏
\newcommand{\setcolorlist}[1]{
\foreach \listitem [count=\i] in {#1}{
\global\let\@tempa\@namedef{color@\i}{\listitem}
}
\@tempa
}
你基本上是在做
\global\let\@tempa\@namedef
确实打印出了“color@1red”等。然后\@tempa
(现在是\@namedef
)必须执行,但可能无法执行。
和\setcolorlist{red,green,blue}
你想做的
\@namedef{color@1}{red}
\@namedef{color@2}{green}
\@namedef{color@3}{blue}
所以你想说
\@namedef{color@\i}{<expansion of \listitem>}
但在全球范围内。由于\@namedef{x}
扩展到
\expandafter\def\csname x\endcsname
并且您需要访问的扩展\listitem
,以下就可以了
\newcommand{\setcolorlist}[1]{%
\foreach \listitem [count=\i] in {#1}{%
\global\@namedef{color@\i\expandafter}\expandafter{\listitem}
}%
}
或者,既然你知道这一点,\listitem
并\i
扩展为一个字符串,
\newcommand{\setcolorlist}[1]{%
\foreach \listitem [count=\i] in {#1}{%
\begingroup\edef\x{\endgroup
\global\noexpand\@namedef{color@\i}{\listitem}}\x
}%
}
请注意,Ahmed 方法也有效,因为在每个后续步骤中\listitem
都定义为扩展为当前颜色名称。但是,如果您需要执行比简单的宏等效更复杂的事情,则该方法将失败。
强制expl3
解决方案
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\setcolorlist}{ m }
{
\claudio_setcolorlist:n { #1 }
}
\int_new:N \l_claudio_cycle_int
\cs_new_protected:Npn \claudio_setcolorlist:n #1
{
\int_zero:N \l_claudio_cycle_int
\clist_map_inline:nn { #1 }
{
\int_incr:N \l_claudio_cycle_int
\cs_set:cpn { color@ \int_to_arabic:n { \l_claudio_cycle_int } } { ##1 }
}
}
\ExplSyntaxOff
你可以选择全局或局部赋值(\cs_gset:cpn
前者),但这不是必须的。所以这种方法优于后者\foreach
,因为除非你需要,否则它不会强迫你进行全局定义。
答案2
尝试
\documentclass[11pt,a4paper]{article}
\usepackage{tikz}
\makeatletter
\newcommand{\setcolorlist}[1]{%
\foreach \listitem [count=\i] in {#1}{
\global\expandafter\let\csname color@\i\endcsname\listitem
}
}
% Command in which colors are necessary
\newcommand{\drawcoloredarrows}[1]{
\foreach \i in {#1}{
\draw[\@nameuse{color@\i},-stealth] (0,-\i)--(2,-\i);
}
}
\makeatother
\begin{document}
\setcolorlist{red,cyan,blue,green}
\begin{tikzpicture}
\drawcoloredarrows{1,...,4}
\end{tikzpicture}
\end{document}
以下是我推荐的方法:
\documentclass{article}
\usepackage{tikz}
\usepackage{keyreader}
\makeatletter
\krddefinekeys{claudiocolor}[claudio@col@]{%
cmd/1/black;cmd/2/black;cmd/3/black;cmd/4/black;cmd/5/black;cmd/6/black;
}
\newcommand*\setcolorlist[1]{\krdsetkeys{claudiocolor}{#1}}
\newcommand*\usecolor[1]{\@nameuse{claudio@col@#1}}
% Command in which colors are necessary:
\newcommand*\drawcoloredarrows[1]{%
\foreach \x in {#1}{%
\draw[\usecolor\x,-stealth] (0,-\x)--(2,-\x);
}%
}
\makeatother
\begin{document}
\setcolorlist{1=red,2=blue,3=cyan,4=green,5=magenta,6=purple}
\begin{tikzpicture}
\drawcoloredarrows{1,...,4}
\end{tikzpicture}
\end{document}