我想定义一种灵活的方式,将源代码和/或图形片段包含到充当浮动图形环境的组中。
这个想法是能够使用type
命令的参数选择计数器\insertCaption
。如果是“列表”,则使用一个计数器;如果是“图形”,则使用另一个计数器。
我面临的问题是我无法正确选择计数器。它在标题中显示得很好,但每当我引用该组时,它都不会显示正确的编号。请考虑以下不起作用的示例:
\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}