Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I understand how to get multicol package to use the entirety of the first column before moving to the next:

\begin{multicols*}{3} 
....
\end{multicols*}

which is mentioned in section 2.2 of the manual. But it also mentions in that section that the starred environment "only works on top-level." The manual explains that "inside a box one has to balance to determine a column height in absence of a fixed value."

What I would like to know is whether there's a way to get around this when the height of the containing box is known.

In other words, if I would like to write something like

\begin{minipage}[t][4in]{10in}
\begin{multicols*}{3}
....
\end{multicols*}
\end{minipage}

and get the multicol package to think that it's on a page of the specified height.

Does anyone know any work arounds?

I know I could use \newgeometry for a given page. But, my headers and footers get moved around and I'm not happy with that. Moreover, I generally don't want to dedicate entire pages to this multicolumned format.

Here's an example of what the page design should look like. While it might be hard to tell from the image. This is an 8.5x11 page in landscape.

enter image description here

Here's the MWE which created this image. This is a very odd page design, but it meets the needs for the finished document.

\documentclass{article}
%--------------------
\usepackage[top=0.35in,bottom=0.35in,width=4in,landscape,includefoot,includehead]{geometry}
%--------------------
\usepackage{fancyhdr}
\renewcommand{\headrulewidth}{0.4pt}
\renewcommand{\footrulewidth}{0.4pt}
\lhead{Left}\rhead{Right}
\pagestyle{fancy}
%--------------------
\usepackage{multicol}
\setlength{\columnseprule}{0.4pt}
\setlength{\columnsep}{0.25in}
%--------------------
\usepackage{lipsum}
\begin{document}

\lipsum[1]
\vspace{2ex}

\noindent
\hspace*{\dimexpr\textwidth/2}%
\hspace*{-5in}%
\begin{minipage}{0pt}
  \begin{minipage}[t][2.85in]{10in}
    \begin{multicols*}{4}
        \lipsum[1-2]
        \vspace{2in}        

        \vspace{2.85in}~
        \hspace*{\fill}.
    \end{multicols*}
  \end{minipage}
\end{minipage}

\vspace{2ex}
\lipsum[2]

\end{document}

The document is deliberately designed to have extremely large margins---so the headers and footers should similarly not span the entire page to preserve the appearance of massive margins.

Obviously I can achieve the effect I want, but I don't want to have to go through each of these multi-column insets and manually place sufficient struts to properly fill up the height of the box.

Incidentally, the final \hspace*{\fill}. in the multicols environment is only inserted there so that, when I cropped the image, the cropping didn't knock off too much of the empty space.

Two ideas:

I have two ideas about how to accomplish this. But I don't have any idea of how to implement either.

Preliminaries

Though for the final version I would like to be able to choose how many columns I need, for the sake of explaining my ideas, I'll assume that I'm working with 4 columns of text.

Let's say that the total width of the environment is W and that the \columnsep is set to s. Then one column of text within the environment should have a width of C=(W-3s)/4.

Let's say that height of the environment is H. Since I'm formatting four columns of text, where each column has height H, the total effective height of each column, if stacked on top of each other combined, is close to 4H.

First Idea

The first formats a multi-column environment under a single run with pdflatex.

The idea is as follows:

(1) First format the text as though it were just one column of width C

I could do that something like:

\begin{lrbox}{\aebox}
  \begin{minipage}{<width=C>}
  ....TEXT....
  \end{minipage}
\end{lrbox}

(2) Measure the height of this column of text, call that h

\setlength{<height=h>}{\dimexpr\dp\aebox+\ht\aebox\relax}    

(3) If h>4H, then I've got problems. I'm not interested in considering this case.

(4) If h<4H, then I look at the difference 4H-h and create as many struts of height H that will fit in 4H-h and one remainder strut of height 4H-h modulo H

Suppose the columns are lettered, from left to right, as A, B, C, and D. Then I will have lengths

\aestrutDheight      
\aestrutBheight      
\aestrutCheight      
\aestrutRheight <remainder height>

<PSEUDO-CODE>
let L=4H-h

while L > H
{
  <set a length for each iteration>
  \setlength{\aestrut[DBC]height}{<height=H>}
  L=L-H
}
\setlength{\aestrutRheight}{L}

(5) Reprocess the text but with the the remainder strut and other struts appended.

The pseudo-code here is for the case where I have enough text to span 3 columns, but not 4.

\begin{minipage}[t][<height=H>]{<width=C>}
\begin{multicols*}{4}
....TEXT....

\rule{0pt}{\aestrutRheight}

\rule{0pt}{\aestrutDheight}
\end{multicols*}
\end{minipage}

Generally, I think I can do this except for the very last step. Once I've used the text, I've lost it and don't know how to reprocess it.

Second Idea

This idea is very similar to the first. But requires two passes of pdflatex.

(1) Try formatting the text as 4 columns of balanced text

\begin{lrbox}{\aebox}
\begin{minipage}{<width=W>}
\begin{multicols}{4}
....TEXT....
\end{multicols}
\end{minipage}
\end{lrbox}

(2) Measure the height of this box.

(3) Calculate the different of betweeen this height and the target height.

(4) Calculate the lengths of the necessary struts, but write this out to a log file.

(5) On the second rerun of pdflatex, read in the log file and then format the text as

\begin{minipage}[<height=H>]{<width=W>}
\begin{multicols*}{4}
...TEXT...
<insert struts determine by `log` file>
\end{multicols*}
\end{minipage}

But I don't know how to write this information to a log file or how to read in from the log file to create the necessary struts.

UPDATE: The start of a workable solution, but not quite there.

I've created the following work around. But there are several things about it that I can't get right:

\begin{filecontents}{content.tex}
  Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut purus elit,
  vestibulum ut, placerat ac, adipiscing vitae, felis. Curabitur dictum
  gravida mauris. Nam arcu libero, nonummy eget, consectetuer id, vulputate
  a, magna. Donec vehicula augue eu neque. Pellentesque habitant morbi
  tristique senectus et netus et malesuada fames ac turpis egestas. Mauris
  ut leo. Cras viverra metus rhoncus sem. Nulla et lectus vestibulum urna
  fringilla ultrices. Phasellus eu tellus sit amet tortor gravida
  placerat. Integer sapien est, iaculis in, pretium quis, viverra ac,
  nunc. Praesent eget sem vel leo ultrices bibendum. Aenean faucibus. Morbi
  dolor nulla, malesuada eu, pulvinar at, mollis ac, nulla. Curabitur auctor
  semper nulla. Donec varius orci eget risus. Duis nibh mi, congue eu,
  accumsan eleifend, sagittis quis, diam. Duis eget orci sit amet orci
  dignissim rutrum.

  Nam dui ligula, fringilla a, euismod sodales, sollicitudin vel,
  wisi. Morbi auctor lorem non justo. Nam lacus libero, pretium at, lobortis
  vitae, ultricies et, tellus. Donec aliquet, tortor sed accumsan bibendum,
  erat ligula aliquet magna, vitae ornare odio metus a mi. Morbi ac orci et
  nisl hendrerit mollis. Suspendisse ut massa. Cras nec ante. Pellentesque a
\end{filecontents}
\documentclass{article}
%--------------------
\usepackage[top=0.35in,bottom=0.35in,width=4in,landscape,includefoot,includehead]{geometry}
%--------------------
\usepackage{xcolor}
\usepackage{fancyhdr}
\renewcommand{\headrulewidth}{0.4pt}
\renewcommand{\footrulewidth}{0.4pt}
\lhead{Left}\rhead{Right}
\pagestyle{fancy}
%--------------------
\usepackage{multicol}
\setlength{\columnseprule}{0.4pt}
\setlength{\columnsep}{0.25in}
%--------------------
\usepackage{lipsum}

\usepackage{xparse}

\newlength\aetmpdima
\newlength\aetmpdimb
%% Loop to reduce the height to below max value
\def\whileloop#1#2%
  {\aetmpdima#1%
   \aetmpdimb#2%
   \ifdim\aetmpdima>\aetmpdimb\relax
      \aetmpdima\dimexpr\aetmpdima-\aetmpdimb\relax
      \whileloop\aetmpdima\aetmpdimb
   \fi
   #1\aetmpdima
  }

\newlength{\myenvWIDTH}
\newlength{\myenvHEIGHT}
\newlength{\myenvREMAINDER}
\newlength{\myenvSTRUT}
\newcommand{\myenvCOLCNT}{4}
\setlength{\myenvWIDTH}{10in}
\setlength{\myenvHEIGHT}{2.25in}
\setlength{\myenvSTRUT}{0pt}
\newsavebox{\singlecolumnbox}
\NewDocumentCommand{\aecols}{ m }
  {
    %% create a box the width of one column
    \begin{lrbox}{\singlecolumnbox}%
      \begin{minipage}{\dimexpr(\myenvWIDTH-\number\numexpr\myenvCOLCNT-1\relax\columnsep)/\myenvCOLCNT}
        \input{#1}%
      \end{minipage}%
    \end{lrbox}%
    %% reduce lengths to get lengths of the struts
    \setlength{\myenvREMAINDER}{\dimexpr\myenvCOLCNT\myenvHEIGHT-(\ht\singlecolumnbox+\dp\singlecolumnbox)\relax}%
    \ifdim\myenvREMAINDER>\myenvHEIGHT\relax
      \setlength{\myenvSTRUT}{\myenvHEIGHT}\fi          
    \whileloop{\myenvREMAINDER}{\myenvHEIGHT}%
    %% format the multicolumn environment
    \noindent
    \begin{minipage}[t][\myenvHEIGHT]{\myenvWIDTH}%
    \noindent
    \begin{multicols}{\myenvCOLCNT}%
        \raisebox{0pt}[0pt][0pt]{\textcolor{gray!60}{\rule[\dimexpr-\myenvHEIGHT+2ex]{4pt}{\myenvHEIGHT}}}
        \input{#1}
        \textcolor{blue}{\rule{4pt}{\dimexpr\myenvREMAINDER}}
        \textcolor{red}{\rule{4pt}{\dimexpr\myenvSTRUT}}
    \end{multicols}%
    \par\xdef\tpd{\the\prevdepth}
    \end{minipage}%
    \par\prevdepth\tpd
}

\begin{document}

\lipsum[1]
\vspace{2ex}

\noindent\hspace*{\dimexpr\textwidth/2-\myenvWIDTH/2}%
\rule{\myenvWIDTH}{5pt}

\noindent\hspace*{\dimexpr\textwidth/2-\myenvWIDTH/2}%
\aecols{content}

\vspace{2ex}
\lipsum[2]

\end{document}

enter image description here

The first problem is I can't seem to get \vspace to work correctly. So, I have to use \rule. In this above example, I've given width different from 0pt only to help them be visible for development purposes. Similarly, the gray strut at the beginning is only there for development purposes.

The second problem, I sometimes get multiple overful vbox errors: apparently caused by my struts, but only for certain values of the parameters. (Can't seem to reproduce them right now, though.) When I do get the errors, there are far more than struts I've created. Sorry I can't reproduce them right now. :(

Third problem, I can't get the spacing after the environment to work out correctly. I tried the \prevdepth trick, but it's not working here.

Fourth, not so much a problem, I'm getting around the issue of having to reformatting the same text by reading the text in twice from an outside file. I can live with this, but it would be nice if I didn't have to go this route.

Any suggestions about how to fix any of this?

PS

If I can rediscover the parameter values which cause the vbox errors, I'll post them in the comments following this question.

share|improve this question
    
Why would you like to put a three column text inside a minipage? –  Keks Dose Jul 10 '13 at 19:54
    
@KeksDose I have text that needs to be formatted differently from the rest of the page: namely, in multiple columns. The formatting calls for it to span a width wider than the usual text width, but it should not sit on its own page. –  A.Ellett Jul 10 '13 at 20:12
    
The parameter values, listed below, create 70 Overfull \vbox errors where the lengths vary from 48.23993pt too high to 76.23993pt too high and quite a few values inbetween. \myenvWidth=10in, \myenvHEIGHT=3.85in, \myenvCOLCNT=4. Not sure why I'm getting so many errors when I have at most 3 struts (I'm assuming it's the struts causing the problems). –  A.Ellett Jul 11 '13 at 4:00
    
I got rid of the \noindent arguments from inside the \aecols command. I'd forgotten about these. This seems to fix the vertical alignment and my \vbox errors have disappeared for any of the current values I've been using. –  A.Ellett Jul 11 '13 at 5:32
1  
Post your solution as an answer and that's it. –  Keks Dose Jul 12 '13 at 8:09

4 Answers 4

up vote 3 down vote accepted

I'd use a low level method with \vsplit:

\documentclass{article}
\usepackage[latin]{babel} % to hyphenate lipsum
\usepackage{microtype}    % avoid overfull lines
%--------------------
\usepackage[
  top=0.35in,
  bottom=0.35in,
  width=4in,
  landscape,
  includefoot,
  includehead,
]{geometry}

%--------------------

\usepackage{fancyhdr}
\pagestyle{fancy}
\renewcommand{\headrulewidth}{0.4pt}
\renewcommand{\footrulewidth}{0.4pt}
\fancyhead[L]{Left}
\fancyhead[R]{Right}

%--------------------

\usepackage{lipsum}

\begin{document}

\lipsum[1]

\vspace{2ex}

\noindent
\hspace*{-3in}%
\makebox[0pt][l]{%
  \setbox0=\vbox{\hsize=2.5in
    \lipsum[1-2]
  }%
  \splittopskip=0pt \vbadness=10000
  \setbox2=\vsplit0 to 2.5in
  \vtop{\hrule height0pt\unvbox2}\hspace{0.25in}\vrule\hspace{0.25in}%
  \setbox2=\vsplit0 to 2.5in
  \vtop{\hrule height0pt\unvbox2}\hspace{0.25in}\vrule\hspace{0.25in}%
  \vtop{\hrule height0pt\unvbox0}
}

\vspace{3ex}

\lipsum[2]

\end{document}

Adjust the positioning at will.

enter image description here

share|improve this answer
    
This is an interesting solution. I'm going to play with it for a while to make sure I understand what it does and how I can create an environment that automates this. –  A.Ellett Jan 11 at 18:02

Well, here goes. I am more than a little reticent about this suggestion, and it is only a start -- you will want to tailor it to your needs if it suits. Still, I think this is what you want. I agree with egreg: \vsplit is your friend. The code first:

    \documentclass{article}

%--------------------
\usepackage[top=0.35in,bottom=0.35in,width=4in,landscape,includefoot,includehead]{geometry}
%--------------------
\usepackage{fancyhdr}
\renewcommand{\headrulewidth}{0.4pt}
\renewcommand{\footrulewidth}{0.4pt}
\lhead{Left}\rhead{Right}
\pagestyle{fancy}

\usepackage{calc}
\usepackage{lipsum}

\newcommand{\breakit}{\vfill\eject\ \unskip}

\newlength{\unbalcolht}

\newenvironment{unbalminicols}[1][2in]{%
\setlength{\unbalcolht}{#1}
\parindent0pt
\vspace{2ex}
\hspace{-2.8in}
\begin{minipage}[1]{9.5in}
\setbox0=\vtop\bgroup\setlength{\hsize}{\linewidth/3-1em}%
}{%
\vfill
\egroup
\splittopskip0pt
\setbox1=\vtop{\vsplit0 to \unbalcolht}
\setbox2=\vtop{\vsplit0 to \unbalcolht}
\setbox3=\vtop{\vsplit0 to \unbalcolht}
\hbox to \linewidth{%
    \vrule\hfil
    \box1%
    \hfil\vrule\hfil
    \box2%
    \hfil\vrule\hfil
    \box3%
    \hfil\vrule
}
\end{minipage}
\vspace{2ex}
}

\begin{document}

\lipsum[1]

\begin{unbalminicols}[1in]
This is the first column\breakit
This is the second column\breakit
This is the third column
\end{unbalminicols}

\lipsum[5]


\end{document}

and here is the output:

Corrected 3-column output.

The environment unbalminicols does the work. It takes an optional argument to adjust the height of the columns, the default being 2in. \breakit does the work of breaking the columns when necessary. If you only have, say, two columns of text, you'll need a \breakit to fill out the minipage.

There is a lot of plain TeX here, and I feel sure that there are better ways to do this. Hopefully this helps.


In my haste, I assumed four columns. My bad. I have updated the code (and screenshot) for three columns. Also demonstrated the optional argument: \begin{unbalminicols}[1in]

share|improve this answer

If I understand right, this is the way:

\documentclass[pagesize, DIV=calc, parskip=half]{scrartcl}
\usepackage{multicol, microtype, blindtext, lmodern}
\begin{document}
Here is text in one column.

\blindtext

\begin{addmargin}[-2cm]{-2cm}
  \begin{multicols}{3}
    \blindtext
  \end{multicols}
\end{addmargin}


\blindtext

\end{document}

If you do not use KOMA-script (you'd better do that!), then you get the addmargin environment with the scrextend package.

enter image description here

share|improve this answer
    
This is a very nice, clean solution. I like it. But, I still need to use a minipage because the text to be set in multiple columns should set in an environment with a restricted height. In other words, I'm using the minipage environment to achieve two effects: (1) changing the width of the typeset text, (2) changing the height of the multi-columnar text. –  A.Ellett Jul 11 '13 at 16:01
    
Also, I want to use unbalanced columns. –  A.Ellett Jul 11 '13 at 16:09
    
This environment is meant to be used with text that will not fill all the columns fully. The empty columns will provide work space for students to write in. Later I can reprint selected students' work and on the hand-out the visual effect will be that I did not change any formatting, only that I added text. With balanced columns, the appearance (to my students) will be that I've reformatted the text. With unbalanced columns, it'll look like I took the original document and just continued the type-setting from where it had been left off on the worksheet. –  A.Ellett Jul 11 '13 at 16:10
1  
@A.Ellett I don't comprehend what you are trying to do. Make a step back and edit your question: Don't describe technical details before giving a full picture of the layout of the page and who should write what to which area. –  Keks Dose Jul 11 '13 at 16:51
    
I've provided a full picture in the original question last night. I was just trying to explain why the need for all the empty columns. –  A.Ellett Jul 11 '13 at 17:32

Inspired by @egreg's solution, here's a slight generalization of what he suggested. It requires the environ package:

\documentclass{article}
\usepackage[
    top=0.35in,
    bottom=0.35in,
    width=4in,
    landscape,
    includefoot,
    includehead,
  ]{geometry}
\usepackage{fancyhdr}
\pagestyle{fancy}
\renewcommand{\headrulewidth}{0.4pt}
\renewcommand{\footrulewidth}{0.4pt}
\fancyhead[L]{Left}
\fancyhead[R]{Right}
%--------------------

\usepackage{environ}
\usepackage{pgfkeys}
\makeatletter
\newlength{\ae@width}
\newlength{\ae@hoffset}
\newlength{\ae@topsep}
\newlength{\ae@botsep}
\newlength{\ae@colheight}
\newlength{\ae@colsep}
\newlength{\ae@colrulewidth}
\pgfkeys{/ae/multi/columns/.cd,
  width/.code=\setlength\ae@width{#1},
  hoffset/.code=\setlength\ae@hoffset{#1},
  topsep/.code=\setlength\ae@topsep{#1},
  botsep/.code=\setlength\ae@botsep{#1},
  height/.code=\setlength\ae@colheight{#1},
  colsep/.code=\setlength\ae@colsep{#1},
  colrulewidth/.code=\setlength\ae@colrulewidth{#1},
}

\NewEnviron{aemulticol}[1][]
  {\pgfkeys{/ae/multi/columns/.cd,
    topsep=2ex,
    botsep=2ex,
    hoffset=-3in,
    width=2in,
    height=4in,
    colsep=2em,
    colrulewidth=0.4pt,
    #1}%%
   \vspace{\ae@topsep}\par
   \noindent
   \hspace*{\ae@hoffset}%%
   \makebox[0pt][l]{\ae@set@multi@cols}%%
   \vspace{\ae@botsep}\par
  }

\def\ae@set@multi@cols{%%
  \setbox0=\vbox{%%
    \hsize=\ae@width
    \BODY}%%
  \splittopskip=0pt
  \vbadness=10000\relax
  \ae@build@column
}

\def\ae@build@column{%%
  \setbox2=\vsplit0 to \ae@colheight 
  \vtop{%%
    \hrule height0pt 
    \unvbox2
  }%%
  \ifvoid0\relax\else
    \hspace{\dimexpr(\ae@colsep-\ae@colrulewidth)/2}%%
    \vrule width \ae@colrulewidth
    \hspace{\dimexpr(\ae@colsep-\ae@colrulewidth)/2}%%
    \expandafter\ae@build@column
  \fi}  

\makeatother

\begin{document}

  Alice was beginning to get very tired of sitting by her sister on
  the bank, and of having nothing to do. Once or twice she had peeped
  into the book her sister was reading, but it had no pictures or
  conversations in it, ``and what is the use of a book,'' thought
  Alice, ``without pictures or conversations?''
\begin{aemulticol}[width=2.75in,height=4.00in]
  So she was considering in her own mind (as well as she could, for
  the day made her feel very sleepy and stupid), whether the pleasure
  of making a daisy-chain would be worth the trouble of getting up and
  picking the daisies, when suddenly a White Rabbit with pink eyes ran
  close by her.

  There was nothing so very remarkable in that, nor did Alice think it
  so very much out of the way to hear the Rabbit say to itself, ``Oh
  dear! Oh dear! I shall be too late!'' But when the Rabbit actually
  took a watch out of its waistcoat-pocket and looked at it and then
  hurried on, Alice started to her feet, for it flashed across her
  mind that she had never before seen a rabbit with either a
  waistcoat-pocket, or a watch to take out of it, and, burning with
  curiosity, she ran across the field after it and was just in time to
  see it pop down a large rabbit-hole, under the hedge. In another
  moment, down went Alice after it!

  The rabbit-hole went straight on like a tunnel for some way and then
  dipped suddenly down, so suddenly that Alice had not a moment to
  think about stopping herself before she found herself falling down
  what seemed to be a very deep well.

  Either the well was very deep, or she fell very slowly, for she had
  plenty of time, as she went down, to look about her. First, she
  tried to make out what she was coming to, but it was too dark to see
  anything; then she looked at the sides of the well and noticed that
  they were filled with cupboards and book-shelves; here and there she
  saw maps and pictures hung upon pegs. She took down a jar from one
  of the shelves as she passed. It was labeled ``ORANGE MARMALADE,''
  but, to her great disappointment, it was empty; she did not like to
  drop the jar, so managed to put it into one of the cupboards as she
  fell past it.

  Down, down, down! Would the fall never come to an end? There was
  nothing else to do, so Alice soon began talking to
  herself. ``Dinah'll miss me very much to-night, I should think!''
  (Dinah was the cat.) ``I hope they'll remember her saucer of milk at
  tea-time. Dinah, my dear, I wish you were down here with me!'' Alice
  felt that she was dozing off, when suddenly, thump! thump! down she
  came upon a heap of sticks and dry leaves, and the fall was over.

  Alice was not a bit hurt, and she jumped up in a moment. She looked
  up, but it was all dark overhead; before her was another long
  passage and the White Rabbit was still in sight, hurrying down
  it. There was not a moment to be lost. Away went Alice like the wind
  and was just in time to hear it say, as it turned a corner, ``Oh, my
  ears and whiskers, how late it's getting!'' She was close behind it
  when she turned the corner, but the Rabbit was no longer to be seen.
\end{aemulticol}
  She found herself in a long, low hall, which was lit up by a row of
  lamps hanging from the roof. There were doors all 'round the hall,
  but they were all locked; and when Alice had been all the way down
  one side and up the other, trying every door, she walked sadly down
  the middle, wondering how she was ever to get out again.

  Suddenly she came upon a little table, all made of solid
  glass. There was nothing on it but a tiny golden key, and Alice's
  first idea was that this might belong to one of the doors of the
  hall; but, alas! either the locks were too large, or the key was too
  small, but, at any rate, it would not open any of them. However, on
  the second time 'round, she came upon a low curtain she had not
  noticed before, and behind it was a little door about fifteen inches
  high. She tried the little golden key in the lock, and to her great
  delight, it fitted!

\end{document}

enter image description here

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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