我正在尝试排版嵌套表格,如下所示:
\documentclass{article}
\usepackage{bigstrut}
\usepackage{multirow}
\begin{document}
\begin{tabular}{|lll|}
\hline
A & \multirow{2}{*}{
\begin{minipage}{3cm}
\begin{tabular}{|l|l|}
\hline
A & \hfill 1\textsuperscript{st}\bigstrut[t] \\
\hline
A & A \\
\hline
\end{tabular}
\end{minipage}
} & A \\
A & {} & A \\
A & A & A \\
\hline
\end{tabular}
\end{document}
这会导致坏盒:Overfull \vbox (3.19998pt too high) detected at line 19
我已经尝试了一段时间来检测这个坏框的确切来源(部分原因是\bigstrut
),但我不知道如何删除此警告。我尝试了各种修复方法\\[3.5pt]
,但我不知道出了什么问题以及如何解决这个问题。可能以完全不同的方式排版表格是“最佳”方法,但目前我对坏框的来源以及如何摆脱它感兴趣。
注意:在这个最小化的例子中,底部中间的 A 与嵌套表重叠,但即使我\\[1cm]
对倒数第二行做了类似的事情,坏的(过满)\vbox
消息仍然存在(顺便说一下相同的点大小指示)。
编辑
这是一个替代的 MWE,它创建类似的溢出错误,而无需读取嵌套tabular
环境:
\documentclass{article}
\usepackage{xcolor}
\usepackage{multirow}
\setlength{\parindent}{0pt}
\newcommand{\vstrut}[3][blue]{{\color{#1}\rule[-#2]{0.4pt}{#3}}}
\newcommand{\hstrut}[2][blue]{{\color{#1}\makebox[0pt][l]{\rule[-0.4pt]{#2}{0.4pt}}}}
\begin{document}
\begin{tabular}{|lll|}
\hline
A\vstrut{0ex}{5ex} & \multirow{2}{3cm}{%
\begin{minipage}[t]{3cm}
Trial \vstrut[red]{18pt}{18pt} text
\end{minipage}}
& A \\
A\vstrut{3ex}{3ex}\hstrut{1.65in} & {} & A \\
A & A & A \\
\hline
\end{tabular}
\end{document}
答案1
TeX 是正确的:应该有溢出框(高出 3.2pt):您试图放入两个外部表格行高度的嵌入表格太高了。是什么让它太高了?首先,您\bigstrut[t]
在嵌入表。这使其高出 2pt。其次,您使用了三个\hlines
,每个都\arrayrulewidth=0.4pt
很高:这占剩余的 1.2pt。
测试:如果删除bigstrut[t]
和,内表将完全适合:\hline
\documentclass{article}
\usepackage{bigstrut}
\usepackage{multirow}
\begin{document}
\begin{tabular}{|lll|}
\hline
A & \multirow{2}{*}{
\begin{tabular}{|l|l|}%|
%\hline
A & \hfill 1\textsuperscript{st}%
%\bigstrut[t]
\\
%\hline
A & A \\
%\hline
\end{tabular}
} & A\\
A & {} & A\\
A & A & A \\
\hline
\end{tabular}
\end{document}
解决这个问题的方法只有一种:在外表中留出更多空间。考虑到您可能希望内表和外表的行对齐,我建议使用并行。每当您\bigstrut
在内表中使用时,也要在外表的同一行中使用它。
但是有一个问题。每当您将外部表格的一行设置为高于正常值时,您都需要告知multirow
它,以免出现溢出框。为此,multirow 提供了可选参数bigstruts
,用于增加多行单元格的高度bigstruts * \bigstrutjot
。因此(我稍微清理了一下 MWE),\bigstrut
内部表格中有一个(仅)的示例,因此\bigstrut
外部表格中有一个加上可选参数[1]
。
\documentclass{article}
\usepackage{bigstrut}
\usepackage{multirow}
\usepackage{xcolor}
\begin{document}
\begin{tabular}{|lll|}
\hline
A & \multirow{2}[1]{*}{\color{red}%
\begin{tabular}{|l|l|}%|
A & A\bigstrut[t] \\
A & A\\
\end{tabular}} & A\bigstrut[t] \\
A & {} & A \\
A & A & A \\
\hline
\end{tabular}
\end{document}
接下来,\hline
在嵌入式表中。首先,平行性:我们还必须在外部表中留出额外的垂直空间。我建议使用适当深度的支柱。
\def\hlinestrut{\rule[\dimexpr-\dp\strutbox-\arrayrulewidth]{\dimexpr\dp\strutbox+\arrayrulewidth}{0pt}}
但是,这还不够:同样,我们还必须告诉 multirow 行比正常行高。但是,我们面临一个问题。增加多行单元格高度的唯一方法是使用可选参数bigstruts
,该参数仅接受整数值,但 a 的高度\hline
不是 的整数倍\bigstrutjot
。默认情况下,\arrayrulewidth
是 的五分之一\bigstrutjot
。除了修补 multirow 以接受浮点数作为参数外,我看不出还有其他方法bigstruts
。幸运的是,这很容易,我们要做的就是更改这一点:
%\ifnum#2>0 \advance\@tempdima\bigstrutjot \fi
\ifdim#2pt>0pt \advance\@tempdima\bigstrutjot \fi
现在完整的例子:
\documentclass{article}
\usepackage{bigstrut}
\usepackage{multirow}
\usepackage{xcolor}
\def\hlinestrut{\rule[\dimexpr-\dp\strutbox-\arrayrulewidth]{\dimexpr\dp\strutbox+\arrayrulewidth}{0pt}}
\makeatletter
\def\@xmultirow#1[#2]#3[#4]#5{\@tempcnta=#1%
\@tempdima\@tempcnta\ht\@arstrutbox
\advance\@tempdima\@tempcnta\dp\@arstrutbox
\ifnum\@tempcnta<0\@tempdima=-\@tempdima\fi
\advance\@tempdima#2\bigstrutjot
\if*#3\setbox0\vtop to \@tempdima{\vfill\multirowsetup
\hbox{\strut#5\strut}\vfill}%
\else
\setbox0\vtop to \@tempdima{\hsize#3\@parboxrestore
\vfill \multirowsetup \strut#5\strut\par\vfill}%
\fi
\ht0\z@\dp0\z@
\ifnum\@tempcnta<0\advance\@tempdima-\dp\@arstrutbox
\else\@tempdima\ht\@arstrutbox
%\ifnum#2>0 \advance\@tempdima\bigstrutjot \fi
\ifdim#2pt>0pt \advance\@tempdima\bigstrutjot \fi
\fi
\advance\@tempdima#4\relax\leavevmode\vtop{\vskip-\@tempdima\box0\vss}}
\@ifundefined{bigstrutjot}{\newdimen\bigstrutjot \bigstrutjot\jot}{}
\makeatother
\begin{document}
\begin{tabular}{|lll|}
\hline
A & \multirow{2}[1.2]{*}{\color{red}%
\begin{tabular}{|l|l|}%|
A & A\bigstrut[t] \\
\hline
A & A\\
\end{tabular}} & A\bigstrut[t]\hlinestrut \\
A & {} & A \\
A & A & A \\
\hline
\end{tabular}
\end{document}
回到原始示例(包含三个\hlines
),最后一个复杂因素:\hline
两个表格的顶部应该重叠。首先,我们将其增加到bigstruts
(1.6
一个\bigstrut
和三个\hline
)。其次:内部\hline
是外部单元格的一部分!因此,如果我们什么都不做,内部表格将被推0.4pt
下。(这将太靠近第三行的单元格。)解决方案是使用 的\multirow
可选fixup
参数,它会移动单元格。(省略此可选参数[\arrayrulewidth]
意味着内部表格是不是移动以使它们的顶线重叠。)
\documentclass{article}
\usepackage{bigstrut}
\usepackage{multirow}
\usepackage{xcolor}
\def\hlinestrut{\rule[\dimexpr-\dp\strutbox-\arrayrulewidth]{\dimexpr\dp\strutbox+\arrayrulewidth}{0pt}}
\makeatletter
\def\@xmultirow#1[#2]#3[#4]#5{\@tempcnta=#1%
\@tempdima\@tempcnta\ht\@arstrutbox
\advance\@tempdima\@tempcnta\dp\@arstrutbox
\ifnum\@tempcnta<0\@tempdima=-\@tempdima\fi
\advance\@tempdima#2\bigstrutjot
\if*#3\setbox0\vtop to \@tempdima{\vfill\multirowsetup
\hbox{\strut#5\strut}\vfill}%
\else
\setbox0\vtop to \@tempdima{\hsize#3\@parboxrestore
\vfill \multirowsetup \strut#5\strut\par\vfill}%
\fi
\ht0\z@\dp0\z@
\ifnum\@tempcnta<0\advance\@tempdima-\dp\@arstrutbox
\else\@tempdima\ht\@arstrutbox
%\ifnum#2>0 \advance\@tempdima\bigstrutjot \fi
\ifdim#2pt>0pt \advance\@tempdima\bigstrutjot \fi
\fi
\advance\@tempdima#4\relax\leavevmode\vtop{\vskip-\@tempdima\box0\vss}}
\@ifundefined{bigstrutjot}{\newdimen\bigstrutjot \bigstrutjot\jot}{}
\makeatother
\begin{document}
\begin{tabular}{|lll|}
\hline
A & \multirow{2}[1.6]{*}[\arrayrulewidth]{\color{red}%
\begin{tabular}{|l|l|}%|
\hline
A & A\bigstrut[t] \\
\hline
A & A\\
\hline
\end{tabular}} & A\bigstrut[t]\hlinestrut \\
A & {} & A \\
A & A & A \\
\hline
\end{tabular}
\end{document}
当你使用(并行)\bigstrut
s 时,会出现另一个复杂情况,但不是在第一行。问题是,只要参数为正数,\multirow
就会自动移动表格。但是,这只有在第一行出现时才有意义(我相信这是由于多行使用top 构建单元格内容)。因此,在上述情况下,必须使用“取消移动”表格,如下所示:\bigstrutjot
bigstruts
\bigstrut
\vtop
fixup
\begin{tabular}{|lll|}
\hline
A & \multirow{2}[1.6]{*}[\dimexpr\arrayrulewidth-\bigstrutjot]{\color{red}%
\begin{tabular}{|l|l|}%|
\hline
A & A \\
\hline
A & A\bigstrut[t]\\
\hline
\end{tabular}} & A\hlinestrut \\
A & {} & A\bigstrut[t] \\
A & A & A \\
\hline
\end{tabular}
答案2
请注意,使用以下文本会重现相同的错误:
\documentclass{article}
\usepackage{xcolor}
\usepackage{multirow}
\setlength{\parindent}{0pt}
\newcommand{\vstrut}[3][blue]{{\color{#1}\rule[-#2]{0.4pt}{#3}}}
\newcommand{\hstrut}[2][blue]{{\color{#1}\makebox[0pt][l]{\rule[-0.4pt]{#2}{0.4pt}}}}
\begin{document}
\begin{tabular}{|lll|}
\hline
A\vstrut{0ex}{5ex} & \multirow{2}{3cm}{%
\begin{minipage}[t]{3cm}
Trial \vstrut[red]{18pt}{18pt} text
\end{minipage}}
& A \\
A\vstrut{3ex}{3ex}\hstrut{1.65in} & {} & A \\
A & A & A \\
\hline
\end{tabular}
\end{document}
\multirow
创建一个\vtop
框,其高度和深度根据的规则设置,\vtop
以及的高度和深度\@arstrutbox
。现在,\@arstrutbox
是创建表格环境时设置的框。它被设置为一个框,其高度和深度是\arraystretch
正常支柱的高度和深度的倍数。
通过上面示例中的可见支柱,您可以看到如何\multirow
为其内容创建框的效果。例如,即使您可以放置一个支柱来扩展第二行的大小,但这并不能防止支柱里面该\multirow
命令强制将创建的框的内容\multirow
设置为也大的。
因此,一种解决方案是重置 的值\arraystretch
。但这似乎有点过头了:你可能不想\arraystretch
改变所有的表仅修复一个盒子。
记住如何\multirow
创建它的框意味着几件事。考虑下一个例子,我告诉\multirow
你我只需要一行。
\begin{tabular}{|lll|}
\hline
A\vstrut{0ex}{5ex} & \multirow{1}{3cm}{%
\begin{minipage}[t][0pt]{3cm}
Trial \vstrut[red]{18pt}{18pt} text
\end{minipage}}
& A \\
A\vstrut{3ex}{3ex}\hstrut{1.65in} & {} & A \\
A & A & A \\
\hline
\end{tabular}
通过创建零高度的\multirow
顶部对齐,您可以完全放弃使用。minipage
\begin{tabular}{|lll|}
\hline
A\vstrut{0ex}{5ex} &%
{\begin{minipage}[t][0pt]{3cm}
Trial \vstrut[red]{18pt}{18pt} text
\end{minipage}}
& A \\
A\vstrut{3ex}{3ex}\hstrut{1.65in} & {} & A \\
A & A & A \\
\hline
\end{tabular}
避免\multirow
,你仍然可以实现更像你的原始示例的东西,你可以写:
\begin{tabular}{|lll|}
\hline
A &%
{\begin{minipage}[t][0pt]{3cm}
\begin{tabular}{|l|l|}
\hline
A & \hfill 1\textsuperscript{st} \\
\hline
A & A \\
\hline
\end{tabular}
\end{minipage}}
& A \\
A & {} & A \\
A & A & A \\
\hline
\end{tabular}
似乎使用的好处\multirow
是能够将其内容相对于它应该跨越的其他行居中(请参阅此答案末尾的编辑)。所以,这里有一个更接近你想要的例子。(我添加了一个\hrule
以更好地显示错误水平线的对齐。
\begin{tabular}{|lll|}
\hline
A &%
\multirow{2}{*}%
{\begin{minipage}[c][0pt]{3cm}%
\begin{tabular}[c]{|l|l|}
\hline
A & \hfill 1\textsuperscript{st} \\
\hline
A & A \\
\hline
\end{tabular}%
\end{minipage}}
& A \\\hline
A & {} & A \\
A & A & A \\
\hline
\end{tabular}
请记住,tabular
环境与 s 非常相似minipage
,可以相对于它们所在的线居中。
为了使水平线正确对齐,请在里面添加一个垂直支柱,minipage
如下所示(在此示例中,我使用它\raisebox
来创建一个总高度+深度为零的框):
\begin{tabular}{|lll|}
\hline
A &%
\multirow{2}{*}%
{\raisebox{0pt}[0pt][0pt]{\begin{minipage}{3cm}\vspace{0.5pt}%
\begin{tabular}[c]{|l|l|}
%\hline % commented-out from original code b/c it slightly struts out at the top
A & \hfill 1\textsuperscript{st} \\
\hline
A & A \\
\hline
\end{tabular}%
\end{minipage}}}
& A \\\hline
A & {} & A \\
A & A & A \\
\hline
\end{tabular}
另外一点,您的文档中行尾处有一些空白。这导致宽度与您定义的宽度不完全一致。我已经消除了一些更令人震惊的情况。
编辑
正如 @SašoŽivanović 指出的那样\multirow
,中心内容。但我谈论的是中心化\multirow
,本质上将总高度和深度为零的框的内容居中。这是因为\vtop
的定义中使用的的内容\multirow
被括在\vfill
s 之间,从而导致内容相对于要跨越的行生成的预期高度居中。
空格
在您最初的帖子中您调用
A & \multirow{2}{*}{
\begin{minipage}{3cm}
\begin{tabular}{|l|l|}
\hline
A & \hfill 1\textsuperscript{st}\bigstrut[t] \\
\hline
A & A \\
\hline
\end{tabular}
\end{minipage}
}
这会在行首添加额外的空格\multirow...
,当您编写时,也会在行尾添加额外的空格\end{minipage}
。请查看我的示例,我通过%
比您更早地放置或关闭参数来避免这种情况。
有关这方面的更多详细信息,我建议阅读@egreg的回答在 \newcommand 或类似命令中,在行尾添加百分号什么时候有害