我用 制作了下表,tabularx
并期望第二行中的所有单元格都具有相同的宽度,因为它们都使用了multicolumn{2}
。但事实并非如此。相反,第三和第六个单元格的宽度是其他单元格宽度的两倍。
第 3 行至第 6 行存在类似的问题。每行上的第一个和第四个单元格只有其应有宽度的一半(考虑到它使用了)multicolumn{4}
,而其他单元格的宽度则是预期宽度的两倍。
我是不是做错了什么,或者tabularx
它的行为和我想的不一样?我以为X
列的宽度与用 定义的列数有关\multicolumn{n}
。例如,如果整个表格有 12 列,我指定\multicolumn{2}
列宽为整个表格的六分之一。但显然情况并非如此,或者说它只适用于第一行……
\documentclass{article}
\usepackage{tabularx}
\usepackage{booktabs}
\begin{document}
\begin{table}[h]
\begin{tabularx}{\textwidth}{*{12}{X|}}
\hline
\multicolumn{6}{|X|}{6 cols} & \multicolumn{6}{|X|}{6 cols} \\
\hline
\multicolumn{2}{|X|}{2 cols} & \multicolumn{2}{X|}{2 cols} & \multicolumn{2}{X|}{2 cols} & \multicolumn{2}{|X|}{2 cols} & \multicolumn{2}{X|}{2 cols} & \multicolumn{2}{X|}{2 cols}\\
\hline
\multicolumn{4}{|X|}{4 cols} & & & \multicolumn{4}{|X|}{4 cols} & & \\
\hline
\multicolumn{4}{|X|}{4 cols} & & & \multicolumn{4}{|X|}{4 cols} & & \\
\hline
\multicolumn{4}{|X|}{4 cols} & & & \multicolumn{4}{|X|}{4 cols} & & \\
\hline
\multicolumn{4}{|X|}{4 cols} & & & \multicolumn{4}{|X|}{4 cols} & & \\
\hline
\end{tabularx}
\end{table}
\end{document}
答案1
你问,
难道我做错了什么?
简短回答:是的。
稍微长一点的答案:您的tabularx
环境包含太多相互冲突的信息;结果就是一团糟,无法产生“正确”的列宽。在某些情况下,事情看起来似乎很顺利,这完全是运气好。然而,这只是巧合。结果呢?您需要停止提供这些相互冲突的指令。
让我们把整体分解tabularx
成更小的部分。让我们从一个看起来很简单的案例开始:
\begin{tabularx}{\textwidth}{|*{12}{X|}}
\hline
\multicolumn{6}{|X|}{6 cols} &
\multicolumn{6}{ X|}{6 cols} \\
\hline
\end{tabularx}
这看上去没什么问题,不是吗?但是,一如既往,外表是会骗人的。潜伏在表面之下的麻烦的根源是滥用符号:列类型X
被迫承担双重职责。首先,由于应该有 12 个等宽列,因此每列的默认可用宽度等于\textwidth/12-2\tabcolsep-(13/12)\arrayrulewidth
。(旁注:$13/12 \approx 1.08333$
。)但在 中\multicolumn{6}{X|}{6 cols}
,单元格的宽度实际上是大 6 倍。[我会让软件包的设计者tabularx
解释为什么这种符号滥用被允许滑动并且不会引发错误...]幸运的是——我必须强调,这纯属巧合——结果还不错,即 LaTeX 能够正确计算出组合列的宽度。这是因为
\begin{tabularx}{\textwidth}{| *{12}{X|} }
\hline
\multicolumn{6}{|X|}{6 cols} &
\multicolumn{6}{ X|}{6 cols} \\
\hline
\end{tabularx}
可以简化为
\begin{tabularx}{\textwidth}{| X | X |}
\hline
1 col & 1 col \\
\hline
\end{tabularx}
不再存在符号滥用的问题。换句话说,LaTeX 通过丢弃第一个tabularx
环境中内置的冗余来解决这个难题。
让我们考虑一个稍微有趣的案例:
\begin{tabularx}{\textwidth}{| *{12}{X|} }
\hline
\multicolumn{6}{|X|}{6 cols} &
\multicolumn{6}{ X|}{6 cols} \\
\hline
\multicolumn{2}{|X|}{2 cols} &
\multicolumn{2}{ X|}{2 cols} &
\multicolumn{2}{ X|}{2 cols} &
\multicolumn{2}{ X|}{2 cols} &
\multicolumn{2}{ X|}{2 cols} &
\multicolumn{2}{ X|}{2 cols} \\
\hline
\end{tabularx}
观察一下,符号的滥用导致X
-type 列的宽度可能有三个 [3!] 个不同的值。但片刻的思考表明,这必须与
\begin{tabularx}{\textwidth}{|*{6}{X|}}
\hline
\multicolumn{3}{|X|}{3 cols} &
\multicolumn{3}{ X|}{3 cols} \\
\hline
1 col & 1 col & 1 col & 1 col & 1 col & 1 col \\
\hline
\end{tabularx}
再次重申,这不会产生歧义。关键在于,实际上没有 12 个独立列,只有 6 个,而 LaTeX 现在拥有足够的信息来在 类型列宽度的两个可能值之间来回切换X
。换句话说,更简单的问题没有致命的歧义。
最后,让我们讨论一下无法明确消除冗余的情况。
\begin{tabularx}{\textwidth}{| *{12}{X|} }
\hline
\multicolumn{6}{|X|}{6 cols} &
\multicolumn{6}{ X|}{6 cols} \\
\hline
\multicolumn{4}{|X|}{4 cols (?!)} & a & b &
\multicolumn{4}{ X|}{4 cols (?!)} & c & d \\
\hline
\end{tabularx}
LaTeX 已获得足够的信息来推断出第 2 行前三个单元格的总宽度必须等于第 1 行第一个单元格的宽度。但是,剩下的信息不足以让 LaTeX 推断出第 2 行第一个单元格的宽度必须等于4次该行中单元格 2 和 3 的宽度。但结果却是第 2 行中三个单元格的宽度相等。哎哟。
为了解决这个问题,真正需要的是这样的:
\newlength\mylen
\setlength\mylen{\textwidth/12-2\tabcolsep-1.08333\arrayrulewidth}
\begin{tabularx}{\textwidth}{| *{2}{*{4}{X|} *{2}{wl{\mylen}|}} }
\hline
\multicolumn{6}{|X|}{6 cols} &
\multicolumn{6}{ X|}{6 cols} \\
\hline
\multicolumn{4}{|X|}{4 cols} & a & b &
\multicolumn{4}{ X|}{4 cols} & c & d \\
\hline
\end{tabularx}
其结果如下:
其之所以“如预期般工作”,是因为我们现在已经给了 LaTeX 足够的信息,让它推断出 给出的单元格宽度\multicolumn{4}{|X|}{4 cols}
必须是 给定单元格宽度的三分之二(而不是三分之一)\multicolumn{6}{|X|}{6 cols}
。
tabularx
这个故事的寓意是什么?如果你没有提供足够有用的信息,那么它将无法正确解决列宽分配问题,请不要感到惊讶。
为了完整起见,这里列出了tabularx
上面提到的所有六种环境:
\documentclass{article}
\usepackage{tabularx,calc}
% code needed for the final 'tabularx' example:
\newlength\mylen
\setlength\mylen{\textwidth/12-2\tabcolsep-1.08333\arrayrulewidth}
\setlength\parindent{0pt} % just for this example
\begin{document}
\begin{tabularx}{\textwidth}{|*{12}{X|}}
\hline
\multicolumn{6}{|X|}{6 cols} &
\multicolumn{6}{ X|}{6 cols} \\
\hline
\end{tabularx}
\smallskip
\begin{tabularx}{\textwidth}{|X|X|}
\hline
1 col & 1 col \\
\hline
\end{tabularx}
\bigskip
\begin{tabularx}{\textwidth}{*{12}{X|}}
\hline
\multicolumn{6}{|X|}{6 cols} &
\multicolumn{6}{ X|}{6 cols} \\
\hline
\multicolumn{2}{|X|}{2 cols} &
\multicolumn{2}{ X|}{2 cols} &
\multicolumn{2}{ X|}{2 cols} &
\multicolumn{2}{ X|}{2 cols} &
\multicolumn{2}{ X|}{2 cols} &
\multicolumn{2}{ X|}{2 cols} \\
\hline
\end{tabularx}
\smallskip
\begin{tabularx}{\textwidth}{|*{6}{X|}}
\hline
\multicolumn{3}{|X|}{3 cols} &
\multicolumn{3}{ X|}{3 cols} \\
\hline
1 col & 1 col & 1 col & 1 col & 1 col & 1 col \\
\hline
\end{tabularx}
\bigskip
\begin{tabularx}{\textwidth}{|*{12}{X|}}
\hline
\multicolumn{6}{|X|}{6 cols} &
\multicolumn{6}{ X|}{6 cols} \\
\hline
\multicolumn{4}{|X|}{4 cols (?!)} & a & b &
\multicolumn{4}{ X|}{4 cols (?!)} & c & d \\
\hline
\end{tabularx}
\smallskip
\begin{tabularx}{\textwidth}{| *{2}{*{4}{X|} *{2}{wl{\mylen}|}} }
\hline
\multicolumn{6}{|X|}{6 cols} &
\multicolumn{6}{ X|}{6 cols} \\
\hline
\multicolumn{4}{|X|}{4 cols} & a & b &
\multicolumn{4}{ X|}{4 cols} & c & d \\
\hline
\end{tabularx}
\end{document}
答案2
列X
的p
宽度由整个表格决定,
因此,如果前两列是|X|X|
(|
您的示例中缺少第一列),那么
\multicolumn{2}{|X|}{...}
将跨越列,但...
将被强制进入由其确定的宽度的 parbox,该X
宽度小于所需宽度的一半。
您可以使用\multicolumn{2}{|l|}{...}
,因此宽度是自动的,或者如果您需要换行,
\multicolumn{2}{|>{\hsize=\dimexpr2\hsize+2\tabcolsep+\arrayrulewidth}X|}{...}
那么p
列就是两列的宽度X
和跨越的填充和规则。
答案3
我决定自己回答这个问题,因为我无法使用提供的答案修复表格。无论如何,感谢@mico 和@david-carlisle。
总结:我放弃向 LaTeX 解释如何确定正确的列宽,而是手动完成。以下代码生成了我想要的表格:
\begin{tabular}{*{12}{l}}
\hline
\multicolumn{6}{|p{\dimexpr(\textwidth-3\arrayrulewidth-4\tabcolsep)/2\relax}|}{
6 col
} & \multicolumn{6}{p{\dimexpr(\textwidth-3\arrayrulewidth-4\tabcolsep)/2\relax}|}{
6col
} \\
\hline
\multicolumn{2}{|p{\dimexpr(\textwidth-7\arrayrulewidth-12\tabcolsep)/6\relax}|}{
2 col
} &
\multicolumn{2}{p{\dimexpr(\textwidth-7\arrayrulewidth-12\tabcolsep)/6\relax}|}{
2 col
} &
\multicolumn{2}{p{\dimexpr(\textwidth-7\arrayrulewidth-12\tabcolsep)/6\relax}|}{
2 col
} &
\multicolumn{2}{p{\dimexpr(\textwidth-7\arrayrulewidth-12\tabcolsep)/6\relax}|}{
2 col
} &
\multicolumn{2}{p{\dimexpr(\textwidth-7\arrayrulewidth-12\tabcolsep)/6\relax}|}{
2 col
} &
\multicolumn{2}{p{\dimexpr(\textwidth-7\arrayrulewidth-12\tabcolsep)/6\relax}|}{
2 col
} \\
\hline
\multicolumn{4}{|p{\dimexpr(\textwidth-7\arrayrulewidth-12\tabcolsep)/3\relax}|}{
4 col
} &
\multicolumn{1}{p{\dimexpr(\textwidth-13\arrayrulewidth-24\tabcolsep)/12\relax}|}{
1 col
} &
\multicolumn{1}{p{\dimexpr(\textwidth-13\arrayrulewidth-24\tabcolsep)/12\relax}|}{
1 col
}&
\multicolumn{4}{p{\dimexpr(\textwidth-7\arrayrulewidth-12\tabcolsep)/3\relax}|}{
4 col
} &
\multicolumn{1}{p{\dimexpr(\textwidth-7\arrayrulewidth-24\tabcolsep)/12\relax}|}{
1 col
} &
\multicolumn{1}{p{\dimexpr(\textwidth-13\arrayrulewidth-24\tabcolsep)/12\relax}|}{
1 col
} \\
\hline
\end{tabular}
长版本:我尝试使用@Mico 的示例修复我的表格,但失败了。例如以下代码:
\documentclass{article}
\usepackage{tabularx,calc}
\begin{document}
\newlength\mylen
\setlength\mylen{\textwidth/12-2\tabcolsep-1.08333\arrayrulewidth}
\begin{tabularx}{\textwidth}{| *{2}{*{4}{X|} *{2}{wl{\mylen}|}} }
\hline
\multicolumn{6}{|X|}{6 cols} &
\multicolumn{6}{ X|}{6 cols} \\
\hline
\multicolumn{4}{|X|}{4 cols} & a & b &
\multicolumn{4}{ X|}{4 cols} & c & d \\
\hline
\end{tabularx}
\end{document}
在本地和https://www.papeeria.com。我没有意识到 papeeria.com 上的默认 LaTeX 版本太旧了(2015 年的!)无法正确编译该代码。在本地,使用新文档时代码可以正确呈现,但将其粘贴到现有文档中时则不行。我没有调试这个,因为当我意识到这一点时,我已经有了自己的解决方案。
更新:我找到了一个更优雅(并且更短)的解决方案,使用tabularray
:
\documentclass{article}
\usepackage{tabularray}
\begin{document}
\begin{table}
\begin{tblr}{
width=\textwidth,
colspec={|X|X|X|X|X|X|X|X|X|X|X|X|},
hline{1-Z} = {1-Z}{solid},
vline{1-Z} = {1-Z}{solid},
cells = {l},
cell{1}{1,7} = {c=6}{l},
cell{2}{1,3,5,7,9,11} = {c=2}{l},
cell{3-6}{1,7} = {c=4}{l},
}
6 cols & & & & & & 6 cols & & & & & \\
2 cols & & 2 cols & & 2 cols & & 2 cols & & 2 cols & & 2cols & \\
4 cols & & & & 1 col & 1 col & 4 cols & & & & 1col & 1col \\
\end{tblr}
\end{table}
\end{document}
这也得到了我想要的表格。