\mathchoice 的正确使用

\mathchoice 的正确使用

我正在尝试学习如何使用\mathchoice

在解决方案发布之前\fbox 的非侵入式替代品?,我尝试使用mathchoice来调整参数的大小,然后测量其高度、深度和宽度。为了简单起见,我首先定义:

\newcommand{\SetHeightDepthWidth}[1]{%          
    \settoheight{\fillbox@height}{#1}%   
    \settodepth{\fillbox@depth}{#1}%     
    \settowidth{\fillbox@width}{#1}%     
}%

然后将宏的开头调整\fillbox为:

\newcommand{\fillbox}[1]{%
  \ifmmode%                                             
    \mathchoice%                                        
        {\SetHeightDepthWidth{$\displaystyle#1$}}%      
        {\SetHeightDepthWidth{$\textstyle#1$}}%         
        {\SetHeightDepthWidth{$\scriptstyle#1$}}%       
        {\SetHeightDepthWidth{$\scriptscriptstyle#1$}}% 
  \else%                                                
    \SetHeightDepthWidth{#1}%                           
  \fi%                                                  

进行这些更改之前,输出为:

在此处输入图片描述

但通过上述改变我得到了:

在此处输入图片描述

那么,发生了什么?在我看来,这似乎是与分组相关的一些问题,因为需要额外的括号组来将四个参数传递给\mathchoice,但不知道如何修复它。它的\mathchoice行为确实与许多其他类型的条件宏不同,例如\iftoggle{condition}{code if true}{code if false}来自etoolbox

代码:

新代码被标记,旧代码保留注释,以简化比较。

\documentclass{article}
\usepackage{tikz}

\makeatletter
  \newlength\fillbox@height%
  \newlength\fillbox@depth%
  \newlength\fillbox@width%
  \newcommand{\SetHeightDepthWidth}[1]{%   new
      \settoheight{\fillbox@height}{#1}%   new
      \settodepth{\fillbox@depth}{#1}%     new
      \settowidth{\fillbox@width}{#1}%     new
  }%

  \newcommand{\fillbox}[1]{%
  \ifmmode%                                             new
    \mathchoice%                                        new
        {\SetHeightDepthWidth{$\displaystyle#1$}}%      new
        {\SetHeightDepthWidth{$\textstyle#1$}}%         new
        {\SetHeightDepthWidth{$\scriptstyle#1$}}%       new
        {\SetHeightDepthWidth{$\scriptscriptstyle#1$}}% new
  \else%                                                new
    \SetHeightDepthWidth{#1}%                           new
  \fi%                                                  new
  %\ifmmode%
  %  \settoheight{\fillbox@height}{$#1$}%
  %  \settodepth{\fillbox@depth}{$#1$}%
  %  \settowidth{\fillbox@width}{$#1$}%
  %\else%
  %  \settoheight{\fillbox@height}{#1}%
  %  \settodepth{\fillbox@depth}{#1}%
  %  \settowidth{\fillbox@width}{#1}%
  %\fi%
  \raisebox{-\fillbox@depth}{%
    \begin{tikzpicture}[scale=1]
    \pgfsetfillcolor{yellow!90!red}
    \pgfsetfillopacity{0.5}
    \pgfsetrectcap
    \fill (0,-\fillbox@depth) rectangle (\fillbox@width,\fillbox@height);
    \pgfsetfillcolor{yellow!50!black}
    \pgfsetfillopacity{1}
    \fill (0,-\fillbox@depth)
          rectangle (\fillbox@width,-\fillbox@depth+.1pt);
    \fill (0,\fillbox@height)
          rectangle (\fillbox@width,\[email protected]);
    \fill (0,-\fillbox@depth)
          rectangle (.1pt,\fillbox@height);
    \fill (\fillbox@width,-\fillbox@depth)
          rectangle (\[email protected],\fillbox@height);
    \end{tikzpicture}%
    \kern-\fillbox@width%
  }%
  #1%
}
\makeatother

\begin{document}

\vskip1em
$\fillbox{p}_{\fillbox{x}}
  \mathrel{\stackrel{\fillbox{_{~+}}}{\fillbox{\leftarrow}}}
  \fillbox{(}\fillbox{\frac{\fillbox{1}}{\fillbox{2}}}\fillbox{\cdot}
  \fillbox{a}_{\fillbox{x}}\fillbox{\cdot}%
  \fillbox{\Delta}\fillbox{t}^{\fillbox{2}}\fillbox{)} \fillbox{+}
  \fillbox{(}\fillbox{v}_{\fillbox{x}}\fillbox{\cdot}%
  \fillbox{\Delta}\fillbox{t}\fillbox{)}$\fillbox{;}\par
$\fillbox{v}_{\fillbox{x}}
  \mathrel{\stackrel{\fillbox{_{~+}}}{\fillbox{\leftarrow}}}
  \fillbox{a}_{\fillbox{x}}\fillbox{\cdot}%
  \fillbox{\Delta}\fillbox{t}$\fillbox{;}\par
%    
%            This section is not relevant to the problem here.
%\vskip1em
%$p_x \mathrel{\stackrel{_{~+}}{\leftarrow}}
%  (\frac{1}{2}\cdot a_x\cdot\Delta t^2) + (v_x\cdot\Delta t)$;\par
%$v_x \mathrel{\stackrel{_{~+}}{\leftarrow}} a_x\cdot\Delta t$;\par
%
\end{document}

答案1

我所知道的一切都是\mathchoice从上面 David Carlisle 的答案中学到的。他解释得非常好。所以这个答案并不是试图取代那个答案,而是要扩大它。他的关键短语激发了我的灵感,即“\mathchoice{a}{b}{c}{d}在 tex 中是无法区分的\hbox{a}\hbox{b}\hbox{c}\hbox{d}”,这让我明白要排版的宏必须与\mathchoice调用一起进行。

因为他的回答非常简洁,所以我花了一段时间才明白如何\mathchoice以更复杂的方式使用它。为此,我提供了\MS获取/保存当前数学样式并执行其参数的命令。该命令\SavedMathStyle可以在参数中用于在调用时调用数学样式。

该命令\MS可以嵌套(递归)方式使用,具体取决于是否希望在外部调用的参数中重置已保存的数学样式。此解决方案的关键特性是,在参数中,宏\SavedMathStyle将调用与该嵌套调用级别相关的数学样式。为了更加强调这一点,我创建了一个示例,其中我将材料放在数学模式下的框内,否则原始数学样式显然会丢失。

\documentclass{article}
\usepackage{graphicx}
\makeatletter
\def\@mstyleD{\displaystyle}
\def\@mstyleT{\textstyle}
\def\@mstyleS{\scriptstyle}
\def\@mstyles{\scriptscriptstyle}
%
\def\SavedMathStyle{\csname @mstyle\m@switch\endcsname}
%
\newcommand\MS[1]{\mathchoice%
  {\edef\m@switch{D}#1}%
  {\edef\m@switch{T}#1}%
  {\edef\m@switch{S}#1}%
  {\edef\m@switch{s}#1}%
}
%
% A SAMPLE COMMAND
\newcommand\mycmd[2]{\SavedMathStyle#2+\fbox{$\SavedMathStyle\frac{#1}{1+#2}$}}
%
\makeatother
\begin{document}

Inline \(\MS{\mycmd{x}{z}}\) test

displaystyle test\[\MS{\mycmd{x}{z}}\]

Recursive test (resetting mathstyle):\[\MS{\mycmd{\MS{\mycmd{x}{z}}}{y}}\]

Remaining examples keep original mathstyle throughout recursion.

Recursive test:\[\MS{\mycmd{\mycmd{x}{z}}{y}}\]

scriptsize test:\[x_{\MS{\mycmd{\mycmd{x}{z}}{y}}}\]

scriptscriptsize test:\[x_{y_{\MS{\mycmd{\mycmd{x}{z}}{y}}}}\]

Inline \(\MS{\mycmd{\mycmd{x}{z}}{y}}\) test

\end{document}

在此处输入图片描述

作为后续,我想解决 Peter Grill 的担忧。首先,我要说的是,我(截至今天)已在软件包的 V1.5 中采用了这种方法scalerel,因为使用mathstyle软件包会导致不兼容((非致命但有症状) amsmath 和 mathstyle 包的冲突)。在scalerel实现中,调用命令已被命名\ThisStyle,调用命令也已被命名\SavedStyle(因此,对于在这个问题的过程中命名法的改变,我深表歉意)。以下示例

\documentclass{article}
\usepackage{scalerel}
\begin{document}

\[
\ThisStyle{
  \frac{x}{y}\scriptstyle
  \ThisStyle{\left(
    \frac{y}{z}\SavedStyle\frac{y}{z}
  \right)}
  \SavedStyle\frac{p}{q}
}
\]

\end{document}

显示此结果

在此处输入图片描述

我们看到,外部调用\ThisStyle是在 中进行的\displaystyle,内部调用 是在 中进行的\scriptstyle。在内部调用中,\SavedStyle部署了\scriptstyle,而在外部调用中,部署了\displaystyle,甚至不同风格的嵌套调用。

答案2

\mathchoice行为在数学列表的末尾 当 TeX 通过将数学框放在正确的位置来制作水平列表时。因此,“选择”发生在您尝试使用长度之后。(它们被设置为一个组并保留为零,但您不能简单地进行全局分配,因为时间完全错误。)

查看\mathchoice(或其包装器)的任何用途\mathpalette) 的任何用途。通常的做法是,您需要将整个命令包括其所有参数,因此,为了简单起见,使用 fbox:

\def\fa#1{%
\mathchoice
  {\fbox{$\displaystyle#1$}}%
  {\fbox{$\textstyle#1$}}%
  {\fbox{$\scriptstyle#1$}}%
  {\fbox{$\scriptscriptstyle#1$}}}

可以工作,尽管通常可以通过定义一个辅助宏来简化操作,该宏将数学样式作为参数,例如在\smash数学模式中的 latex.ltx 中使用此形式,它是将(例如)作为附加参数\mathsm@sh的版本。因此,类似\smash\scriptstyle

\def\xfb#1#2{\fbox{$#1#2$}}

\def\fb{\mathpalette\xfb}

或者你可以让 AMS 来照顾你

\usepackage{amsmath}

\def\fc#1{\text{\fbox{$#1$}}}

相关内容