\ pgfmathsetlengthmacro incompatível com um loop?
O código a seguir compila perfeitamente:
\documentclass[]{article}
\usepackage[most]{tcolorbox}
\newcommand\UseImageLeft[1]{%
\IfFileExists{#1\i.jpg}%
{\includegraphics[scale=0.2]{#1\i.jpg}}%
{\includegraphics[scale=0.2]{example-image.jpg}}%
}
\def\ImageLeft{\UseImageLeft{Image-}}
% Problem ===================================
% \pgfmathsetlengthmacro\LeftWidth{width("\ImageLeft")}
% =======================================
\begin{document}
\foreach \i in {1,...,2}{
% On any page (begin)
\begin{tcolorbox}[]
\begin{tcbitemize}[]
\tcbitem[] \ImageLeft
\end{tcbitemize}
\end{tcolorbox}
% On any page (end)
\newpage
}
\end{document}
Meu problema é que eu quero descomentar \pgfmathsetlengthmacro\LeftWidth{width("\ImageLeft")}, mas o código não compila mais. Como posso consertar isso, por favor?
Respostas
Problema 1:
Você usa \pgfmathsetlengthmacro\LeftWidth{width("\ImageLeft")} fora do \foreachloop. Mas com \pgfmathsetlengthmacro\LeftWidth{width("\ImageLeft")}a macro \ImageLefté usada que por sua vez usa \UseImageLeftque por sua vez usa \ienquanto \ié definido para produzir o número de uma imagem apenas dentro do \foreach-loop.
Problema 2:
Você tem \pgfmathsetlengthmacro\LeftWidth{width("\ImageLeft")}qual é o padrão
\pgfmathsetlengthmacro\LeftWidth{⟨expression⟩}
com
⟨expression⟩ = width("\ImageLeft")
, enquanto
width("\ImageLeft")
por sua vez é do padrão
com = .
width(⟨expression⟩)
⟨expression⟩"\ImageLeft"
Isso significa que \ImageLefté avaliado ⟨expression⟩duas vezes:
A primeira vez quando a ⟨expression⟩formação do argumento de \pgfmathsetlengthmacro\LeftWidthé avaliada.
A segunda vez quando a ⟨expression⟩formação do argumento de width(...)é avaliada.
pgfmanual.pdf, seção "95.2 Sintaxe para Expressões Matemáticas: Operadores" diz na explicação do -operador:"x"
... No entanto, como cada expressão é expandida com \ edef antes de ser analisada, macros (por exemplo, comandos de fonte como \ tt ou \ Huge) podem precisar ser “protegidos” dessa expansão (por exemplo, \ noexpand \ Huge). Idealmente, você deve evitar essas macros de qualquer maneira. Obviamente, esses operadores devem ser usados com muito cuidado, pois cálculos adicionais provavelmente não serão possíveis com o resultado.
Essas informações não estão relacionadas apenas ao -operador. Essas informações são relevantes sempre que se trata de avaliar um . É uma regra geral aplicada durante a avaliação de cada . Portanto, acho que não é uma boa ideia transmitir essas informações apenas ao explicar um operador especial."x"⟨expression⟩⟨expression⟩
Seja como for:
Juntando as informações, você descobre que \ImageLefté avaliado por \edefduas vezes. Como a cadeia de expansão é \ImageLeft→ \UseImageLeft→ ...\includegraphics..., isso implica que duas tentativas de avaliação de \includegraphicsvia \edefocorrem.
Mas no caso de você não usar uma das mais recentes distribuições de TeX \includegraphics, não funciona em \edefcontextos de expansão. Isso ocorre porque em distribuições TeX mais antigas \includegraphicsnão é "protegido" - "protegido" refere-se a um mecanismo interno do LaTeX para prevenir a expansão de comandos em situações onde essa expansão não funcionaria - e "depende de" realizar atribuições temporárias, por exemplo, em termos de \def, enquanto tais atribuições não são realizadas enquanto a \edef-avaliação está em andamento. \edefdispara a expansão de tokens expansíveis enquanto \defé um primitivo não expansível .
Portanto, se não estiver usando uma das distribuições TeX mais recentes, você precisará tomar medidas de precaução para evitar a expansão / avaliação do comando \ImageLeft(e, portanto, também evitar a expansão / avaliação de \includegraphics) com cada uma dessas avaliações \edef. (Nas distribuições de TeX mais recentes, essas medidas de precaução não são um incômodo nem são necessárias.)
Você pode evitar a expansão / avaliação prefixando \ImageLeftcom \noexpand\noexpand\noexpand.
A primeira \edefavaliação, aplicada em <code>\noexpand\noexpand\noexpand\ImageLeft</code>,
produz
<code>\noexpand\ImageLeft</code>.
O segundo \edef-avaliação vai ser aplicado em que, por sua vez, que, em rendimentos:
<code>\ImageLeft</code>.
Problema 3:
egreg apontou que \ijá está definido no LaTeX e que você provavelmente não deseja substituir essa definição. Portanto, no exemplo abaixo, usei em \NiceForEachElementvez de \i.
\documentclass[]{article}
\usepackage[most]{tcolorbox}
\newcommand\UseImageLeft[1]{%
\IfFileExists{#1\NiceForEachElement.jpg}%
{\includegraphics[scale=0.2]{#1\NiceForEachElement.jpg}}%
{\includegraphics[scale=0.2]{example-image.jpg}}%
}
\def\ImageLeft{\UseImageLeft{Image-}}
% Problem ===================================
%\pgfmathsetlengthmacro\LeftWidth{width("\ImageLeft")}
% =======================================
\begin{document}
\foreach \NiceForEachElement in {1,...,2}{%
\pgfmathsetlengthmacro\LeftWidth{width("\noexpand\noexpand\noexpand\ImageLeft")}%
%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
\end{tcbitemize}%
\end{tcolorbox}%
% On any page (end)
\newpage
}
\end{document}
Se você deseja ser capaz de usar \ImageLeftfora do loop também, defina \ImageLeftetc para processar um argumento em vez de processar \i/ \NiceForEachElement.
Dentro do loop, você pode passar \i/ \NiceForEachElementcomo argumento.
Fora do loop, você pode passar o número da imagem como argumento diretamente.
\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}
Não use variáveis de loop fora de um loop, nem no código executado, nem nas definições.
\documentclass[]{article}
\usepackage[most]{tcolorbox}
\newcommand\UseImageLeft[1]{%
\IfFileExists{#1.jpg}%
{\includegraphics[scale=0.2]{#1.jpg}}%
{\includegraphics[scale=0.2]{example-image.jpg}}%
}
\begin{document}
\foreach \i in {1,...,2}{%
\pgfmathsetlengthmacro\LeftWidth{width("\UseImageLeft{image\i}")}%
% On any page (begin)
\begin{tcolorbox}[]
\begin{tcbitemize}[]
\tcbitem[] \UseImageLeft{image\i}
\end{tcbitemize}
\end{tcolorbox}
% On any page (end)
\newpage
}^
\end{document}