我有一段代码:
\documentclass{scrartcl}
\usepackage{pbox,calc}
\makeatletter
\newcommand*{\strippt}[1]{\strip@pt#1}
\makeatother
\newlength{\pointsExo}
\setlength{\pointsExo}{4pt}
\newlength{\pointsSousTotal}
\setlength{\pointsSousTotal}{0pt}
\newlength{\souspointsExo}
\newcommand{\sousPoints}[1]{
\setlength{\souspointsExo}{#1pt}
\setlength{\pointsSousTotal}{\pointsSousTotal + #1pt}
{\scriptsize{(#1~\ifdim#1pt=1pt point\else points\fi/\strippt\pointsExo)}}
}
\newcommand{\subexo}[2]{
\textsf{ %%If I comment these two lines, the sub-total is correct
#1\hfill\sousPoints{#2}% Points
} %%If I comment these two lines, the sub-total is correct
\medskip
}
\newcommand{\exercice}[2]{
\setlength{\pointsExo}{#2pt}
\setlength{\pointsSousTotal}{0pt}
\medskip
#1\hfill#2 Points% Points
\medskip
}
\begin{document}
\exercice{A first one}{2.5}
\subexo{Anything}{2}
\subexo{Something}{0.5}
Sub-Total: \strippt\pointsSousTotal %should display 2.5
\exercice{A title}{4}
\subexo{another thing}{2.5}
\subexo{and a thing}{1.5}
Sub-Total: \strippt\pointsSousTotal %should display 4
\end{document}
问题是它应该显示如下内容:
第一个 2.5 分
任何事物(2 分/2.5)
某事(0.5 分/2.5)
小计:2.5
一个标题
另一件事 (2.5 分/4)
和一件事(1.5 分/4)
小计:4
但是,除非我注释掉指示的两行(目前,一个封闭的 \textsf{...},但只要我将 \sousPoints{#2} 括在两个花括号之间,问题就是一样的),否则我会得到这个:
第一个 2.5 分
任何事物(2 分/2.5)
某事(0.5 分/2.5)
小计:0
一个标题
另一件事 (2.5 分/4)
和一件事(1.5 分/4)
小计:0
在括号 {...} 内使用长度有什么问题?这是一个错误吗?对命令的工作方式理解不正确?
答案1
您需要进行全局分配才能在组外看到效果:
\documentclass{scrartcl}
\usepackage{pbox,calc}
\makeatletter
\newcommand*{\strippt}[1]{\strip@pt#1}
\makeatother
\newlength{\pointsExo}
\setlength{\pointsExo}{4pt}
\newlength{\pointsSousTotal}
\setlength{\pointsSousTotal}{0pt}
\newlength{\souspointsExo}
\newcommand{\sousPoints}[1]{% don't let egreg get points for missing %
\setlength{\souspointsExo}{#1pt}% don't let egreg get points for missing %
\setlength{\pointsSousTotal}{\pointsSousTotal + #1pt}% don't let egreg get points for missing %
\global\souspointsExo=\souspointsExo % a bit costly of save stack but unlikely to have 1000s of these.
\global\pointsSousTotal=\pointsSousTotal
{\scriptsize{(#1~\ifdim#1pt=1pt point\else points\fi/\strippt\pointsExo)}}% don't let egreg get points for missing %
}
\newcommand{\subexo}[2]{% don't let egreg get points for missing %
\textsf{%%If I comment these two lines, the sub-total is correct
#1\hfill\sousPoints{#2}% Points
}%%If I comment these two lines, the sub-total is correct
\medskip
}
\newcommand{\exercice}[2]{% don't let egreg get points for missing %
\setlength{\pointsExo}{#2pt}% don't let egreg get points for missing %
\setlength{\pointsSousTotal}{0pt}% don't let egreg get points for missing %
\medskip
#1\hfill#2 Points% Points
\medskip
}
\begin{document}
\exercice{A first one}{2.5}
\subexo{Anything}{2}
\subexo{Something}{0.5}
Sub-Total: \strippt\pointsSousTotal %should display 2.5
\exercice{A title}{4}
\subexo{another thing}{2.5}
\subexo{and a thing}{1.5}
Sub-Total: \strippt\pointsSousTotal %should display 4
\end{document}
答案2
我在这里发布的是我做的一个补充测试。我发布它是为了演示 \setlength 在组内或组外时的效果(这是 David Carlisle 在我的问题的第一个评论中提出的一种可能的解决方案)。
不过,我更喜欢 David Carlisle 的 \global 答案。它允许在一个命令中显示和设置值(因为我永远不会在一个文档中调用超过 50 次此命令,所以它不会消耗太多资源)。
\documentclass{scrartcl}
\usepackage{pbox,calc}
\makeatletter
\newcommand*{\strippt}[1]{\strip@pt#1}
\makeatother
\newlength{\pointsTotal}
\setlength{\pointsTotal}{0pt}
\newcounter{numExercice}
\newlength{\pointsExo}
\setlength{\pointsExo}{4pt}
\newlength{\pointsSousTotal}
\setlength{\pointsSousTotal}{0pt}
\newlength{\souspointsExo}
\newcommand{\sousPoints}[1]{% Will only display the points, not make the assignement
{\scriptsize{(#1~\ifdim#1pt<2pt point\else points\fi/\strippt\pointsExo)}}%
}
\newcounter{sousExercice}[numExercice]
\newcommand{\subexo}[2]{%
\stepcounter{sousExercice}%
\setlength{\souspointsExo}{#2pt}%makes the assignment outside of the group, no global required
\setlength{\pointsSousTotal}{\pointsSousTotal + #2pt}%makes the assignment outside of the group, no global required
\medskip
\textsf{%
\textbf{\arabic{numExercice}.\arabic{sousExercice}} :~#1%
\hfill\sousPoints{#2}% Points
}
}
\newcommand{\exercice}[2]{%
\stepcounter{numExercice}%
\setlength{\pointsExo}{#2pt}%
\setlength{\pointsSousTotal}{0pt}%
\setlength{\pointsTotal}{\pointsTotal + #2pt}%
\medskip
\textbf{Exercice \arabic{numExercice}} :~#1\hfill%
{\normalsize{(#2~\ifdim#2pt<2pt point\else points\fi)}}% Points
\medskip
}
\newcommand{\subtotal}{\strippt\pointsSousTotal}
\newcommand{\Total}{Total des points : \strippt\pointsTotal}
\begin{document}
\exercice{A first one}{2.5}
\subexo{Anything}{2}
\subexo{Something}{0.5}
Sub-Total: \strippt\pointsSousTotal
\exercice{A title}{4}
\subexo{another thing}{2.5}
\subexo{and a thing}{1.5}
Sub-Total: \strippt\pointsSousTotal
\end{document}