垂直堆叠 parboxes:间距和计算

垂直堆叠 parboxes:间距和计算

我需要一个可以在双列模式下工作并且可以跨越多个页面的表格。由于我放弃了 supertabular(太多错误,控制力太差),我使用垂直堆叠的 parboxes 编写了一个简单的解决方案。这是我目前得到的结果:

在此处输入图片描述

(我添加了 fboxes 以使“单元格”可见。图像仅显示输出的上部。)

问题 1:垂直规则未与顶部对齐,我不知道如何计算正确的手动偏移量。(下一步是向规则添加一些额外的高度,以便它与上部规则关闭。)

在此处输入图片描述

问题2: 在这个例子中,我注释掉了垂直规则。现在你看到 parboxes 后面的空间是“不正确的”,它太少了。


梅威瑟:

\documentclass[10pt]{article}
\usepackage{lipsum}
\usepackage{forloop}
\usepackage{geometry}
\usepackage{ragged2e}
\geometry{a4paper, twocolumn, columnsep=10mm, top=10mm, left=10mm, right=10mm, bottom=10mm,
headsep=0mm, footskip=0mm}

\newlength\pataCellAWidth
\newlength\pataCellBWidth

%calculated
\newlength\pataCellAHeight
\newlength\pataCellBHeight
\newlength\pataRuleHeight
\newlength\pataLineHeight

\newsavebox{\pataBox}

% \newlength\pataTemp

\setlength\fboxsep{0pt}%for demonstration

%To be done
% \newlength\pataRowSep%vertical space between cells
% \setlength\pataRowSep{0.25\baselineskip}
\newcommand\pataNewRow{%
    \\%[\pataLineSep]%
}

\newcommand\pataAddCellA[1]{%
    \parbox[t]{\pataCellAWidth}{\RaggedRight #1}%
}

\newcommand\pataAddColSep[1]{%
    \hfill%
    \parbox[t]{1pt}{\rule[\dimexpr-#1]{1pt}{\dimexpr#1}}%
    \hfill%
}

\newcommand\pataAddCellB[1]{%
    \parbox[t]{\pataCellBWidth}{#1}%
}

\newcommand\pataAddRow[2]{%
    %estimate parbox heights
    \savebox{\pataBox}{{\parbox[b]{\pataCellAWidth}{#1}}}%
    \setlength\pataCellAHeight{\ht\pataBox}
    \savebox{\pataBox}{{\parbox[b]{\pataCellBWidth}{#2}}}%
    \setlength\pataCellBHeight{\ht\pataBox}%
    %always use the longer parbox for the rule
    \setlength\pataRuleHeight{\pataCellAHeight}
    \ifdim\pataCellBHeight>\pataRuleHeight%
        \setlength\pataRuleHeight{\pataCellBHeight}
    \fi%
    %
    %Output
    \pataAddCellA{#1}%
    \pataAddColSep{\pataRuleHeight}%
    \pataAddCellB{#2}%
    \pataNewRow%
}

\begin{document}
\setlength\parindent{0pt}
\setlength\pataCellAWidth{20mm}
\setlength\pataCellBWidth{\dimexpr66mm}
Table\par

\newcounter{thenumberA}
\newcounter{thenumberB}
\forloop{thenumberA}{1}{\value{thenumberA} < 3}{%
    \pataAddRow{longer text}{\lipsum[1]}
    \forloop{thenumberB}{1}{\value{thenumberB} < 8}{%
        \pataAddRow{short text}{dummytext\\more dummytext}%
    }%
}%
\lipsum[1]
\end{document}

答案1

你应该考虑如何在使用 minipages (或 \parboxes) 时保持恒定的 baselineskip?并使用\parbox[t]

这是一个实现,它还考虑到了左边的框比右边的框有更多行的可能性。

\documentclass[10pt]{article}
\usepackage{lipsum}
\usepackage{forloop}
\usepackage{geometry}
\usepackage{ragged2e}
\geometry{a4paper, twocolumn, columnsep=10mm, top=10mm, left=10mm, right=10mm, bottom=10mm,
headsep=0mm, footskip=0mm}

\newlength\pataCellAWidth
\newlength\pataCellBWidth
\newlength\pataCellAHeight
\newlength\pataCellBHeight
\newsavebox{\pataBox}

\newcommand\pataAddRow[2]{%
  \par
  \sbox{\pataBox}{\parbox[t]{\pataCellAWidth}{#1}}
  \setlength{\pataCellAHeight}{\dp\pataBox}%
  \sbox{\pataBox}{\parbox[t]{\pataCellBWidth}{#2}}
  \setlength{\pataCellBHeight}{\dp\pataBox}%
  \makebox[\linewidth][s]{%
    \parbox[t]{\pataCellAWidth}{#1\maybeprevdepth{\pataDepthCellA}}%
    \hfill
    \parbox[t]{\pataCellBWidth}{#2\maybeprevdepth{\pataDepthCellB}}%
  }%
  \par\prevdepth\savedprevdepth
}

\newcommand{\maybeprevdepth}[1]{\par\xdef#1{\the\prevdepth}}
\newcommand{\savedprevdepth}{%
  \ifdim\pataCellAHeight>\pataCellBHeight
    \pataDepthCellA
  \else
    \pataDepthCellB
  \fi
}

\begin{document}
\setlength\parindent{0pt}
\setlength\pataCellAWidth{20mm}
\setlength\pataCellBWidth{\dimexpr66mm}
Table\par

\newcounter{thenumberA}
\newcounter{thenumberB}
\forloop{thenumberA}{1}{\value{thenumberA} < 3}{%
    \pataAddRow{longer text}{\lipsum[1]}
    \forloop{thenumberB}{1}{\value{thenumberB} < 5}{%
        \pataAddRow{short text}{dummytext\\more dummytext}%
        \pataAddRow{short text\\two lines}{dummytext}%
    }%
}%
\lipsum[1]
\end{document}

在此处输入图片描述

允许使用规则将左列与右列分开的另一种实现。我在表格主体周围添加了一个环境。

\documentclass[10pt]{article}
\usepackage{lipsum}
\usepackage{forloop}
\usepackage{geometry}
\usepackage{ragged2e}
\geometry{a4paper, twocolumn, columnsep=10mm, top=10mm, left=10mm, right=10mm, bottom=10mm,
headsep=0mm, footskip=0mm}


\newlength\pataCellAWidth
\newlength\pataCellBWidth

\newenvironment{pataCells}[1]
 {\par\setlength{\parindent}{0pt}%
  \setlength{\pataCellAWidth}{#1}%
  \setlength{\pataCellBWidth}{\dimexpr\linewidth-#1-1em}}
 {\par\prevdepth=\dp\strutbox}

\newcommand\pataAddRow[2]{%
  \par\ifdim\prevdepth=-1002pt\penalty0 \nointerlineskip\fi
  \makebox[\linewidth][s]{%
    \parbox[t]{\pataCellAWidth}{\strut#1\unskip\nobreak\strut}%
    \hfill\vrule\hfill
    \parbox[t]{\pataCellBWidth}{\strut#2\unskip\nobreak\strut}
  }%
  \par\prevdepth-1002pt
}

\begin{document}
\lipsum[2]

\begin{pataCells}{20mm}
\newcounter{thenumberA}
\newcounter{thenumberB}
\forloop{thenumberA}{1}{\value{thenumberA} < 3}{%
    \pataAddRow{longer text}{\lipsum[1]}
    \forloop{thenumberB}{1}{\value{thenumberB} < 5}{%
        \pataAddRow{short text}{dummytext\\more dummytext}%
        \pataAddRow{short text\\two lines}{dummytext}%
    }%
}
\end{pataCells}
\lipsum[1]
\end{document}

在此处输入图片描述

答案2

另一种基于使用minipagesTikZ节点的相对简单的方法: 在此处输入图片描述

代码:

\documentclass[10pt]{article}
\usepackage{lipsum}
\usepackage{tikz,calc}% <-- added
\usepackage{geometry}
\usepackage{ragged2e}
\geometry{a4paper, twocolumn, columnsep=10mm, top=10mm, left=10mm, right=10mm, bottom=10mm,
headsep=0mm, footskip=0mm}

\newlength\ShortCell
\newlength\LongCell

\newcommand\pataRow[2]{
    \parbox[t]{\ShortCell}{#1}
    \parbox[t]{\LongCell}{\hspace{0.5ex}
                          \tikz{\node[inner sep=0pt,outer sep=0pt,
                                      align=justify, text width=\hsize-2ex]
                                      (LongCell) {#2};
                                \draw[ultra thick,%<-- line thickness
                                      transform canvas={xshift=-2ex}]
                                      (LongCell.north west) -- (LongCell.south west);
                                }
                            }}

\setlength\parindent{0pt}
\setlength\parskip{1ex}

\begin{document}
\setlength\ShortCell{20mm}
\setlength\LongCell{\columnwidth-\ShortCell}

\lipsum[1]
\textbf{Table}\par
\pataRow{longer text}{\lipsum[1]}

\pataRow{short text}{dummytext\\more dummy text}%
\pataRow{short text}{dummytext\\more dummy text}%
\pataRow{short text}{dummytext\\more dummy text}%
\pataRow{short text}{dummytext\\more dummy text}%

\pataRow{short text\\two lines}{dummy text}%

\lipsum[1-3]
\end{document}

在我的提议中,我跳过了循环中堆叠 parbox 的生成。确定它很简单。

答案3

感谢@egreg,我可以编写一个可行的解决方案作为 supertabular 的替代方案。代码肯定不完美,但我想分享它,以防有人使用它。

几点说明:

  1. 该代码只是为了我的目的而编写的:一个包含两列的表格,可以跨越多页并自动进行分栏。
  2. \RaggedLeft不能作为列的预编码(右对齐)。
  3. 自动分栏计算:Supertabular 在这一点上非常薄弱。我注意到,\pagetotal如果出现分栏,LaTeX 不会更新,只有在 1-2 行之后才会更新。我的代码解决了这个问题(参见代码)。计算似乎非常准确,但没有考虑脚注等。
  4. 由于\\在表格中不起作用,您可以使用\pataContinueRow来模拟换行符。它将添加一行没有垂直分隔符的行。
  5. 单元格之间的垂直间距代码不太好。这可能需要改进。

梅威瑟:

\documentclass[10pt]{article}
\usepackage{forloop}
\usepackage{geometry}
\usepackage{ragged2e}
\usepackage{etoolbox}

\geometry{a4paper, twocolumn, columnsep=10mm, top=10mm, left=10mm, right=10mm, bottom=10mm,
headsep=0mm, footskip=0mm}

\newlength\pataCellAWidth
\newlength\pataCellBWidth

\newtoggle{pataVeryFirstRow}%First of Row doesn't get ever a separator
\newtoggle{pataNewColHasARowAlready}%only don't use a separator if it's the first row on the new column
\newtoggle{pataUseSeparator}%use the separator for this row?
\newtoggle{pataContinueRow}%row is just continued, no separator

\newlength\pataRowSep{}%length of the vspace
\setlength\pataRowSep{-120mm}%%TODO:there should be a better way to handle the additional vertical space

\newlength\pataRestHeight%temporary calculated rest after boxes are printed
\newlength\pataSafetyDistance%if remaining margin is below 4pt or something there are automatical column breaks
\setlength\pataSafetyDistance{4pt}%
\newsavebox\pataTempBox%for calculation

\newenvironment{pataCells}[1]
 {\par\setlength{\parindent}{0pt}%
  \setlength\parskip{0pt}
  \setlength{\pataCellAWidth}{#1}%
  \setlength{\pataCellBWidth}{\dimexpr\linewidth-#1-1em}%
  \toggletrue{pataVeryFirstRow}%
  }
 {\par\prevdepth=\dp\strutbox}

\newcommand\pataPreCellA{}%in case \RaggedRight or something must be added
\newcommand\pataPreCellB{}

\newcommand\pataEstimateBox[2]{%calculate height of a box
  \sbox\pataTempBox{\makebox[\linewidth][s]{%
    \parbox[t]{\pataCellAWidth}{\strut#1\unskip\nobreak\strut}%
    \hfill\vrule\hfill
    \parbox[t]{\pataCellBWidth}{\strut#2\unskip\nobreak\strut}
  }}%
}

\newcommand\pataWriteBox[2]{%just write the box
  \makebox[\linewidth][s]{%
    \parbox[t]{\pataCellAWidth}{\strut#1\unskip\nobreak\strut}%
    \hfill\vrule\hfill%
    \parbox[t]{\pataCellBWidth}{\strut#2\unskip\nobreak\strut}%
  }%
  \par\prevdepth-10002pt%connect the par with the previous one
}

\newcommand\pataAddRow[2]{%adds an row
  \wlog{CellA: #1}%for debugging
  \toggletrue{pataUseSeparator}%reset
  \iftoggle{pataContinueRow}{\togglefalse{pataUseSeparator}}{}
  \iftoggle{pataVeryFirstRow}%
    {\togglefalse{pataUseSeparator}}%if it's the first row just print it
    {%it's not the very first row
      %calculate content height
      \pataEstimateBox{{\pataPreCellA{}#1}}{{\pataPreCellB{}#2}}
      \setlength\pataRestHeight{\dimexpr\ht\pataTempBox+\dp\pataTempBox}%add main box height
      \iftoggle{pataNewColHasARowAlready}{%add the separator box height if it's not the first row of a new column
        \tiny\pataEstimateBox{\vspace{\pataRowSep}}{\vspace{\pataRowSep}}\normalsize%estimate height
        \addtolength\pataRestHeight{\dimexpr\ht\pataTempBox+\dp\pataTempBox}%Sep.box
      }{}
      \addtolength\pataRestHeight\pataSafetyDistance%add some safety distance
      \wlog{Height of content+safety distance: \the\pataRestHeight}%
      \setlength\pataRestHeight{\dimexpr\textheight-\pagetotal-\pataRestHeight}%remaining space on page%not working with footnotes etc.
      \wlog{Remaining space after content: \the\pataRestHeight}
      %
      \ifdimcomp{\pataRestHeight}{>}{0pt}{%enough space
        \togglefalse{pataNewColHasARowAlready}%setback; pagetotal working correct again
      }{%there was somewhere in time a column break
        \nottoggle{pataNewColHasARowAlready}{%it's the first row in the new column
          \togglefalse{pataUseSeparator}%
          \toggletrue{pataNewColHasARowAlready}%that's me
          \newpage%
          \wlog{Breaking the column manually}
        }{%it's not the first column
          \toggletrue{pataUseSeparator}%I hope this 'blind' rows have 'normal' heights
        }%\nottoggle
      }%\ifdimcomp
    }%
  %Output
  \par
  \iftoggle{pataUseSeparator}{%Add space above the row if needed
    \tiny\pataWriteBox{\vspace{\pataRowSep}}{\vspace{\pataRowSep}}\normalsize%TODO:there should be a better way to handle the additional vertical space
    }{}%
  \pataWriteBox{{\pataPreCellA{}#1}}{{\pataPreCellB{}#2}}%write the row, finally
  \togglefalse{pataVeryFirstRow}
  \togglefalse{pataContinueRow}
  % \ifdim\prevdepth=-1002pt\penalty0 \nointerlineskip\fi
}

\newcommand\pataContinueRow[2]{%behaves like a linebreak: writes a Row but doesn't use the separator
  \toggletrue{pataContinueRow}%
  \pataAddRow{#1}{#2}%
}


\begin{document}

\newcommand\lip{Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.}
\lip

\newcounter{thenumberA}
\newcounter{thenumberB}
\begin{pataCells}{20mm}
\pataAddRow{Col A}{Col B}
\hrule
\forloop{thenumberA}{1}{\value{thenumberA} < 13}{%
    \pataAddRow{longer text}{\lip}\wlog{here}
    \pataContinueRow{}{\lip{}}
    \forloop{thenumberB}{1}{\value{thenumberB} < 5}{%
        \pataAddRow{short texttwo lines}{dummytext}%
    }%
}%
\end{pataCells}
\lip
\end{document}

相关内容