我正在尝试学习如何使用\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$}}}