![如何交叉引用不同計數器的標題?](https://rvso.com/image/476252/%E5%A6%82%E4%BD%95%E4%BA%A4%E5%8F%89%E5%BC%95%E7%94%A8%E4%B8%8D%E5%90%8C%E8%A8%88%E6%95%B8%E5%99%A8%E7%9A%84%E6%A8%99%E9%A1%8C%EF%BC%9F.png)
我想定義一種靈活的方式,將原始程式碼和/或圖形包含到充當浮動圖形環境的群組中。
這個想法是能夠使用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:
可以看出,標題和交叉引用中的數字不符。
答案1
我不提供解決方案,因為您還沒有弄清楚您是將其用作學習練習還是實際用途,所以我不知道該給出哪種答案。
這是「為什麼?」的回答。而不是“如何?”
每次您在環境\caption
中使用時figure
,figure
計數器都會增加。資訊寫入.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}