10

I'm setting up a little test, which includes empty boxes for students to write their answers.

The boxes start at different places on the page, but I'd like - for neatness - each box to reach to the end of the line. I'm using

\newcommand{\answerbox[2]{\raisebox{2mm}{%
    \fbox{%
          \begin{minipage}[t]{#1}%
              \hfill\vspace*{#2}%
          \end{minipage}
         }
    }
}

which works well, but I have to guess at the box width (first parameter). Is there a cunning way of using rules and hfill to do this?

Alasdair
  • 5,257
  • 4
  • 38
  • 64
  • 1
    I've tried the suggestions given - and many many thanks to all of you - but none are 100% robust. They especially seem to fall down in itemize environments, where \item Write something \answerbox{2cm} may or may not reach the right hand margin. – Alasdair Feb 23 '15 at 03:02
  • Maybe \dotfill or \hrulefill are a solution (see also https://tex.stackexchange.com/a/155960). And there is the excellent package exam, even though it has no perfect solution for this question. – hplieninger Jun 07 '17 at 15:42

5 Answers5

4

Hopefully someone can come along and improve upon this. But here's a start.

One trick is to use the construct:

$$\xdef\pds{\the\predisplaysize}$$

which will obtain the width up to where the previous line ended (with some adjustments, see section 24.3 of "TeX by Topic" for further details). This may seem an odd approach, but this is how to put it into action:

\newcommand\answerbox[1]{%%
  \bgroup 
    \abovedisplayskip0pt%%
    \belowdisplayskip0pt%%
    \abovedisplayshortskip0pt%% 
    \belowdisplayshortskip0pt%%
    $$\xdef\pds{\the\predisplaysize}$$%
  \par\prevdepth0pt{\par\kern-2\baselineskip\parskip0pt}%%
  \noindent
  \kern\pds\kern-2em\fbox{%%
    \rule{\dimexpr\linewidth-\pds+2em-2\fboxrule-2\fboxsep}{0pt}%%
    \rule{0pt}{#1}}%%
  \egroup}

In this, the grouping is necessary to restrict the adjusted values of the \abovedisplayskip et al. to the scope of your macro.

Regarding the adjustments of 2em, see section 24.3 of TeX by Topic.

\documentclass{article}
\usepackage{pgffor}
\setlength\parindent{0pt}
\usepackage{lipsum}

\newcommand\answerbox[1]{%%
  \bgroup 
    \abovedisplayskip0pt%%
    \belowdisplayskip0pt%%
    \abovedisplayshortskip0pt%% 
    \belowdisplayshortskip0pt%%
    $$\xdef\pds{\the\predisplaysize}$$%
  \par\prevdepth0pt{\par\kern-2\baselineskip\parskip0pt}%%
  \noindent
  \kern\pds\kern-2em\fbox{%%
    \rule{\dimexpr\linewidth-\pds+2em-2\fboxrule-2\fboxsep}{0pt}%%
    \rule{0pt}{#1}}%%
  \egroup}

\begin{document}

\foreach \myn in {0,5,10,15,20,25}
  {
    \par
    \foreach \myk in {0,...,\myn} {a }%%
    \answerbox{2ex}\vspace{2ex}%%
  }

\lipsum[1-2]

\end{document}

enter image description here

The use of pgffor and lipsum are merely for presentation and not necessary for the macro \answerbox.

A.Ellett
  • 50,533
4

You can use \linegoal from the linegoal package to calculate the remaining space (compile the document twice):

\documentclass{article}
\usepackage{linegoal}
\usepackage{lipsum}% just to have filler text

\newcommand\answerbox[1][0.5\ht\strutbox]{\raisebox{0.25\height}{%
  \fbox{\begin{minipage}[t]{\dimexpr-\fboxsep-\fboxrule+\linegoal\relax}%
    \mbox{}\rule{0pt}{#1}%
  \end{minipage}%
    }%
  }%
} 

\begin{document}

\noindent
test \answerbox

\noindent
other test text \answerbox

\noindent
some other test with a longer text \answerbox

\lipsum[4]

\end{document}

enter image description here

Gonzalo Medina
  • 505,128
3

Here I make a box using \cleaders. The parameters \boxht, \boxdp and \rulewidth are settable by the user.

To make it so that no additional text is squeezed after the box, the \boxfill should be followed with a \par (as I have done here) or a \\.

EDITED to remove the need for packages.

\documentclass{article}
\usepackage{lipsum}
\newcommand\rulewidth{1pt}
\newcommand\boxht{2ex}
\newcommand\boxdp{3pt}
\newcommand\boxfill{%
  \let\replength\rulewidth
  \def\laprule{\rule[-\boxdp]{\rulewidth}{\dimexpr\boxht+\boxdp+\rulewidth\relax}}%
  \makebox[0pt][l]{\laprule}%
  \cleaders\hbox to \replength{%
    \ooalign{\rule[-\boxdp]{\replength}{\rulewidth}\cr%
             \rule[\boxht]{\replength}{\rulewidth}}}\hfill%
  \makebox[0pt][r]{\laprule}%
}
\begin{document}
A test\boxfill\par
This is another test of the fill when it doesn't begin on the first
line of a paragraph.\boxfill\par
\boxfill\par
\lipsum[1]
\end{document}

enter image description here

2

Here's another approach, using this time TikZ and a node with the desired width; the width is calculates with the help of the tikzpagenodes package and the tikzmark library (compile the document two or three times to stabilize):

\documentclass{article}
\usepackage{tikzpagenodes}
\usetikzlibrary{tikzmark,calc}
\usepackage{lipsum}% just to have filler text

\newcounter{tmp}

\newcommand\answerbox[1][\ht\strutbox]{%
  \stepcounter{tmp}%
  \tikzmark{startbox-\thetmp}%
  \tikz[remember picture,overlay,baseline=(box.south)] 
  \path let 
    \p1=(pic cs:start-\thetmp),
    \p2=(current page text area.east) in
  node[
    draw,
    anchor=west,
    minimum height=#1,
    inner sep=0pt,
    outer sep=0pt,
    text width=\x2-\x1] (box)
  {};
} 

\begin{document}

\noindent
test \answerbox

\noindent
other test text \answerbox

\noindent
some other test with a longer text \answerbox

\lipsum[4]

\end{document}

enter image description here

Gonzalo Medina
  • 505,128
1

Here is a zref (module savepos) implementation:

enter image description here

\documentclass{article}
\usepackage{zref-savepos,lipsum}
\newcounter{boxmarker}% Position marker counter
\newcommand{\boxfill}{%
  \leavevmode% Just in case...
  \stepcounter{boxmarker}% To avoid multiple references
  \zsaveposx{boxmarkerL\theboxmarker}% Save left location
  \hfill
  \zsaveposx{boxmarkerR\theboxmarker}% Save right location
  \llap{% Left overlap
    \fbox{% framed box
      \rule{0pt}{.5\baselineskip}% Vertical strut
      \rule{\dimexpr\zposx{boxmarkerR\theboxmarker}sp-\zposx{boxmarkerL\theboxmarker}sp-2\fboxsep-2\fboxrule}{0pt}% Horizontal strut
    }%
  }%
}
\begin{document}
A test \boxfill

This is another test of the fill when it doesn't begin on the first
line of a paragraph. \boxfill

\boxfill

\lipsum[1]

\end{document}

The above approach uses some techniques from Skip to absolute position on line. Essentially two locations are marked and labelled with a call to \boxfill. These <label>s store the x-coordinate of the marker in the .aux, which is retrieved via \zposx{<label>} and then used to calculate the remainder on the line.

Since it uses TeX's \label-\ref system, you have to compile at least twice at the start, and twice for every subsequent adjustment of the marker locations (to allow references to settle).

Werner
  • 603,163