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
    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. 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
    Aug 29, 2021 at 7:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.