我想自定义\thickhline
命令替代\hline
,以便控制表格横线粗细。以下代码是可行的:
\documentclass{article}
\newcommand \thickhline {
\noalign{\global\arrayrulewidth1.5bp}
\hline
\noalign{\global\arrayrulewidth0.5bp}
}
\begin{document}
\begin{tabular}{ll}
\thickhline
a & b \\
\hline
c & d \\
\thickhline
\end{tabular}
\end{document}
但是,一旦希望\thickhline
接收一个可选的长度参数
,例如
\newcommand \thickhline [1] [1.5bp] {
\noalign{\global\arrayrulewidth#1}
\hline
\noalign{\global\arrayrulewidth0.5bp}
}
就会报错了。
我尝试了用\NewExpandableDocumentCommand
定义以及用\@ifnextchar
预读[
两种方法,都不可行。应该这里面存在我不懂的宏展开问题。
我知道有很多表格宏包能做这件事情。我的问题是如何自定义具有一个可选参数的\thickhline
命令?或者有没有其他打包控制表格线粗细命令的方法?
在usrguide
中,如@u101077 老师所言,要使用\NewExpandableDocumentCommand
才可以在表格内正确展开,但与此同时又有如下限制:
无法将唯一的参数定义为O
型...
我不太懂展开,也不太懂是否有好的办法绕开这一限制,但OP又说:
我知道有很多表格宏包能做这件事情。我的问题是如何自定义具有一个可选参数的thickhline命令?或者有没有其他打包控制表格线粗细命令的方法?
因此我虽然发现booktabs
中的toprule
命令完全符合这一要求...但不确定OP是否“允许”站在前人的肩膀上,下面是直接偷Plain-TeX的方法,个人觉得这样的话,这个横线命令应该会比自己定义的更sound...
\documentclass{article}
\makeatletter
\newdimen\myheavyrulewidth
\myheavyrulewidth=1.5bp %<-default width here
\newdimen\belowrulesep
\newdimen\belowbottomsep
\newdimen\aboverulesep
\newdimen\abovetopsep
\newdimen\@aboverulesep
\newdimen\@belowrulesep
\newcount\@thisruleclass
\newcount\@lastruleclass
\@lastruleclass=0
\newdimen\@thisrulewidth
\def\futurenonspacelet#1{\def\@BTcs{#1}%
\afterassignment\@BTfnslone\let\nexttoken= }
\def\@BTfnslone{\expandafter\futurelet\@BTcs\@BTfnsltwo}
\def\@BTfnsltwo{\expandafter\ifx\@BTcs\@sptoken\let\next=\@BTfnslthree
\else\let\next=\nexttoken\fi \next}
\def\@BTfnslthree{\afterassignment\@BTfnslone\let\next= }
\def\Thickhline{\noalign{\ifnum0=`}\fi%<- modified from \toprule
\@aboverulesep=\abovetopsep
\global\@belowrulesep=\belowrulesep %global cos for use in the next noalign
\global\@thisruleclass=\@ne
\@ifnextchar[{\@BTrule}{\@BTrule[\myheavyrulewidth]}}%<- modified here
\def\@BTrule[#1]{%
\ifx\longtable\undefined
\let\@BTswitch\@BTnormal
\else\ifx\hline\LT@hline
\nobreak
\let\@BTswitch\@BLTrule
\else
\let\@BTswitch\@BTnormal
\fi\fi
\global\@thisrulewidth=#1\relax
% \ifnum\@thisruleclass=\tw@\vskip\@aboverulesep\else
% \ifnum\@lastruleclass=\z@\vskip\@aboverulesep\else
% \ifnum\@lastruleclass=\@ne\vskip\doublerulesep\fi\fi\fi
\@BTswitch}
\AtBeginDocument{%
\providecommand*\CT@arc@{}}%% colortbl support
\def\@BTnormal{%
{\CT@arc@\hrule\@height\@thisrulewidth}%
\futurenonspacelet\@tempa\@BTendrule}
\def\@BLTrule{\@ifnextchar({\@@BLTrule}{\@@BLTrule()}}
\def\@@BLTrule(#1){\@setrulekerning{#1}%
\global\@cmidlb\LT@cols
\ifnum0=`{\fi}%
\noalign{\ifnum0=`}\fi
\futurenonspacelet\@tempa\@BTendrule}
\def\@BTendrule{\ifx\@tempa\toprule\global\@lastruleclass=\@thisruleclass
\else\ifx\@tempa\midrule\global\@lastruleclass=\@thisruleclass
\else\ifx\@tempa\bottomrule\global\@lastruleclass=\@thisruleclass
\else\ifx\@tempa\cmidrule\global\@lastruleclass=\@thisruleclass
\else\ifx\@tempa\specialrule\global\@lastruleclass=\@thisruleclass
\else\ifx\@tempa\addlinespace\global\@lastruleclass=\@thisruleclass
\else\global\@lastruleclass=\z@\fi\fi\fi\fi\fi\fi
% \ifnum\@lastruleclass=\@ne\relax\else\vskip\@belowrulesep\fi
\ifnum0=`{\fi}}
\makeatother
\begin{document}
\begin{tabular}{ll}
\Thickhline
a & b \\
\hline
c & d \\
\Thickhline[1bp]
\end{tabular}
\end{document}
感觉抄的很不整洁(neat),上面应该还存在一些可以删的unused
命令...
请问 Plain TeX 的方法是从哪里找到的?
Plain TeX 的方法是我想要的,但它直接让我汗流浃背了。。
@u686 找到了,是 booktabs 的
@u686 我是抄的
booktabs
的源码...其实我还试过NewCommandCopy
把\midrule
进行复制,但似乎有点间距问题。顺便贴一下吧...好改,这些间距显然是\vskip
导致的,似乎一个个patch即可,但是个人感觉意义不大,于是没进一步改了...我如果有这种想自定义表格线的需求的话,我可能会更倾向于用做好的更专业设置过的宏包,毕竟
don't reinvent the wheel as possible
,比如texdoc booktabs
:除此之外,上面的源代码实现是有一些hacks的,例如:
\noalign{\ifnum0=`}\fi
可以解决一些垂直间距的小问题,而这是我这种plain-TeX newbees很难弄明白甚至很难发现的....找到了一个答案,我整理了一下:
@u686 David Carilse老师真是优雅,学习了,确实比我的neat很多!
\NewExpandableDocumentCommand\thickhline{}
+\@ifnextchar
也有点出乎我的意料hhh赞!
@u70550 好尴尬。。其实我不太懂什么时候用
\def
,什么时候用\newcommand
,什么时候用\NewDocumentCommand
。