4

the following example shows that the self defined counter in the tabularx environment does not start with "1". Can't figure out how to define the command to always start with "1". Ideas?

\documentclass{article}

\usepackage{enumitem}
\usepackage{cleveref}
\usepackage{etoolbox}
\usepackage{booktabs}
\usepackage{ltxtable}
\usepackage{ltablex}

\makeatletter\newcommand*{%
\CreateCounterIfNotExists}[1]{\begingroup%
\@ifundefined{c@#1}{\newcounter{#1}}{}%
\endgroup}\makeatother

\def\sdef#1{\expandafter\def\csname#1\endcsname}
\newcommand\requirement[3]{%
\CreateCounterIfNotExists{my#1}%
\sdef{themy#1}{#1\arabic{my#1}}%
\refstepcounter{my#1}%
\label{#2} #1\arabic{my#1}: #3%
}

\begin{document}
\requirement{A}{req:foo:a}{Starts with 1}
\requirement{A}{req:foo:b}{continues with 2}
\requirement{B}{req:hop:a}{Starts with 1}
\requirement{B}{req:hop:b}{continues with 2}
\begin{tabularx}{\textwidth}{lX}
    \caption{Requirements}\\
    \label{tbl:reqs}\\
    \toprule
    \textbf{Area}& \textbf{Description}  \\\midrule
    \requirement{C}{req:bar:A}{Starts with 3}
    \requirement{C}{req:bar:B}{Continues with 4}
       & 
    This should start with C1    \\\midrule
\end{tabularx}
\end{document}
  • cleveref should be the last package, in most cases, but this is not the cause of your problems. Why do you think, it should start with 1 using tabularx? – user31729 Apr 21 '15 at 21:06
  • By the way, you could use the \ifltxcounter from etoolbox to test for the counter – user31729 Apr 21 '15 at 21:13
4

You can't define counters while tabularx does its job.

A solution may be to define the one you need in a tabularx beforehand, or do it in a delayed fashion using the .aux file.

\documentclass{article}

\usepackage{enumitem}
\usepackage{etoolbox}
\usepackage{booktabs}
\usepackage{ltxtable}
\usepackage{ltablex}
\usepackage{cleveref}

\makeatletter
\newcommand\requirement[3]{%
  \protected@write\@auxout{}{\string\CreateCounter{#1}}%
  \@ifundefined{c@my#1}
    {#1??: #3}
    {\refstepcounter{my#1}\label{#2}#1\arabic{my#1}: #3}%
}
\newcommand{\CreateCounter}[1]{%
  \@ifundefined{c@my#1}
    {\newcounter{my#1}\global\@namedef{themy#1}{#1\arabic{my#1}}}
    {}%
}
\AtEndDocument{\let\CreateCounter\@gobble}
\makeatother

\begin{document}
{\requirement{A}{req:foo:a}{Starts with 1}}
\requirement{A}{req:foo:b}{continues with 2}
\requirement{B}{req:hop:a}{Starts with 1}
\requirement{B}{req:hop:b}{continues with 2}

\noindent
\begin{tabularx}{\textwidth}{lX}
\caption{Requirements}\label{tbl:reqs}\\
\toprule
\textbf{Area}& \textbf{Description}  \\
\midrule
\requirement{C}{req:bar:A}{Starts with 1}
\requirement{C}{req:bar:B}{Continues with 2} & This should start with C1 \\
\midrule
\end{tabularx}

\end{document}

enter image description here

The first time \requirement{X} is used, the number won't be generated, but it will at the next LaTeX run.

  • Splendid. I like this solution most since it doesn't require to define a list of envisioned/used requirements in the preamble. – Alex Apr 22 '15 at 6:37
  • One more thing, if I add the line This ref should be named "C1": \ref{req:bar:A}. But it's called "1". to the end of your example it shows that the references have no prefix anymore. – Alex Apr 22 '15 at 7:06
  • @Alex Sorry, \global missing. – egreg Apr 22 '15 at 8:00
3

You should almost never declare a counter within a macro, it should be declared once in the preamble and just used. then tabularx would know about it and preserve its value when doing trial width settings.

\documentclass{article}

\usepackage{enumitem}
\usepackage{cleveref}
\usepackage{etoolbox}
\usepackage{booktabs}
\usepackage{ltxtable}
\usepackage{ltablex}

\newcounter{myA}\renewcommand\themyA{A\arabic{myA}}
\newcounter{myB}\renewcommand\themyB{B\arabic{myB}}
\newcounter{myC}\renewcommand\themyC{C\arabic{myC}}



\newcommand\requirement[3]{%
\refstepcounter{my#1}%
\label{#2}#1\arabic{my#1}: #3%
}

\begin{document}
\requirement{A}{req:foo:a}{Starts with 1}
\requirement{A}{req:foo:b}{continues with 2}
\requirement{B}{req:hop:a}{Starts with 1}
\requirement{B}{req:hop:b}{continues with 2}
\begin{tabularx}{\textwidth}{lX}
    \caption{Requirements}\\
    \label{tbl:reqs}\\
    \toprule
    \textbf{Area}& \textbf{Description}  \\\midrule
    \requirement{C}{req:bar:A}{Starts with 3}
    \requirement{C}{req:bar:B}{Continues with 4}
       & 
    This should start with C1    \\\midrule
\end{tabularx}
\end{document}
  • Thank you very much! Very clean and compact. However, defining the counters in the header is not as handy as the solution provided by egreg, since you've to know beforehand which counters to use the in document. – Alex Apr 22 '15 at 6:39
2

As in the solutions by David Carlisle and egreg mentioned: counters should not be defined on-the-fly.

I used a similar approach as David Carlisle, providing a \NewDocumentCounter, \DeclareRequirement, DeclareRequirements commands which can be used in preamble only, to prevent accidental usage.

\documentclass{article}

\usepackage{enumitem}
\usepackage{etoolbox}
\usepackage{booktabs}
\usepackage{ltxtable}
\usepackage{ltablex}
\usepackage{cleveref}

\usepackage{xparse}

\NewDocumentCommand{\NewDocumentCounter}{m}{%
  \ifltxcounter{#1}{%
  }{%
    \typeout{Creating counter #1}
    \newcounter{#1}%
  } 
}

\NewDocumentCommand{\DeclareRequirement}{m}{%
  \NewDocumentCounter{my#1}%
  \expandafter\renewcommand\csname themy#1\endcsname{#1\arabic{my#1}}
}%

    \listgadd\reqlist{}


\NewDocumentCommand{\DeclareRequirements}{+m}{%
  \forcsvlist{\listgadd\reqlist}{#1}
  \forlistloop{\DeclareRequirement}{\reqlist}
}%



\makeatletter
\@onlypreamble{\NewDocumentCounter}
\@onlypreamble{\DeclareRequirement}
\@onlypreamble{\DeclareRequirements}
\makeatother




\DeclareRequirements{A,B,C} % Declare all requirement counters in a row ... 


\newcommand\requirement[3]{%
  \refstepcounter{my#1}%
  \label{#2} #1\arabic{my#1}: #3%
}

\begin{document}
\requirement{A}{req:foo:a}{Starts with 1}
\requirement{A}{req:foo:b}{continues with 2}
\requirement{B}{req:hop:a}{Starts with 1}
\requirement{B}{req:hop:b}{continues with 2}
\begin{tabularx}{\textwidth}{lX}
    \caption{Requirements}\\
    \label{tbl:reqs}\\
    \toprule
    \textbf{Area}& \textbf{Description}  \\\midrule
    \requirement{C}{req:bar:A}{Starts with 3 no longer} %\themyC
    \requirement{C}{req:bar:B}{Continues with 4 no longer} %\themyC
    & 
    This should start with C1    \\\midrule
  \end{tabularx}
\end{document}
  • Thanks, tested and it works. But declaring the possible requirements/counters in the preamble was something I wanted to avoid. – Alex Apr 22 '15 at 6:40

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.