宏可以显示水平等距文本和数学运算,并且可以超过单行吗?

宏可以显示水平等距文本和数学运算,并且可以超过单行吗?

我正在尝试编写一个宏,它可以接受一组选择,然后列出它们(以特定但可能随机的顺序),以尽可能少地使用垂直空间,同时仍能很好地呈现。我想出了一个解决方案,但它使用了 hbox,因此如果单个给定的选择超过一行文本,就会失败。我的 MWE:

\documentclass{article}
\usepackage{forloop}
\makeatletter
\newcounter{choiceNum}
\newcounter{choiceEnvNum}
\newcounter{Iteration@printChoices}

\newenvironment{choices}{% Start environment code for multiple choice Choices environment
        \setcounter{choiceNum}{0}% New MCChoices environment means a new set of choices, so reset current choice to 0.
        \refstepcounter{choiceEnvNum}
    }% End of start-environment code.
    {% Start of end-environment code.
        \printChoices
    }% End of end-environment code.


\newcommand{\choice}[1]{% Choice command holds a multiple choice option by generating a new command with unique name that will be used to write the outputs at the end of the MCChoices environment.
        \refstepcounter{choiceNum}% A new choice means we need to step current choice (before definition since counters starts at 0)
        \expandafter\def\csname \Roman{choiceEnvNum}choice\roman{choiceNum}\endcsname{#1}
    }% End of \choice code.


\providecommand{\printChoices}{% \printChoices is an internal macro to print the choices at the end of a MCChoice environment, depending on if we want them shuffled or not. Note: I removed the shuffle content as this is a mwe

    % Now print the results:

    \stepcounter{choiceNum}% Step counter for the < symbol in foreloop.

    \forloop{Iteration@printChoices}{1}{\arabic{Iteration@printChoices}<\arabic{choiceNum}}{% Begin forloop
        \hspace*{0pt}\hfill\hbox{\expandafter\choiceLetter{\arabic{Iteration@printChoices}} % Print the correct letter of the choice. Note that \hspace*{0pt} forces the \hfill to populate correctly, or else TeX will ignore it at the start of lines which makes everything look super weird.
        \csname \Roman{choiceEnvNum}choice\roman{Iteration@printChoices}\endcsname}\hfill% Print choice
        }% End forloop
        % Check to see if we have a "last choice".
            \ifcsname\Roman{choiceEnvNum}lastChoice\endcsname% If we do, then we should print it.
            \hspace*{0pt}\hfill\hbox{\expandafter\choiceLetter{\arabic{choiceNum}} % Since we stepped choiceNum this hack will work.
            \csname \Roman{choiceEnvNum}lastChoice\endcsname}\hfill% Print lastChoice
            \fi% 
    }% End of \printChoices code.

\providecommand{\choiceLetter}[1]{% A simple internal command to print the correct letter.
    \ifnum\numexpr#1\relax=1 A)\fi
    \ifnum\numexpr#1\relax=2 B)\fi
    \ifnum\numexpr#1\relax=3 C)\fi
    \ifnum\numexpr#1\relax=4 D)\fi
    \ifnum\numexpr#1\relax=5 E)\fi
    \ifnum\numexpr#1\relax>5 ?Too many choices?)\fi
    }% End \choiceLetter code.

\providecommand{\lastChoice}[1]{% This is a \choice command, but it will be forced to be printed last.
        \expandafter\def\csname \Roman{choiceEnvNum}lastChoice\endcsname{\noexpand{#1}}
    }% End of \lastChoice command.

\begin{document}
\begin{choices}
\choice{This is choice 1}
\choice{This is choice 2}
\choice{This is choice 3}
\choice{And this is some really long choice that will not fit on one line, which is why hbox really isn't a great plan because I may have someone crazy try to do something like this even though they really probably shouldn't!}
\choice{Oh, and we need math, so $\frac{x}{2} \cdot 15 = $ ?}
\end{choices}
\end{document}

这只是我想出的解决方案,但我希望有某种(相对)完美分离的水平扩展,最多 5 个选项,只有当单个\choice内容占据整行时才会换行。我无法指定宽度为一定量,因为单个长选项会变成垂直列,而真正的目标是最小化垂直扩展。因此,我使用 hbox 来避免换行,但显然有些情况下换行是必要的,或者内容超出了纸张的一侧。

有什么建议么?

答案1

这或许就是您所寻找的东西?

\documentclass{article}
\usepackage{forloop}
\makeatletter
\newcounter{choiceNum}
\newcounter{choiceEnvNum}
\newcounter{Iteration@printChoices}

\newenvironment{choices}{% Start environment code for multiple choice Choices environment
        \setcounter{choiceNum}{0}% New MCChoices environment means a new set of choices, so reset current choice to 0.
        \refstepcounter{choiceEnvNum}
    }% End of start-environment code.
    {% Start of end-environment code.
        \printChoices
    }% End of end-environment code.


\newcommand{\choice}[1]{% Choice command holds a multiple choice option by generating a new command with unique name that will be used to write the outputs at the end of the MCChoices environment.
        \refstepcounter{choiceNum}% A new choice means we need to step current choice (before definition since counters starts at 0)
        \expandafter\def\csname \Roman{choiceEnvNum}choice\roman{choiceNum}\endcsname{#1}
    }% End of \choice code.


\providecommand{\printChoices}{% \printChoices is an internal macro to print the choices at the end of a MCChoice environment, depending on if we want them shuffled or not. Note: I removed the shuffle content as this is a mwe

    % Now print the results:

    \stepcounter{choiceNum}% Step counter for the < symbol in foreloop.
    \newdimen\qb@xlen \qb@xlen 0pt

    \forloop{Iteration@printChoices}{1}{\arabic{Iteration@printChoices}<\arabic{choiceNum}}{% Begin forloop
        \parindent=0pt
        \newbox\ch@icebox
        \setbox\ch@icebox\hbox{\expandafter\choiceLetter{\arabic{Iteration@printChoices}} % Print the correct letter of the choice. Note that \hspace*{0pt} forces the \hfill to populate correctly, or else TeX will ignore it at the start of lines which makes everything look super weird.
        \csname \Roman{choiceEnvNum}choice\roman{Iteration@printChoices}\endcsname }
        \ifdim \wd\ch@icebox > \textwidth
            % Too wide!
            \hfill \par \unhbox\ch@icebox \hfill \par
            \qb@xlen=0pt
        \else
            \advance\qb@xlen by \wd\ch@icebox
            \ifdim \qb@xlen > \textwidth
                \par \hfill \box\ch@icebox \hfill
                \qb@xlen=\wd\ch@icebox
            \else
                \hfill \box\ch@icebox \hfill 
            \fi
        \fi
        % \hfill\hbox{\expandafter\choiceLetter{\arabic{Iteration@printChoices}} % Print the correct letter of the choice. Note that \hspace*{0pt} forces the \hfill to populate correctly, or else TeX will ignore it at the start of lines which makes everything look super weird.
        % \csname \Roman{choiceEnvNum}choice\roman{Iteration@printChoices}\endcsname}\hfill% Print choice
        }% End forloop
        % Check to see if we have a "last choice".
            \ifcsname\Roman{choiceEnvNum}lastChoice\endcsname% If we do, then we should print it.
            \hspace*{0pt}\hfill\hbox{\expandafter\choiceLetter{\arabic{choiceNum}} % Since we stepped choiceNum this hack will work.
            \csname \Roman{choiceEnvNum}lastChoice\endcsname}\hfill% Print lastChoice
            \fi% 
    }% End of \printChoices code.

\providecommand{\choiceLetter}[1]{% A simple internal command to print the correct letter.
    \ifnum\numexpr#1\relax=1 A)\fi
    \ifnum\numexpr#1\relax=2 B)\fi
    \ifnum\numexpr#1\relax=3 C)\fi
    \ifnum\numexpr#1\relax=4 D)\fi
    \ifnum\numexpr#1\relax=5 E)\fi
    \ifnum\numexpr#1\relax>5 ?Too many choices?)\fi
    }% End \choiceLetter code.

\providecommand{\lastChoice}[1]{% This is a \choice command, but it will be forced to be printed last.
        \expandafter\def\csname \Roman{choiceEnvNum}lastChoice\endcsname{\noexpand{#1}}
    }% End of \lastChoice command.

\begin{document}
\begin{choices}
\choice{This is choice 1}
\choice{This is choice 2}
\choice{This is choice 3, it can't fit with A and B}
\choice{And this is some really long choice that will not fit on one line, which is why hbox really isn't a great plan because I may have someone crazy try to do something like this even though they really probably shouldn't!}
\choice{Oh, and we need math, so $\frac{x}{2} \cdot 15 = $ ?}
\end{choices}
\end{document}

在此处输入图片描述

答案2

这是 Gleason 答案的双框版本。我还参与了许多不必要的更改和一些真正必要的更改(例如不将\newbox\newdimen放在循环内)。

一个关键的附加功能是\choicesep(胶水),它既可以扩展\hfill,又可以提供最小 2em 的间隙。

\documentclass{article}
\usepackage{forloop}
\makeatletter
\newcounter{choiceNum}
\newcounter{choiceEnvNum}
\newcounter{Iteration@printChoices}

\renewcommand{\thechoiceEnvNum}{\Roman{choiceEnvNum}}
\renewcommand{\thechoiceNum}{\Alph{choiceNum}}
\renewcommand{\theIteration@printChoices}{\Alph{Iteration@printChoices}}

\newsavebox\choicebox
\newskip\choicesep% separation between choices (glue)
\choicesep=2em plus 100fil

\newenvironment{choices}{% Start environment code for multiple choice Choices environment
        \setcounter{choiceNum}{0}% New MCChoices environment means a new set of choices, so reset current choice to 0.
        \refstepcounter{choiceEnvNum}%
    }% End of start-environment code.
    {% Start of end-environment code.
        \printChoices
    }% End of end-environment code.


\newcommand{\choice}[1]{% Choice command holds a multiple choice option by generating a new command with unique name that will be used to write the outputs at the end of the MCChoices environment.
        \refstepcounter{choiceNum}% A new choice means we need to step current choice (before definition since counters starts at 0)
        \expandafter\def\csname \thechoiceEnvNum choice\roman{choiceNum}\endcsname{#1}%
        \ignorespaces
    }% End of \choice code.


\providecommand{\printChoices}{% \printChoices is an internal macro to print the choices at the end of a MCChoice environment, depending on if we want them shuffled or not. Note: I removed the shuffle content as this is a mwe
    % Now print the results:
    \stepcounter{choiceNum}% Step counter for the < symbol in foreloop.
    \savebox\choicebox{}%
    \parindent=0pt
    \forloop{Iteration@printChoices}{1}{\value{Iteration@printChoices}<\value{choiceNum}}{% Begin forloop
        \sbox0{\theIteration@printChoices\space
          \csname \thechoiceEnvNum choice\roman{Iteration@printChoices}\endcsname}%
        \ifdim \textwidth > \dimexpr \wd\choicebox+\wd0\relax
            % okay
            \ifdim \wd\choicebox>0pt
              \savebox\choicebox{\unhbox\choicebox \hspace{\choicesep}\unhbox0}%
            \else
              \setbox\choicebox=\box0
            \fi
        \else% too wide
            \ifdim \wd\choicebox>0pt
              \par
              \hangindent=1em
              \unhbox\choicebox
            \fi
            \setbox\choicebox=\box0
        \fi}%
    \ifdim \wd\choicebox>0pt %last box
      \par
      \hangindent=1em
      \unhbox\choicebox
      \par
    \fi
    }% End of \printChoices code.

\begin{document}
\begin{choices}
\choice{This is choice 1}
\choice{This is choice 2}
\choice{This is choice 3, it can't fit with A and B}
\choice{And this is some really long choice that will not fit on one line, which is why hbox really isn't a great plan because I may have someone crazy try to do something like this even though they really probably shouldn't!}
\choice{Oh, and we need math, so $\frac{x}{2} \cdot 15 = $ ?}
\end{choices}
\end{document}

演示

相关内容