我了解到\parbox
有五個參數,即:\parbox[<align>][<height>][<inner-align>]{<width>}{<text>}
。所以我建立了自己的 \myparbox,在\sloppy\setlength\parfillskip{0pt}
#5 之前添加了它。但它失敗了。原因是什麼以及如何重新定義\myparbox?
微量元素:
\documentclass{article}
\usepackage{xparse}
\NewDocumentCommand{\myparbox}{ooomm}{%
\parbox[#1][#2][#3]{#4}{\sloppy\setlength\parfillskip{0pt}#5}
}
\begin{document}
AAA\fbox{\parbox[][][]{4em}{aa bb cc dd ee ff}}AAA\\% parbox typesets nothing. why?
BBB\fbox{\myparbox{4em}{aa bb cc dd ee ff}}BBB% This fails to compile
\end{document}
編輯:
\documentclass{article}
\usepackage{xparse}
\let\oldparbox\parbox
\RenewDocumentCommand{\parbox}{sO{c}oO{t}mm}{%
\IfBooleanTF{#1}
{%
\IfNoValueTF{#3}
{\oldparbox[#2]{#5}{\sloppy\setlength\parfillskip{0pt}#6}}
{\oldparbox[#2][#3][#4]{#5}{\sloppy\setlength\parfillskip{0pt}#6}}
}
{%
\IfNoValueTF{#3}
{\oldparbox[#2]{#5}{#6}}
{\oldparbox[#2][#3][#4]{#5}{#6}}
}
}
\begin{document}\the\fboxsep
AAA\fbox{\parbox[t]{8em}{aa bb cc dd ee ff gg hh ii}}AAA\\% parbox typesets nothing why?.
BBB\fbox{\parbox*{6em}{aa bb cc dd ee ff}}BBB% This fails to compile
\end{document}
答案1
如註釋中所指出的,空的可選參數[]
不必等同於根本不給予可選參數。不給出參數是否等同於傳遞特定值必須透過命令的文檔或實作進行檢查。
在範例中,情況會變得更糟,因為如果未給出相應的可選參數,則xparse
的可選o
參數實際上包含特殊的標記值。-NoValue-
您可以並且應該測試某個值是否存在\IfNoValueTF
(如達萊夫的評論)。
當您只有一個可選參數需要處理時,這是一個非常可行的解決方案,但如果參數數量增加,它就會變得混亂。
如果您可以在 中尋找定義時\parbox
發現預設參數是c
,\relax
作為特殊標記。s
sourc2e.pdf
所以你可以嘗試
\documentclass{article}
\usepackage{xparse}
\NewDocumentCommand{\myparbox}{O{c}O{\relax}O{s}mm}{%
\parbox[#1][#2][#3]{#4}{\sloppy\setlength\parfillskip{0pt}#5}%
}
\begin{document}
BBB\fbox{\parbox{4em}{\sloppy\setlength\parfillskip{0pt}aa bb cc dd ee ff}}BBB
BBB\fbox{\myparbox{4em}{aa bb cc dd ee ff}}BBB
\end{document}
通常,我會嘗試解決這樣的問題,這些問題需要我知道預設的可選參數值/行為,或者需要大量\IfNoValueTF
測試才能獲得正確的參數,因為第一個方法似乎很脆弱,而第二個方法非常冗長和重複。類似的方法馬金的回答可能是一種替代方案,但至少在這種情況下還需要深入了解 的定義\parbox
。
編輯: 我剛剛看到這個問題的新版本。\let
對於具有可選參數的健全命令來說是不夠的:何時使用 \LetLtxMacro?。我還強烈建議不要重新定義基本命令,例如\parbox
即使實現可能向後相容。新名字更安全。
答案2
或者,您可以xpatch
在命令中的正確位置插入額外的程式碼,而無需傳遞變數。該\parbox
命令呼叫處理實際內容的內部\@iiiparbox
命令,因此該內部命令是應該修補的命令。微量元素:
\documentclass{article}
\usepackage{xpatch}
\begin{document}
\makeatletter
\xpatchcmd{\@iiiparbox}{#5}{\sloppy\setlength\parfillskip{0pt}#5}{}{}
\makeatother
AAA\fbox{\parbox{4em}{aa bb cc dd ee ff}}AAA
\end{document}
請注意,這會更改所有 parbox 的行為。如果您想要一個具有合理對齊方式的自訂命令並保留常規命令,那麼您可以使用該命令的副本定義自訂命令\@iiiparbox
並修補該副本而不是原始命令。微量元素:
\documentclass{article}
\usepackage{xpatch}
\begin{document}
\makeatletter
\def\myparbox{\@ifnextchar [\@iparbox {\myiiiparbox c\relax [s]}}
\let\myiiiparbox\@iiiparbox
\xpatchcmd{\myiiiparbox}{#5}{\sloppy\setlength\parfillskip{0pt}#5}{}{}
\makeatother
AAA\fbox{\parbox{4em}{aa bb cc dd ee ff}}AAA
BBB\fbox{\myparbox{4em}{aa bb cc dd ee ff}}BBB
\end{document}
結果:
答案3
的可選參數\parbox
必須包含特定標記(如果存在)。第一個的預設值為c
,因此我們可以對可選參數是否存在進行一些檢查。需要從最後一項開始。
第一個可選參數應該是c
(預設),t
或b
;第二個應該是長度;最後一個應該是c
, t
,b
或s
(如果未給出,則使用第一個)。
請注意,最後一個參數應該\myparbox
用 表示+m
,以便能夠輸入不同的段落。使用巨集\deliverparbox
是為了最大限度地減少程式碼重複。
\documentclass{article}
\usepackage{xparse}
\NewDocumentCommand{\myparbox}{O{c}oom+m}{%
\IfNoValueTF{#3}
{%
\IfNoValueTF{#2}
{%
\parbox[#1]{#4}{\deliverparbox{#5}}%
}%
{%
\parbox[#1][#2]{#4}{\deliverparbox{#5}}%
}%
}%
{%
\parbox[#1][#2][#3]{#4}{\deliverparbox{#5}}%
}
}
\NewDocumentCommand{\deliverparbox}{+m}{%
\sloppy\setlength\parfillskip{0pt}#1%
}
\begin{document}
AAA\fbox{\parbox{4em}{aa bb cc dd ee ff}}AAA
BBB\fbox{\myparbox{4em}{aa bb cc dd ee ff}}BBB
BBB\fbox{\myparbox[t][12ex][s]{4em}{aa bb cc dd ee ff\par\vfil aa bb}}BBB
\end{document}