考虑Ulrich Diez 的回答这篇文章:\pgfmathsetlengthmacro 与循环不兼容?:
\documentclass[]{article}
\usepackage[most]{tcolorbox}
% Define the command \NiceForEachElement to ensure error-message in case it is already defined.
% This way you can ensure to a certain degree that using `\niceelement` as Foreach-variable
% does not override something that alerady exists.
\newcommand\NiceForEachElement{}%
\newcommand\UseImageLeft[2]{%
% #1 preceding phrase "image-"
% #2 number of image
\IfFileExists{#1#2.jpg}%
{\includegraphics[scale=0.2]{#1#2.jpg}}%
{\includegraphics[scale=0.2]{example-image.jpg}}%
}
\newcommand*\ImageLeft[1]{\UseImageLeft{Image-}{#1}}
% Problem ===================================
%\pgfmathsetlengthmacro\LeftWidth{width("\ImageLeft")}
% =======================================
\begin{document}
% outside the loop the width of Image-7.jpg or example-image.jpg:
\pgfmathsetlengthmacro\LeftWidth{width("\noexpand\noexpand\noexpand\ImageLeft{7}")}%
%Activate the following line in case you wish to see on screen/console what the definition of \LeftWidth looks like now:
%\show\LeftWidth
% inside the loop:
\foreach \NiceForEachElement in {1,...,2}{%
\pgfmathsetlengthmacro\LeftWidth{width("\noexpand\noexpand\noexpand\ImageLeft{\NiceForEachElement}")}%
%Activate the following line in case you wish to see on screen/console what the definition of \LeftWidth looks like now:
%\show\LeftWidth
% On any page (begin)
\begin{tcolorbox}[]%
\begin{tcbitemize}[]%
\tcbitem[] \ImageLeft{\NiceForEachElement}%
\end{tcbitemize}%
\end{tcolorbox}%
% On any page (end)
\newpage
}
\end{document}
编译效果非常好。
它也适用于tikz
。请参阅此工作 MWE:
\documentclass[]{article}
\usepackage{tikz}%
答案1
您即将到达:
\newcommand
在 -loop 中无关紧要,\foreach
因为 -loop 的每次迭代都\foreach
在其自己的组/本地范围内进行。迭代之后,\newcommand
该迭代中执行的操作将随迭代发生的本地范围一起消失。
但是您需要将表示在循环内定义的宏的参数的哈希值加倍\foreach
。
原因是:
基本模式为\foreach
:
\foreach⟨comma-list or macro expanding to comma-list⟩{%
⟨Tokens to carry out repeatedly⟩%
}
在其他操作之下\foreach
触发定义一个临时宏。\pgffor@body
⟨Tokens to carry out repeatedly⟩
就像是。\def\pgffor@body{⟨Tokens to carry out repeatedly⟩}
\pgffor@body
没有参数文本/不处理参数。但如果包含诸如或 之类的⟨Tokens to carry out repeatedly⟩
内容,则 LaTeX 会假定这些内容旨在表示 的参数,并引发错误消息:#1
#2
\pgffor@body
Illegal parameter number in definition of \pgffor@body.
<to be read again>
1
因此,当⟨Tokens to carry out repeatedly⟩
其本身包含宏定义时,这些宏定义的哈希值需要加倍 - 当在其他宏定义中嵌套宏定义时,始终需要使用内部宏定义将哈希值加倍。
我不知道\foreach
pgfmanual.pdf 中是否记录了将内部宏定义哈希值加倍的必要性。如果没有,可能值得向 tikz/pgf 的作者/维护者提供一点提示。
但我认为这很少需要,因为通常你可以在循环外定义宏。
但有时我使用\foreach
-variables 作为宏名称的一部分,这些宏将在以下\foreach
方面进行定义:
\expandafter\newcommand\csname\foreachvariable CommonNamePart\endcsname[1]{...}
\global\expandafter\let\csname\foreachvariable CommonNamePart\expandafter\endcsname\csname\foreachvariable CommonNamePart\endcsname
以便它们在\foreach
循环之外也可用。
这里与加倍哈希值的需求相关。
当遇到此类错误消息时Illegal parameter number in definition of...
,最好检查宏定义中是否存在宏定义嵌套,以及是否正确完成了内部宏定义的哈希加倍。
\documentclass[]{article}
\usepackage{tikz}%
\usepackage[most]{tcolorbox}
% Define the command \NiceForEachElement to ensure error-message in case it is already defined.
% This way you can ensure to a certain degree that using `\niceelement` as Foreach-variable
% does not override something that alerady exists.
\newcommand\NiceForEachElement{}%
\newcommand\UseImageLeft[2]{%
% #1 preceding phrase "image-"
% #2 number of image
\IfFileExists{#1#2.jpg}%
{\includegraphics[scale=0.2]{#1#2.jpg}}%
{\includegraphics[scale=0.2]{example-image.jpg}}%
}
\newcommand*\ImageLeft[1]{\UseImageLeft{Image-}{#1}}
\begin{document}
% outside the loop the width of Image-7.jpg or example-image.jpg:
\pgfmathsetlengthmacro\LeftWidth{width("\noexpand\noexpand\noexpand\ImageLeft{7}")}%
%Activate the following line in case you wish to see on screen/console what the definition of \LeftWidth looks like now:
%\show\LeftWidth
% inside the loop:
\foreach \NiceForEachElement in {1,...,2}{%
\pgfmathsetlengthmacro\LeftWidth{width("\noexpand\noexpand\noexpand\ImageLeft{\NiceForEachElement}")}%
%Activate the following line in case you wish to see on screen/console what the definition of \LeftWidth looks like now:
%\show\LeftWidth
% On any page (begin)
\begin{tcolorbox}[]%
\begin{tcbitemize}[]%
\tcbitem[] \ImageLeft{\NiceForEachElement}%
\end{tcbitemize}%
\end{tcolorbox}%
% On any page (end)
\begin{tikzpicture}%
\filldraw[black] (0,0) circle (2pt) node[anchor=west] {This was drawn inside a tikzpicture};%
%
% DOUBLE THE HASHES IN THE DEFINITION OF \xRuler
% DOUBLE THE HASHES IN THE DEFINITION OF \xRuler
%
\newcommand\xRuler[2]{%
\filldraw[black] (##1,##2) circle (2pt) node[anchor=west] {This was drawn inside a tikzpicture};
}%
\end{tikzpicture}%
\newpage
}
\end{document}
意识到:
由于 的定义\xRuler
不依赖于\foreach
-variable-macros 的扩展,因此\xRuler
可以在 之外进行定义\foreach
,这将为 LaTeX 节省大量重复的定义工作:
\documentclass[]{article}
\usepackage{tikz}%
\usepackage[most]{tcolorbox}
% Define the command \NiceForEachElement to ensure error-message in case it is already defined.
% This way you can ensure to a certain degree that using `\niceelement` as Foreach-variable
% does not override something that alerady exists.
\newcommand\NiceForEachElement{}%
\newcommand\UseImageLeft[2]{%
% #1 preceding phrase "image-"
% #2 number of image
\IfFileExists{#1#2.jpg}%
{\includegraphics[scale=0.2]{#1#2.jpg}}%
{\includegraphics[scale=0.2]{example-image.jpg}}%
}
\newcommand*\ImageLeft[1]{\UseImageLeft{Image-}{#1}}
\newcommand\xRuler[2]{%
\filldraw[black] (#1,#2) circle (2pt) node[anchor=west] {This was drawn inside a tikzpicture};
}%
\begin{document}
% outside the loop the width of Image-7.jpg or example-image.jpg:
\pgfmathsetlengthmacro\LeftWidth{width("\noexpand\noexpand\noexpand\ImageLeft{7}")}%
%Activate the following line in case you wish to see on screen/console what the definition of \LeftWidth looks like now:
%\show\LeftWidth
% inside the loop:
\foreach \NiceForEachElement in {1,...,2}{%
\pgfmathsetlengthmacro\LeftWidth{width("\noexpand\noexpand\noexpand\ImageLeft{\NiceForEachElement}")}%
%Activate the following line in case you wish to see on screen/console what the definition of \LeftWidth looks like now:
%\show\LeftWidth
% On any page (begin)
\begin{tcolorbox}[]%
\begin{tcbitemize}[]%
\tcbitem[] \ImageLeft{\NiceForEachElement}%
\end{tcbitemize}%
\end{tcolorbox}%
% On any page (end)
\begin{tikzpicture}%
\filldraw[black] (0,0) circle (2pt) node[anchor=west] {This was drawn inside a tikzpicture};%
\end{tikzpicture}%
\newpage
}
\end{document}