2

environment to balance a table in a multicol

I'd like an environment that balances a table in a multicol environment.

By this I mean I'd like to have potentially long tabular-like data that automatically breaks to another column of a roughly equal number of rows.

like so, automatically breaking after row 3, for a 2 column tabular, into a 2 column multicol (artist's rendition)

lipsum lipsum lipsum lipsum lipsum

    row1 col2        row4 col2
    row2 col2        row5 col2
    row3 col2

lipsum lipsum lipsum lipsum lipsum

Additionally, I was looking to use xparse and a multicol to do this, in order to pass the number of columns to use through the custom environment down to multicols.

Additionally, I was looking to use the book class and showframe package.

I've tried two solutions:

solution A, long table

This answer produces the correct output but not when I wrap it in an environment:

Balancing long table inside multicol in LaTeX

I've tried two fixes:

solution A, fix 1: replace the \vbox{ and } with \bgroupand \egroup

Attempt no. 1 results in misaligned columns, and these errors:

  • Undefined control sequence. \begin{myenvironment}
  • Package longtable Error: longtable not in 1-column mode.
  • Undefined control sequence. \end{myenvironment}
  • misaligned columns
  • @numberne appears in the columns

solution 1, attempt 1

\documentclass[]{book}
\usepackage{showframe}
\usepackage[]{geometry}
\usepackage{longtable}
\usepackage{multicol}
\usepackage{xparse}

\newsavebox\ltmcbox

\def\shortlipsum{\par Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut purus elit, vestibulum ut, placerat ac, adipiscing vitae, felis.\par}

\newcounter{entryno}
\setcounter{entryno}{1}
\def\tabline{Test & \the\value{entryno} & Description\addtocounter{entryno}{1}\\}
\def\tablines{\tabline\tabline\tabline\tabline\tabline}

\NewDocumentEnvironment{myenvironment}{O{2}}
{
    \begin{multicols}{#1}
    \setbox\ltmcbox\vbox\bgroup
    \makeatletter\col@number\@ne
    \begin{longtable}{|l|l|l|}
}
{
    \makeatletter\col@number\@ne
    \end{longtable}
    \unskip
    \unpenalty
    \unpenalty
    \egroup\unvbox\ltmcbox
    \end{multicols}
}

\begin{document}

This works great!
\shortlipsum
\begin{multicols}{2}
    \shortlipsum
    \medskip
    \setbox\ltmcbox\vbox{
        \makeatletter\col@number\@ne
        \begin{longtable}{|l|l|l|}
            \tablines\tablines\tablines\tablines\tablines\tablines
        \end{longtable}
        \unskip
        \unpenalty
        \unpenalty
    }
    \unvbox\ltmcbox
    \medskip
    \shortlipsum
\end{multicols}

\shortlipsum
\par

This does not work!
\begin{myenvironment}
\tablines\tablines\tablines\tablines\tablines\tablines
\end{myenvironment}
\shortlipsum

\end{document}

solution A, fix 2: replace the \vbox{ and } with \begingroup and \endgroup

Attempt no. 2 results in a loss of output past the first \shortlipsum and:

  • Missing { inserted. \begin{myenvironment}
  • Undefined control sequence. \begin{myenvironment}
  • Package longtable Error: longtable not in 1-column mode.
  • Undefined control sequence. \end{myenvironment}
  • Missing } inserted. \end{myenvironment}

enter image description here

\documentclass[]{book}
\usepackage{showframe}
\usepackage[]{geometry}
\usepackage{longtable}
\usepackage{multicol}
\usepackage{xparse}

\newsavebox\ltmcbox

\def\shortlipsum{\par Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut purus elit, vestibulum ut, placerat ac, adipiscing vitae, felis.\par}

\newcounter{entryno}
\setcounter{entryno}{1}
\def\tabline{Test & \the\value{entryno} & Description\addtocounter{entryno}{1}\\}
\def\tablines{\tabline\tabline\tabline\tabline\tabline}

\NewDocumentEnvironment{myenvironment}{O{2}}
{
    \begin{multicols}{#1}
    \setbox\ltmcbox\vbox\begingroup
    \makeatletter\col@number\@ne
    \begin{longtable}{|l|l|l|}
}
{
    \makeatletter\col@number\@ne
    \end{longtable}
    \unskip
    \unpenalty
    \unpenalty
    \endgroup\unvbox\ltmcbox
    \end{multicols}
}

\begin{document}

This works great!
\shortlipsum
\begin{multicols}{2}
    \shortlipsum
    \medskip
    \setbox\ltmcbox\vbox{
        \makeatletter\col@number\@ne
        \begin{longtable}{|l|l|l|}
            \tablines\tablines\tablines\tablines\tablines\tablines
        \end{longtable}
        \unskip
        \unpenalty
        \unpenalty
    }
    \unvbox\ltmcbox
    \medskip
    \shortlipsum
\end{multicols}

\shortlipsum
\par

This does not work!
\begin{myenvironment}
\tablines\tablines\tablines\tablines\tablines\tablines
\end{myenvironment}
\shortlipsum

\end{document}

solution B, pseudo-nested longtable w/ savebox

This answer also produces what I want, but I couldn't get it to align with the text.

balanced longtables, multicol and page breaks

I've tried:

solution B, fix 1: wrap the commands in an env and remove the table, and that works great!

enter image description here

However...

That works great until I add the showframe package and I get:

  • Missing } inserted. \begin{myenvironment}3
  • Extra }, or forgotten \endgroup{myenvironment}
  • added space under the longtable

enter image description here

\documentclass[]{book}
%\usepackage{showframe}
\usepackage{longtable}
\usepackage{multicol}
\usepackage{lipsum}
\usepackage{capt-of}
\usepackage{xparse}

\def\shortlipsum{\par Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut purus elit, vestibulum ut, placerat ac, adipiscing vitae, felis.\par}

\newcounter{entryno}
\setcounter{entryno}{1}
\def\tabline{Test & \the\value{entryno} & Description\addtocounter{entryno}{1}\\}
\def\tablines{\tabline\tabline\tabline\tabline\tabline}

\makeatletter
\newsavebox\ltmcbox
\newsavebox\xxbox
\newenvironment{multicolslongtable}[1]{
    \setbox\ltmcbox\vbox\bgroup
    \col@number\@ne
    \begin{longtable}{#1}
}
{
    \end{longtable}
    \unskip
    \unpenalty
    \unpenalty\egroup
    \unvbox\ltmcbox
}
\makeatother

\NewDocumentEnvironment{myenvironment}{O{2}}
{
    \savebox\xxbox\bgroup
    \begin{minipage}{\textwidth}
    \begin{multicols}{#1}
    \begin{multicolslongtable}{| l | l | l |}
}
{
    \end{multicolslongtable}
    \end{multicols}
    \end{minipage}
    \egroup
    \begin{multicols}{#1}
        \usebox\xxbox
    \end{multicols}
}


\begin{document}

\shortlipsum

\begin{myenvironment}[2]
\tablines\tablines\tablines\tablines\tablines\tablines
\end{myenvironment}

\shortlipsum

\end{document}
2
  • 1
    Have you tried \usepackage[showframe]{geometry}? It does the same but without breaking your code.
    – AboAmmar
    Commented Jul 28, 2020 at 1:26
  • @AboAmmar perfect! thank you! I wasn't aware of that option. I'll clean up the code and post the answer. Commented Jul 29, 2020 at 0:39

1 Answer 1

0

The fix was to use the showframe option from geometry package instead of the showframe package.

Thank you AboAmmar!

The code below shows an environment that balances tabular data using a longtable in a multicol (with showframe), by combining the following answers, xparse, and minor refactoring:

enter image description here

% environment to balance a table in a multicol

\documentclass[]{book}
\usepackage[showframe]{geometry}
\usepackage{longtable}
\usepackage{multicol}
\usepackage{lipsum}
\usepackage{xparse}


% helpers for the test
\def\shortlipsum{\par Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut purus elit, vestibulum ut, placerat ac, adipiscing vitae, felis.\par}
\newcounter{entryno}
\setcounter{entryno}{1}
\def\tabline{Test & \the\value{entryno} & Description\addtocounter{entryno}{1}\\}
\def\tablines{\tabline\tabline\tabline\tabline\tabline\tabline\tabline\tabline\tabline}


% box for a multi column long table
% SEE https://tex.stackexchange.com/questions/161827/balanced-longtables-multicol-and-page-breaks
\makeatletter
\newsavebox\ltmcbox
\newsavebox\xxbox
\newenvironment{multicolslongtable}[1]{
    \setbox\ltmcbox\vbox\bgroup
    \col@number\@ne
    \begin{longtable}{#1}
}
{
    \end{longtable}
    \unskip
    \unpenalty
    \unpenalty\egroup
    \unvbox\ltmcbox
}
\makeatother


% environment to accept table input and produce multicol
\NewDocumentEnvironment{myenvironment}{O{2}}
{
    \savebox\xxbox\bgroup
    \begin{minipage}{\textwidth}
    \begin{multicols}{#1}
    \begin{multicolslongtable}{| l | l | l |}
}
{
    \end{multicolslongtable}
    \end{multicols}
    \end{minipage}
    \egroup
    \begin{multicols}{#1}
        \centering
        \usebox\xxbox
    \end{multicols}
}


% patch multicols to allow for one column
% SEE https://tex.stackexchange.com/questions/233866/one-column-multicol-environment
\let\multicolmulticols\multicols
\let\endmulticolmulticols\endmulticols
\RenewDocumentEnvironment{multicols}{mO{}}
{%
    \ifnum#1=1
    #2%
    \else % More than 1 column
    \multicolmulticols{#1}[#2]
    \fi
}
{%
    \ifnum#1=1
    \else % More than 1 column
    \endmulticolmulticols
    \fi
}


\begin{document}

\section{one column}
\shortlipsum
\begin{myenvironment}[1]
\tablines
\end{myenvironment}
\shortlipsum

\section{two column}
\shortlipsum
\begin{myenvironment}
    \tablines
\end{myenvironment}
\shortlipsum

\section{three column}
\shortlipsum
\begin{myenvironment}[3]
    \tablines
\end{myenvironment}
\shortlipsum

\end{document}
1
  • Your document example can't be compiled, it throw the same error as you reported in question. BTW, showframe doesn't interact with page content. Cause of your error is something else.
    – Zarko
    Commented Aug 29, 2021 at 7:59

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .