如何交叉引用不同計數器的標題?

如何交叉引用不同計數器的標題?

我想定義一種靈活的方式,將原始程式碼和/或圖形包含到充當浮動圖形環境的群組中。

這個想法是能夠使用type命令的參數選擇計數器\insertCaption。如果是“Listing”,則使用計數器,如果是“Figure”,則使用另一個計數器。

我面臨的問題是我無法正確選擇計數器。它在標題中顯示良好,但每當我引用該群組時,它都不會顯示正確的編號。

\documentclass{book}
\usepackage{geometry}
\geometry{margin=0.2in,papersize={8.5in,11in}}
\usepackage{graphicx}
\usepackage{pgfkeys}
\usepackage{subcaption}
\usepackage{ifthen}
\usepackage{listings}
\usepackage{xcolor}
\definecolor{lightgray}{gray}{0.9}

\makeatletter

\pgfkeys{/fig/entities/.cd,
    file/.initial={},
    width/.initial={},
    caption/.initial={},
    label/.initial={},
}
\def\fig@set@keys#1{\pgfkeys{/fig/entities/.cd,#1}}
\def\fig@get#1{\pgfkeysvalueof{/fig/entities/#1}}
\def\fig@set@defaults{\pgfkeys{/fig/entities/.cd,
    file/.initial={DUMMY},
    width/.initial={0.6},
    caption/.initial={},
    label/.initial={},
}}
\newcommand\insertFigure[1]{%%
    \fig@set@defaults%%
    \fig@set@keys{#1}%%
    \bgroup\begin{subfigure}[b]{\fig@get{width}\textwidth}%%
        \centering%%
        \includegraphics[width=1\textwidth]{\fig@get{file}}%%
        \ifthenelse{\NOT\equal{\fig@get{caption}}{}}{%%
            \ifthenelse{\equal{\fig@get{caption}}{abc}}{%%
                \caption{}%%
            }{%%
                \caption{\fig@get{caption}}%%
            }%%
            \ifthenelse{\NOT\equal{\fig@get{label}}{}}{%%
                \label{\fig@get{label}}%%
            }{}%%
        }{}%%
    \end{subfigure}\egroup%%
}


\pgfkeys{/code/entities/.cd,
    file/.initial={},
    width/.initial={},
    caption/.initial={},
    label/.initial={},
}
\def\code@set@keys#1{\pgfkeys{/code/entities/.cd,#1}}
\def\code@get#1{\pgfkeysvalueof{/code/entities/#1}}
\def\code@set@defaults{\pgfkeys{/code/entities/.cd,
    file/.initial={DUMMY},
    width/.initial={0.6},
    caption/.initial={},
    label/.initial={},
}}
\newcommand\insertCode[1]{%%
    \code@set@defaults%%
    \code@set@keys{#1}%%
    \bgroup\begin{subfigure}[b]{\code@get{width}\textwidth}%%
        \centering%%
        \fcolorbox{lightgray}{lightgray}{%%
            \begin{minipage}[t]{0.98\textwidth}
                \hspace{0pt}\vspace{-1pt}%% hack to align \fbox with \lstinputlisting.
                \lstinputlisting[basicstyle=\ttfamily\scriptsize]%%
                                {\code@get{file}}%%
            \end{minipage}%%
        }%%
        \ifthenelse{\NOT\equal{\code@get{caption}}{}}{%%
            \ifthenelse{\equal{\code@get{caption}}{abc}}{%%
                \caption{}%%
            }{%%
                \caption{\code@get{caption}}%%
            }%%
            \ifthenelse{\NOT\equal{\code@get{label}}{}}{%%
                \label{\code@get{label}}%%
            }{}%%
        }{}%%
    \end{subfigure}\egroup%%
}


\pgfkeys{/capt/entities/.cd,
    type/.initial={},
    caption/.initial={},
    label/.initial={},
}
\def\capt@set@keys#1{\pgfkeys{/capt/entities/.cd,#1}}
\def\capt@get#1{\pgfkeysvalueof{/capt/entities/#1}}
\def\capt@set@defaults{\pgfkeys{/capt/entities/.cd,
    type/.initial={Figure},
    caption/.initial={},
    label/.initial={},
}}
% counter for captions of type 'Figure' and 'Listing'
\newcounter{figurecounter}[chapter]
\newcounter{codecounter}[chapter]
\DeclareCaptionLabelFormat{figurefmt}{Figure~\thechapter.\thefigurecounter}
\DeclareCaptionLabelFormat{codefmt}{Listing~\thechapter.\thecodecounter}

\newcommand\insertCaption[1]{%%
    \capt@set@defaults%%
    \capt@set@keys{#1}%%
    \ifthenelse{\NOT\equal{\capt@get{caption}}{}}{%%
        \ifthenelse{\equal{\capt@get{type}}{Listing}}{%%
            \captionsetup{name=Listing}%%
            \refstepcounter{codecounter}%%
            \captionsetup{labelformat=codefmt}%%
        }{%%
            \captionsetup{name=Figure}%%
            \refstepcounter{figurecounter}%%
            \captionsetup{labelformat=figurefmt}%%
        }%%
        \ifthenelse{\equal{\capt@get{caption}}{abc}}{%%
            \caption{}%%
        }{%%
            \caption{\capt@get{caption}}%%
        }%%
        \ifthenelse{\NOT\equal{\capt@get{label}}{}}{%%
            \label{\capt@get{label}}%%
        }{}%%
    }{}%%
}

\newcommand\FloatingElements[1]{%%
    \begin{figure}[h!]\centering#1\end{figure}%%
}

\begin{document}
\chapter{Chapter One}
\FloatingElements{
  \insertFigure{
    file={figA},
    width=0.2,
    caption={abc},
  }\hfil%%
  \insertCode{
    file={textA.txt},
    width=0.3,
    caption={abc},
    label={the-first-text}
  }%%
  \insertCaption{
    type=Figure,
    caption={This is a figure with some text, use the Figure counter.},
    label={group1},
  }%%
}

\FloatingElements{
  \insertCode{
    file={textB.txt},
    width=0.8,
  }%%
  \insertCaption{
    type=Listing,
    caption={This is just text B, so use the Listing counter.},
    label={group2},
  }%%
}

\FloatingElements{
  \insertFigure{
    file={figB},
    width=0.2,
  }%%
  \insertCaption{
    type=Figure,
    caption={This is just a figure, so use the Figure counter.},
    label={group3},
  }%%
}

\FloatingElements{
  \insertCode{
    file={textC.txt},
    width=0.2,
    caption={abc},
    label={text-c}
  }\hfil%%
  \insertCode{
    file={textD.txt},
    width=0.2,
    caption={abc},
  }%%
  \insertCaption{
    type=Listing,
    caption={These are texts C and D, so use the Listing counter.},
    label={group4},
  }%%
}

\textbf{Cross references:}\\
Figure~\ref{group1} has the figureA and textA. Listing~\ref{the-first-text} is within the same Figure~\ref{group1}.\\
Listing~\ref{group2} only has the textB.\\
Figure~\ref{group3} only has the figureB.\\
Listing~\ref{group4} has the texts C and D. And sub-listing~\ref{text-c} is textC.

\end{document}

假設文字和圖像檔案都在那裡,我得到以下 pdf:

從上面的程式碼得到的PDF

可以看出,標題和交叉引用中的數字不符。

答案1

我不提供解決方案,因為您還沒有弄清楚您是將其用作學習練習還是實際用途,所以我不知道該給出哪種答案。

這是「為什麼?」的回答。而不是“如何?”

每次您在環境\caption中使用時figurefigure計數器都會增加。資訊寫入.aux文件以供交叉引用等使用。

您已經更改了標題標籤格式的外觀,但尚未觸及所使用的計數器。您的格式不使用所使用的計數器。也就是說,它不使用figure.所以你看不到figure環境本身所使用的價值。您只能看到您的自訂計數器。但這些並沒有用於交叉引用。因此,當您稍後引用它時,您將獲得寫入 的信息.aux,它使用figure.並且您指定的格式此處未激活,因此這次使用計數器的值。

要了解發生了什麼,請查看.aux

\relax
\@writefile{toc}{\contentsline {chapter}{\numberline {1}Chapter One}{1}{}\protected@file@percent }
\@writefile{lof}{\addvspace {10\p@ }}
\@writefile{lot}{\addvspace {10\p@ }}
\@writefile{lol}{\contentsline {lstlisting}{indentfirst.sty}{1}{}\protected@file@percent }
\providecommand*\caption@xref[2]{\@setref\relax\@undefined{#1}}
\newlabel{the-first-text}{{1.1b}{1}{}{}{}}
\newlabel{sub@the-first-text}{{b}{1}{}{}{}}

請注意,這些使用的是我們所期望的。

\@writefile{lof}{\contentsline {figure}{\numberline {1.1}{\ignorespaces This is a figure with some text, use the Figure counter.}}{1}{}\protected@file@percent }
\newlabel{group1}{{1.1}{1}{}{}{}}

這是我們的第一個數字。

\@writefile{lol}{\contentsline {lstlisting}{indentfirst.sty}{2}{}\protected@file@percent }
\@writefile{lof}{\contentsline {figure}{\numberline {1.2}{\ignorespaces This is just text B, so use the Listing counter.}}{2}{}\protected@file@percent }
\newlabel{group2}{{1.2}{2}{}{}{}}

在這裡我們看到為第二個浮點數寫入的資訊。請注意,寫入的值.aux正在使用figure計數器,即使在標題格式的任何地方都沒有使用它。

\@writefile{lof}{\contentsline {figure}{\numberline {1.3}{\ignorespaces This is just a figure, so use the Figure counter.}}{2}{}\protected@file@percent }
\newlabel{group3}{{1.3}{2}{}{}{}}
\@writefile{lol}{\contentsline {lstlisting}{indentfirst.sty}{3}{}\protected@file@percent }

現在我們得到3第三個浮點數。同樣, 的值figure不用於排版標題。

\newlabel{text-c}{{1.4a}{3}{}{}{}}
\newlabel{sub@text-c}{{a}{3}{}{}{}}

再次,我們讓figure計數器遞增,儘管這並不意味著是,figure因為它發生在figure環境內部。

\@writefile{lol}{\contentsline {lstlisting}{indentfirst.sty}{3}{}\protected@file@percent }
\@writefile{lof}{\contentsline {figure}{\numberline {1.4}{\ignorespaces These are texts C and D, so use the Listing counter.}}{3}{}\protected@file@percent }
\newlabel{group4}{{1.4}{3}{}{}{}}
\gdef \@abspage@last{3}

如果您希望查看已編譯文件中發生的情況,這裡的一些程式碼可能會有所幫助。你必須編譯它,因為我的圖像由於 Okular 錯誤而無法使用。請注意:實際輸出非常難看。

% WHY? NOT HOW?
\documentclass{book}
\usepackage{geometry}
\geometry{margin=0.2in,papersize={8.5in,11in}}
\usepackage[draft]{graphicx}
\usepackage{pgfkeys}
\usepackage{subcaption}
\usepackage{ifthen}
\usepackage{listings}
\usepackage{xcolor}
\definecolor{lightgray}{gray}{0.9}

\makeatletter

\pgfkeys{/fig/entities/.cd,
    file/.initial={},
    width/.initial={},
    caption/.initial={},
    label/.initial={},
}
\def\fig@set@keys#1{\pgfkeys{/fig/entities/.cd,#1}}
\def\fig@get#1{\pgfkeysvalueof{/fig/entities/#1}}
\def\fig@set@defaults{\pgfkeys{/fig/entities/.cd,
    file/.initial={DUMMY},
    width/.initial={0.6},
    caption/.initial={},
    label/.initial={},
}}
\newcommand\insertFigure[1]{%%
  \fig@set@defaults%%
  \fig@set@keys{#1}%%
  \bgroup\begin{subfigure}[b]{\fig@get{width}\textwidth}%%
    \centering%%
    \includegraphics[width=1\textwidth]{\fig@get{file}}%%
    \ifthenelse{\NOT\equal{\fig@get{caption}}{}}{%%
      \ifthenelse{\equal{\fig@get{caption}}{abc}}{%%
        \caption{}%%
      }{%%
        \caption{\fig@get{caption}}%%
      }%%
      \ifthenelse{\NOT\equal{\fig@get{label}}{}}{%%
        \label{\fig@get{label}}%%
      }{}%%
    }{}%%
  \end{subfigure}\egroup%%
}


\pgfkeys{/code/entities/.cd,
    file/.initial={},
    width/.initial={},
    caption/.initial={},
    label/.initial={},
}
\def\code@set@keys#1{\pgfkeys{/code/entities/.cd,#1}}
\def\code@get#1{\pgfkeysvalueof{/code/entities/#1}}
\def\code@set@defaults{\pgfkeys{/code/entities/.cd,
    file/.initial={DUMMY},
    width/.initial={0.6},
    caption/.initial={},
    label/.initial={},
}}
\newcommand\insertCode[1]{%%
  \code@set@defaults%%
  \code@set@keys{#1}%%
  \bgroup\begin{subfigure}[b]{\code@get{width}\textwidth}%%
    \centering%%
    \fcolorbox{lightgray}{lightgray}{%%
      \begin{minipage}[t]{0.98\textwidth}
        \hspace{0pt}\vspace{-1pt}%% hack to align \fbox with \lstinputlisting.
        \lstinputlisting[basicstyle=\ttfamily\scriptsize]%%
        {\code@get{file}}%%
      \end{minipage}%%
    }%%
    \ifthenelse{\NOT\equal{\code@get{caption}}{}}{%%
      \ifthenelse{\equal{\code@get{caption}}{abc}}{%%
        \caption{}%%
      }{%%
        \caption{\code@get{caption}}%%
      }%%
      \ifthenelse{\NOT\equal{\code@get{label}}{}}{%%
        \label{\code@get{label}}%%
      }{}%%
    }{}%%
  \end{subfigure}\egroup%%
}


\pgfkeys{/capt/entities/.cd,
  type/.initial={},
  caption/.initial={},
  label/.initial={},
}
\def\capt@set@keys#1{\pgfkeys{/capt/entities/.cd,#1}}
\def\capt@get#1{\pgfkeysvalueof{/capt/entities/#1}}
\def\capt@set@defaults{\pgfkeys{/capt/ent    type/.initial={Figure},
    caption/.initial={},
    label/.initial={},ities/.cd,
    type/.initial={Figure},
    caption/.initial={},
    label/.initial={},
}}
% counter for captions of type 'Figure' and 'Listing'
\newcounter{figurecounter}[chapter]
\newcounter{codecounter}[chapter]
\DeclareCaptionLabelFormat{figurefmt}{Figure~\thechapter.\thefigurecounter}
\DeclareCaptionLabelFormat{codefmt}{Listing~\thechapter.\thecodecounter}

\newcommand\insertCaption[1]{%%
  \capt@set@defaults%%
  \capt@set@keys{#1}%%
  \ifthenelse{\NOT\equal{\capt@get{caption}}{}}{%%
    \ifthenelse{\equal{\capt@get{type}}{Listing}}{%%
      \captionsetup{name=Listing}%%
      \refstepcounter{codecounter}%%
      \captionsetup{labelformat=codefmt}%%
    }{%%
      \captionsetup{name=Figure}%%
      \refstepcounter{figurecounter}%%
      \captionsetup{labelformat=figurefmt}%%
    }%%
    \ifthenelse{\equal{\capt@get{caption}}{abc}}{%%
      \caption{}%%
    }{%%
      \caption{\capt@get{caption}}%%
    }%%
    \ifthenelse{\NOT\equal{\capt@get{label}}{}}{%%
      \label{\capt@get{label}}%%
    }{}%%
  }{}%%
}

\NewDocumentCommand \displaycounter { O {figure} }
{%
  \texttt{\textbackslash the#1} is \csname the#1\endcsname
}
\newcommand\FloatingElements[1]{%%
  \displaycounter
  \begin{figure}[ht!]
    \displaycounter
    
    \centering#1
    
    \displaycounter
  \end{figure}\par
  \displaycounter
}

\begin{document}
\chapter{Chapter One}
\FloatingElements{
  \insertFigure{
    file={example-image-a},
    width=0.2,
    caption={abc},
  }\hfil
  \insertCode{
    file={indentfirst.sty},
    width=0.3,
    caption={abc},
    label={the-first-text}
  }
  
  \displaycounter
%   \displaycounter[lstlisting]
  \insertCaption{
    type=Figure,
    caption={This is a figure with some text, use the Figure counter.},
    label={group1},
  }
  
  \displaycounter
%   \displaycounter[lstlisting]
}

\FloatingElements{
  \insertCode{
    file={indentfirst.sty},
    width=0.8,
  }%%
  \insertCaption{
    type=Listing,
    caption={This is just text B, so use the Listing counter.},
    label={group2},
  }%%
}

\FloatingElements{
  \insertFigure{
    file={example-image-b},
    width=0.2,
  }%%
  \insertCaption{
    type=Figure,
    caption={This is just a figure, so use the Figure counter.},
    label={group3},
  }%%
}

\FloatingElements{
  \insertCode{
    file={indentfirst.sty},
    width=0.2,
    caption={abc},
    label={text-c}
  }\hfil%%
  \insertCode{
    file={indentfirst.sty},
    width=0.2,
    caption={abc},
  }%%
  \insertCaption{
    type=Listing,
    caption={These are texts C and D, so use the Listing counter.},
    label={group4},
  }%%
}\displaycounter

\textbf{Cross references:}

Figure~\ref{group1} has the figureA and textA. Listing~\ref{the-first-text} is within the same Figure~\ref{group1}.

Listing~\ref{group2} only has the textB.

Figure~\ref{group3} only has the figureB.

Listing~\ref{group4} has the texts C and D. And sub-listing~\ref{text-c} is textC.

\end{document}

相關內容