我把问题归结为更简单的 MWE。请参阅下面的更新。
我尝试自定义表格环境,以便在整个论文中轻松使用连贯的风格。我希望表格环境能够
- 在表格主体的每一行后自动添加
\addlinespace
(最后一行除外) - 自动交替显示行颜色 - 不是针对单行,而是针对多行(大多数情况下是 3 行,在 stackexchange 的其他地方也有人推荐这样做
我知道有\arraystretch
,但这也会影响标题,因此如果两种类型的表格彼此靠近使用,看起来会很别扭。我也知道\rowcolors
有该命令,但它不允许对行组进行着色(据我所知)。
我在自定义环境中进行了所有这些修改,我可以使用命令选择其中一项(或两项)修改。这两个选项都有效,但不幸的是,行颜色对下一个表格环境,即不是我修改的环境。
我准备了一个最小的工作示例:
\documentclass[a4paper,11pt]{book}
\usepackage[T1]{fontenc}
\usepackage[english]{babel}
\usepackage{booktabs}
\usepackage[table]{xcolor}
\usepackage{ifthen}
\usepackage{calc}
\input{tables}
\begin{document}
\begin{stable}
\srowgroupcolors{2}{white}{orange}
\begin{tabular}{ccc}
\toprule
a & b & c\\
\midrule
0 & 0 & 0 \\
0 & 1 & 1 \\
1 & 0 & 1 \\
1 & 1 & 0 \\
\bottomrule
\end{tabular}
\end{stable}
\begin{stable}
\begin{tabular}{ccc}
\toprule
a & b & c\\
\midrule
0 & 0 & 0 \\
0 & 1 & 1 \\
1 & 0 & 1 \\
1 & 1 & 0 \\
\bottomrule
\end{tabular}
\end{stable}
\begin{stable}
\begin{tabular}{ccc}
\toprule
a & b & c\\
\midrule
0 & 0 & 0 \\
0 & 1 & 1 \\
1 & 0 & 1 \\
1 & 1 & 0 \\
\bottomrule
\end{tabular}
\end{stable}
\end{document}
第一个表中的命令\srowgroupscolors{2}{white}{orange}
激活了行着色。第二个表在第一行的第一列(\toprule 之后)中显示了问题。第三个表按预期工作。请注意,即使使用第二个表格环境而没有周围的稳定环境,问题仍然存在。
结果如下所示(对于稳定环境中的第二个表):
稳定的代码定义在tables.tex
下面的文件中。我删除了用于自动行距的部分,因为它不会引起任何问题。它仍然相当长(尽管它包含的注释比代码多)。
它的作用如下:它计算表格行数,但仅限于正文,即\midrule
使用后。在标题中,计数器保持为零。对于每个正文行,\stable@color@step
由覆盖的命令调用\@arraycr
。(请注意,stable@color@step
在中定义\srowgroupcolors
,否则为空。)它调用\stable@calc@rowcolor
(在\noalign
命令中)根据颜色计算颜色下一个 行并将相应\rowcolor
命令存储在 中\stable@rowcolor
。后者在\noalign
命令之后直接调用。因此\rowcolor
下一行的命令在 之后立即发出\\
。
\makeatletter
% counter for the line number (modulo 2 * group@size)
\newcounter{stable@counter}
% size of groups (row coloring)
\newcounter{stable@group@size}
% modulo value, used to get the right color
\newcounter{stable@modulo}
% whether array / tabular have already been patched
\newboolean{stable@patched}
% replacement for table
% arguments:
% #1 - placement - default is !htb
\newenvironment{stable}[1][!htb]{%
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% internal commands for auto spacing and coloring of rows
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% set the group size and calculate the modulo
\newcommand*{\stable@set@group@size}[1]{%
\setcounter{stable@group@size}{##1}%
\setcounter{stable@modulo}{2*\value{stable@group@size}}%
}%
%
% calculate the rowcolor based on the row number
% step the rownumber (module 2 * group size) if > 0 (body)
% TODO refactor: extract a step method
\newcommand{\stable@calc@rowcolor}{%
\ifthenelse{\value{stable@counter}=0}%
% we're still in the header
{\gdef\stable@rowcolor{}}%
% we're in the body
{%
% 1 - group size: color 1, above group size: color 2
\ifthenelse{\value{stable@counter}>\value{stable@group@size}}%
{\gdef\stable@rowcolor{\rowcolor{stable@color2}}}%
{\gdef\stable@rowcolor{\rowcolor{stable@color1}}}%
% increase counter -> number of the NEXT row
\stepcounter{stable@counter}%
% modulo operation
\ifthenelse{\value{stable@counter}>\value{stable@modulo}}%
% reset to 1 (sic!), as 0 would be header
{\setcounter{stable@counter}{1}}%
{}%
}%
}%
%
% shortcut: call stable@calc@color in a \noalign, use the calculated color
% the default implementation does nothing, the command has to be changed
\def\stable@color@step{}
%
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% modify the array / tabular package
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% backup the original array / tabular commands
\newcommand{\stable@arraycr}{}%
\let\stable@arraycr\@arraycr%
\newcommand{\stable@midrule}{}%
\let\stable@midrule\midrule%
%
% patch the array / tabular commands
% lazy patching makes sure this does not break anything
\newcommand*{\stable@patch@array}{%
\ifthenelse{\boolean{stable@patched}}%
% already patched, do nothing
{}%
{%
\setboolean{stable@patched}{true}%
% replace the \\ command (@arraycr): integrate coloring and spacing
\renewcommand{\@arraycr}{%
\stable@arraycr%
\stable@color@step%
}%
%
% replace \midrule: start coloring and spacing
\renewcommand{\midrule}{%
\stable@midrule%
% set counter to 1 (end of heading}
\noalign{%
\setcounter{stable@counter}{1}%
}%
% start coloring (1st row)
\stable@color@step%
}%
}%
}%
%
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% external commands for tables
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% alternating colored groups of rows
% arguments:
% #1 - group size
% #2 - first color (tables always start with this color)
% #3 - second color
\newcommand{\srowgroupcolors}[3]{%
% shortcut: call stable@calc@color in a \noalign, use the calculated color
\def\stable@color@step{\noalign{\stable@calc@rowcolor}\stable@rowcolor}%
% store the settings
\stable@set@group@size{##1}%
\colorlet{stable@color1}{##2}%
\colorlet{stable@color2}{##3}%
% patch the array commands
\stable@patch@array
}%
%
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% configuration / defaults
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% prepare row counter
% (count rows modulo (2 * colored group size), value 0 means: header)
\setcounter{stable@counter}{0}%
% initialize with default values
\stable@set@group@size{1}%
% array / tabular commands have not yet been patched
\setboolean{stable@patched}{false}%
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% start of the actual table
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% use small sized sans serif font
\begin{table}[#1]%
}{%
\end{table}%
}%
\makeatother
尽管一切都是在稳定组中完成的,但我的代码一定是设法破坏了表格中的某些内容。唯一的例外是在用于临时存储(如果需要)的\gdef
中使用。我使用了这种解决方法(取自\stable@calc@rowcolor
\addlinespace
这个问题) 以避免!Misplaced \noalign
错误。
有人知道这些问题的根源是什么吗?
更新
以下代码会触发同样的问题 - 这正是我的表格扩展所做的:
\documentclass[a4paper,11pt]{book}
\usepackage[T1]{fontenc}
\usepackage[english]{babel}
\usepackage{booktabs}
\usepackage[table]{xcolor}
\begin{document}
\begin{table}
\begin{tabular}{ccc}
\toprule
a & b & c\\
\midrule
\rowcolor{white} 0 & 0 & 0 \\
\rowcolor{white} 0 & 1 & 1 \\
\rowcolor{orange} 1 & 0 & 1 \\
\rowcolor{orange} 1 & 1 & 0 \\
\rowcolor{orange} \bottomrule
\end{tabular}
\end{table}
\begin{table}
\begin{tabular}{ccc}
\toprule
a & b & c\\
\midrule
0 & 0 & 0 \\
0 & 1 & 1 \\
1 & 0 & 1 \\
1 & 1 & 0 \\
\bottomrule
\end{tabular}
\end{table}
\begin{table}
\begin{tabular}{ccc}
\toprule
a & b & c\\
\midrule
0 & 0 & 0 \\
0 & 1 & 1 \\
1 & 0 & 1 \\
1 & 1 & 0 \\
\bottomrule
\end{tabular}
\end{table}
\end{document}
这是通过\rowcolor
在 之后直接添加命令\\
(使用\everycr
或通过覆盖\@arraycr
)来触发的。此时不清楚是否还有另一行。出于某种原因,\rowcolor
如果最后一行是 a\bottomrule
或 a ,则表格环境不喜欢最后一行中的 a \hline
。
有办法解决这个问题吗? tabular 是否在行首提供了一个钩子,我可以使用它来代替? 是否可以检查某一行是否不包含\bottomrule
?
或者有没有办法“撤消”\rowcolor
覆盖的命令\bottomrule
?实际上,这就是我为使间距部分(示例中未显示)正常工作所做的工作。
更新 2
我进一步调查了这个问题。归根结底是 colortbl 中的一个问题。当\rowcolor
使用 而后面没有 时\\
,下一个表格会显示错误。我发现的最简单的例子如下:
\documentclass{article}
\usepackage[english]{babel}
\usepackage{colortbl}
\begin{document}
\begin{tabular}{c}
a \\
\rowcolor{orange}
\end{tabular}
\begin{tabular}{c}
a \\
\end{tabular}
\end{document}
结果如下:
在我看来,这似乎是 colortbl 中的一个错误。即使这个“尾随”\rowcolor
完全没有意义,它也不应该对下一个表格产生影响。
我尝试查看如何\rowcolors
解决该问题 - 它似乎没有生成这样的“尾随”rowcolor
命令,但我不完全了解其来源。
我的解决方法是在保存框中创建下一个表格,然后将其丢弃。保存框之后创建的表格不会显示该问题。
\documentclass{article}
\usepackage[english]{babel}
\usepackage{colortbl}
\begin{document}
\begin{tabular}{c}
a \\
\rowcolor{orange}
\end{tabular}
\newsavebox{\bin}
\savebox{\bin}{\tabular{c}\\\endtabular}
\begin{tabular}{c}
a \\
\end{tabular}
\end{document}
无论如何,如果有更好的方法可以修复我的扩展,我会很乐意使用它,而不是这个丑陋的解决方法。
答案1
似乎没有任何用例需要\rowcolor
在所有的行之后添加,但是如果这样做了,您可以在表之后清除其设置:
\documentclass{article}
\usepackage[english]{babel}
\usepackage{colortbl}
\begin{document}
\begin{tabular}{c}
a \\
\rowcolor{orange}
\end{tabular}
\makeatletter\global\let\CT@do@color\relax\makeatother
\begin{tabular}{c}
a \\
\end{tabular}
\end{document}