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.

What I want to do is to show a "progress bar" in the header to show how far you are in the document, by making a rule with width pagenumber divided by total pages times the paper width.

This is what I have:

\usepackage{fancyhdr,lastpage}
\pagestyle{fancy}
\lhead{\rule{\value{page}/\value{\pageref{LastPage}}*120mm}{2mm}}

but obviously it doesn't work.

share|improve this question
3  
I hope you don't mind that I changed your title to better reflect the real problem, for the benefit of people of the future having similar problems and searching the archives. –  Lev Bishop Oct 17 '10 at 15:31
add comment

6 Answers

up vote 21 down vote accepted

Solving this kind of problem is the raison d'être of the refcount package. Here's one way to use it:

\documentclass[oneside]{book}
\usepackage{lipsum,fancyhdr,lastpage,refcount}
\pagestyle{fancy}
\setrefcountdefault{-1}
\lhead{\rule{\dimexpr \textwidth * \thepage/\getpagerefnumber{LastPage}}{2mm}}
\begin{document}
\lipsum[1-60] %Insert dummy text for demonstration
\end{document}
share|improve this answer
1  
As much as I like TH's answer, I think this is a perfect example of why it is good to wait a bit before accepting an answer. –  Hendrik Vogt Oct 17 '10 at 7:01
    
@Hendrik Vogt: I believe he can (and should) change his answer. Mine is clearly inferior to Lev's. –  TH. Oct 17 '10 at 8:16
1  
@Edootjuh, did you forget to include the \setrefcountdefault{-1} line? It's purpose is to deal with this issue, by avoiding the divide-by-zero that would otherwise occur when the LastPage label is undefined. –  Lev Bishop Nov 2 '10 at 5:08
1  
@Lev Bishop: No, it's there. The strange thing about it is that the error occurs on page 63. –  Edo Mangelaars Nov 3 '10 at 14:41
1  
@Edootjuh, OK I see. The problem is that TeX's maximum allowed dimension is 2^30 sp, or about 19ft. Try \setrefcountdefault{1000} to avoid it –  Lev Bishop Nov 4 '10 at 1:48
show 3 more comments

The code of Lev will break if the page number is not a number, e.g. with \pagenumbering{Roman}. I would use the zref package:

\documentclass[oneside]{book}
\usepackage{lipsum,fancyhdr}
\pagestyle{fancy}
\usepackage[lastpage]{zref}
\pagenumbering{Roman}
\makeatletter
\zref@newprop*{numpage}{\the\value{page}}
\zref@addprop{main}{numpage}
\lhead{\rule{\dimexpr \textwidth * \the\value{page}/\zref@extractdefault{LastPage}{numpage}{1}}{2mm}}
\makeatother
\begin{document}
\lipsum[1-60] %Insert dummy text for demonstration
\end{document}

(Instead of the new property "numpage" one could also use "abspage" if the absolute page number is wanted.)

share|improve this answer
    
Couldn't I use \value{\thepage} and \value{\pageref{LastPage}} then? –  Edo Mangelaars Oct 18 '10 at 15:55
    
Well why don't you try it? (But no, it will not work, the argument of \value must be the name of counter.) –  Ulrike Fischer Oct 18 '10 at 17:53
    
@UlrikeFischer Brilliant! I have adapted the code to test if a document has one or more pages, and remove the page number if it is only one page (\thispagestyle{empty}), but keep page number on the first page if the document has two or more pages. Thank you! –  Sveinung May 21 '12 at 13:44
add comment

It's slightly tricky to do this since you need to unroll what \pageref does, but what you need to do basically boils down to this.

\newcount\lastpagecount
\makeatletter
\AtBeginDocument{%
        \expandafter\ifx\csname r@LastPage\endcsname\relax
                \lastpagecount\m@ne
        \else
                \lastpagecount\expandafter\@secondoftwo\r@LastPage\relax
        \fi
}
\lhead{%
        \begingroup
                \ifnum\c@page>\lastpagecount
                        \count@\c@page
                \else
                        \count@\lastpagecount
                \fi
                \dimen@\dimexpr 120mm * \c@page/\count@\relax
                \rule{\dimen@}{2mm}%
        \endgroup
}
\makeatother

The code being passed to \AtBeginDocument checks to see if the LastPage reference has been set. If it hasn't, it sets the \lastpagecount to -1. If it has, then it sets \lastpagecount to be the value of the last page.

Then, in \lhead, \count@ is set to the maximum of the current page and the last page. Note that it's possible for the current page to be greater than the last page because you need to compile at least twice to find the real last page number. Then it uses \dimexpr ... \relax to compute the length of the rule.

This didn't get extensive testing, but it seems to work.

share|improve this answer
    
Thanks! It works perfectly! –  Edo Mangelaars Oct 16 '10 at 18:18
add comment

This one is tricky, unfortunately catching me and I'm guessing a few others out by the way it was originally framed. Edootjuh's problem has nothing to do with whether calc (or in fact whether \dimexpr) can execute a divide. It (they) can. Rather, it has to do with whether \pageref{LastPage} (or as far as I can work out, any expression based on \pageref{LastPage}) can stand as an operand in the divide.

The problem is trivially solved if (as in Aditya's contribution) the last page number is hard-coded as a literal. It is much less easily solved if this value is pulled in via a \pageref to a label. Ultimately, the problem that needs to be solved is this:

\documentclass{article}
\usepackage{fancyhdr}
\usepackage{calc}
\usepackage{lipsum}

\pagestyle{fancy}
\lhead{\rule{\textwidth * \thepage / 6}{2mm}}                     % <-- works fine, trivial solution
%\lhead{\rule{\textwidth * \thepage / \pageref{LastPage}}{2mm}}   % <-- any form of reference to a label fails

\begin{document}
\pageref{LastPage}

\rule{\dimexpr 120mm*1/6 \relax}{2mm}   % solution requires reference to LastPage label rather than a hard-coded literal here 

\lipsum[1-30]
\label{LastPage}
\end{document}
share|improve this answer
1  
You're absolutely right. That's where I got hung up last night. Fortunately, the solution isn't too complicated but it does depend on how references are implemented. –  TH. Oct 16 '10 at 12:56
add comment

OK, you got already 4 answers, but to give still more options to other people looking up the question:

As you already are useing the lastpage package, you can also use \lastpage@lastpage (at least with the recent version 1.2k):

\documentclass[oneside]{book}
\usepackage{fancyhdr,lastpage}
\pagestyle{fancy}
\makeatletter
\def\lastpage@lastpage{1000}% because \lastpage@lastpage is undefined before
% the .aux file has been loaded at the begin of the document
% (and during the first compilation run).
\lhead{\rule{\dimexpr \textwidth*\thepage/\lastpage@lastpage \relax}{2mm}}%
\makeatother
\usepackage{lipsum}
\begin{document}
\lipsum[1-60] % inserts dummy text for demonstration.
\end{document}

BUT when another pagenumbering scheme (e.g. Roman) is used, or the pagenumbers are reset, this will not work, e.g. \lastpage@lastpage could be X (Roman for 10), and pages put out with \AtEndDocument might not be counted (depending on loading order of the packages). In those cases the pageslts package (v1.2a) could be used:

\documentclass[oneside]{book}
\usepackage{fancyhdr,pageslts}
\setcounter{pagesLTS.pagenr}{1000}
% because pagesLTS.pagenr is zero before
% the .aux file has been loaded at the begin of the document
% (and during the first compilation run).
\pagestyle{fancy}
\lhead{\rule{\dimexpr \textwidth*\theCurrentPage/\the\value{pagesLTS.pagenr}\relax}{2mm}}%
\usepackage{lipsum}
\begin{document}
\pagenumbering{arabic}
\lipsum[1-30] % inserts dummy text for demonstration.
\clearpage
\pagenumbering{Roman}
\lipsum[31-60] % inserts dummy text for demonstration.
\end{document}

(I also replace the fixed 120mm by \textwidth.)

share|improve this answer
add comment

As to the problem of "using pageref as a number", but not the "progress bar problem": there's a fine solution here. And for the record, here's a way to increase the reference of pageref by 1:

\usepackage{refcount}

\newcommand{\incpageref}[1]{%
  \number\numexpr\getpagerefnumber{#1} + 1}

\incpagere takes label as an argument.

share|improve this answer
add comment

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.