编辑

编辑

我尝试使用针对该问题提出的答案:标记伪代码块并在其附近插入注释

但是当我尝试将它与多个块一起使用时,它并不像只有一个突出显示的块那样完美地工作:

在此处输入图片描述

\documentclass{beamer}
\usepackage{algorithm,algpseudocode}
\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{xcolor}
\makeatletter

% to change colors
\newcommand{\fillcol}{green!20}
\newcommand{\bordercol}{black}

% code from Andrew Stacey (with small adjustment to the border color)
% https://tex.stackexchange.com/questions/51582/background-coloring-with-overlay-specification-in-algorithm2e-beamer-package
\newcounter{jumping}
\resetcounteronoverlays{jumping}

\def\jump@setbb#1#2#3{%
  \@ifundefined{jump@#1@maxbb}{%
    \expandafter\gdef\csname jump@#1@maxbb\endcsname{#3}%
  }{%
    \csname jump@#1@maxbb\endcsname
    \pgf@xa=\pgf@x
    \pgf@ya=\pgf@y
    #3
    \pgfmathsetlength\pgf@x{max(\pgf@x,\pgf@xa)}%
    \pgfmathsetlength\pgf@y{max(\pgf@y,\pgf@ya)}%
    \expandafter\xdef\csname jump@#1@maxbb\endcsname{\noexpand\pgfpoint{\the\pgf@x}{\the\pgf@y}}%
  }
  \@ifundefined{jump@#1@minbb}{%
    \expandafter\gdef\csname jump@#1@minbb\endcsname{#2}%
  }{%
    \csname jump@#1@minbb\endcsname
    \pgf@xa=\pgf@x
    \pgf@ya=\pgf@y
    #2
    \pgfmathsetlength\pgf@x{min(\pgf@x,\pgf@xa)}%
    \pgfmathsetlength\pgf@y{min(\pgf@y,\pgf@ya)}%
    \expandafter\xdef\csname jump@#1@minbb\endcsname{\noexpand\pgfpoint{\the\pgf@x}{\the\pgf@y}}%
  }
}

\tikzset{%
  remember picture with id/.style={%
    remember picture,
    overlay,
    draw=\bordercol,
    save picture id=#1,
  },
  save picture id/.code={%
    \edef\pgf@temp{#1}%
    \immediate\write\pgfutil@auxout{%
      \noexpand\savepointas{\pgf@temp}{\pgfpictureid}}%
  },
  if picture id/.code args={#1#2#3}{%
    \@ifundefined{save@pt@#1}{%
      \pgfkeysalso{#3}%
    }{
      \pgfkeysalso{#2}%
    }
  },
  onslide/.code args={<#1>#2}{%
    \only<#1>{\pgfkeysalso{#2}}%
  },
  alt/.code args={<#1>#2#3}{%
    \alt<#1>{\pgfkeysalso{#2}}{\pgfkeysalso{#3}}%
  },
  stop jumping/.style={
    execute at end picture={%
      \stepcounter{jumping}%
      \immediate\write\pgfutil@auxout{%
        \noexpand\jump@setbb{\the\value{jumping}}{\noexpand\pgfpoint{\the\pgf@picminx}{\the\pgf@picminy}}{\noexpand\pgfpoint{\the\pgf@picmaxx}{\the\pgf@picmaxy}}
      },
      \csname jump@\the\value{jumping}@maxbb\endcsname
      \path (\the\pgf@x,\the\pgf@y);
      \csname jump@\the\value{jumping}@minbb\endcsname
      \path (\the\pgf@x,\the\pgf@y);
    },
  }
}


\def\savepointas#1#2{%
  \expandafter\gdef\csname save@pt@#1\endcsname{#2}%
}

\def\tmk@labeldef#1,#2\@nil{%
  \def\tmk@label{#1}%
  \def\tmk@def{#2}%
}

\tikzdeclarecoordinatesystem{pic}{%
  \pgfutil@in@,{#1}%
  \ifpgfutil@in@%
    \tmk@labeldef#1\@nil
  \else
    \tmk@labeldef#1,\pgfpointorigin\@nil
  \fi
  \@ifundefined{save@pt@\tmk@label}{%
    \tikz@scan@one@point\pgfutil@firstofone\tmk@def
  }{%
  \pgfsys@getposition{\csname save@pt@\tmk@label\endcsname}\save@orig@pic%
  \pgfsys@getposition{\pgfpictureid}\save@this@pic%
  \pgf@process{\pgfpointorigin\save@this@pic}%
  \pgf@xa=\pgf@x
  \pgf@ya=\pgf@y
  \pgf@process{\pgfpointorigin\save@orig@pic}%
  \advance\pgf@x by -\pgf@xa
  \advance\pgf@y by -\pgf@ya
  }%
}
\newcommand\tikzmark[2][]{%
\tikz[remember picture with id=#2] #1;}
\makeatother

\resetcounteronoverlays{algocf}

\newcommand<>{\boxto}[1]{%
\only#2{\tikz[remember picture with id=#1]
\draw[line width=1pt,fill=\fillcol,rectangle,rounded corners]
(pic cs:#1) ++(5.2,-.1) rectangle (-0.4,0)
;\tikz\node [anchor=base] (#1){};}% <= insertion to store the anchor to be used as based for the annotation
}

\begin{document}
\begin{frame}
\begin{algorithm}[H]
    \begin{algorithmic}
        \Function{tarjan}{Node* node}
            \State $node.visited \gets $ \textbf{true}
            \State $node.index \gets indexCounter$
            \State $s.push(node)$
            \boxto<1->{b}\ForAll{$successor$ in $node.successors$}
                \If{$!node.visited$}
                    \Call{tarjan}{successor}
                \EndIf
                \State $node.lowlink \gets$ \Call{min}{$node.lowlink, successor.lowlink$}
            \EndFor\tikzmark{b}     

            \boxto<1->{a}\If{$node.lowlink == node.index$}
                \Repeat 
                    \State $successor \gets stack.pop()$
                \Until{$successor == node$}
            \EndIf\tikzmark{a}
        \EndFunction
    \end{algorithmic}
\label{alg:seq2}
\end{algorithm}

% To insert the annotation
\begin{tikzpicture}[remember picture,overlay]
\coordinate (aa) at ($(a)+(8.5,3)$); % <= adjust this parameter to move the position of the annotation 
\node[rectangle,draw, gray,text width=3cm,align=left,right] at (aa) {The root node was found and the whole SCC gets poped from stack};
\end{tikzpicture}
\end{frame}

\end{document}

工作答案

以下是符号 1 提出的答案的完整工作示例:\documentclass{beamer} \usepackage{algorithm,algpseudocode} \usepackage{tikz} \usetikzlibrary{calc,fit,tikzmark} \makeatletter

\def\tikzbackgroundpath#1;{
    \gdef\tikzmarkhookinbeamerheadline{
        \gdef\tikzmarkhookinbeamerheadline{}
        \tikz[remember picture,overlay]\path#1;
    }
}

\begin{document}
\gdef\tikzmarkhookinbeamerheadline{}
\addtobeamertemplate{headline}{}{\tikzmarkhookinbeamerheadline}

\begin{frame}
frame before
\end{frame}

\begin{frame}
\begin{algorithm}[H]
    \begin{algorithmic}
        \Function{tarjan}{Node* node}
            \State $node.visited \gets $ \textbf{true}
            \State $node.index \gets indexCounter$
            \State \tikzmark{a}$s.push(node)$
            \ForAll{$successor$ in $node.successors$}
                \If{$!node.visited$}
                    \Call{tarjan}{successor}
                \EndIf
                \State $node.lowlink \gets$ \Call{min}{$node.lowlink, successor.lowlink$}\tikzmark{b}
            \EndFor\tikzmark{c}     
            \State \tikzmark{d}
            \If{$node.lowlink == node.index$}\tikzmark{e}
                \Repeat 
                    \State $successor \gets stack.pop()$
                \Until{$successor == node$}
            \EndIf\tikzmark{f}
        \EndFunction
    \end{algorithmic}
\label{alg:seq2}
\end{algorithm}

\tikzbackgroundpath node[rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:a)(pic cs:b)(pic cs:c)}]{}
        node[rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:d)(pic cs:e)(pic cs:f)}](G){}
        (G.east)node[right=10,gray,draw,fill=white,text width=100,align=left]{The root node was found and the whole SCC gets popped from stack};


\end{frame}


\begin{frame}
frame after
\end{frame}

\end{document}

答案1

也许我的代码更容易理解。

这行

\addtobeamertemplate{headline}{}{\tikzmarkhookinbeamerheadline}

在标题中添加一个钩子。将钩子放在哪里并不重要,只要在文本排版之前展开钩子即可。

接下来就是你的算法了。把一些\tikzmarks 放好。

第三,\gdef钩子可以绘制方框。你可以看到

node[fit={([yshift=-5]pic cs:a)(pic cs:b)(pic cs:c)}]{}

绘制一个节点合身前三个分数,但该分数a已提前移位。

最后

(G.east)node[right=10,gray,draw,fill=white,text width=100,align=left]{The root node was found and the whole SCC gets popped from stack};

给你评论。

\documentclass{beamer}
\usepackage{algorithm,algpseudocode}
\usepackage{tikz}
\usetikzlibrary{calc,fit,tikzmark}
\makeatletter

\begin{document}

\addtobeamertemplate{headline}{}{\tikzmarkhookinbeamerheadline}

\begin{frame}
\begin{algorithm}[H]
    \begin{algorithmic}
        \Function{tarjan}{Node* node}
            \State $node.visited \gets $ \textbf{true}
            \State $node.index \gets indexCounter$
            \State \tikzmark{a}$s.push(node)$
            \ForAll{$successor$ in $node.successors$}
                \If{$!node.visited$}
                    \Call{tarjan}{successor}
                \EndIf
                \State $node.lowlink \gets$ \Call{min}{$node.lowlink, successor.lowlink$}\tikzmark{b}
            \EndFor\tikzmark{c}     
            \State \tikzmark{d}
            \If{$node.lowlink == node.index$}\tikzmark{e}
                \Repeat 
                    \State $successor \gets stack.pop()$
                \Until{$successor == node$}
            \EndIf\tikzmark{f}
        \EndFunction
    \end{algorithmic}
\label{alg:seq2}
\end{algorithm}

\gdef\tikzmarkhookinbeamerheadline{
    \tikz[remember picture,overlay]\path
        node[rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:a)(pic cs:b)(pic cs:c)}]{}
        node[rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:d)(pic cs:e)(pic cs:f)}](G){}
        (G.east)node[right=10,gray,draw,fill=white,text width=100,align=left]{The root node was found and the whole SCC gets popped from stack};
}

\end{frame}

\end{document}

编辑

(抱歉我忘记了这部分)

由于我刚刚定义了钩子,并且钩子将保留在标题中,因此 Beamer 将在所有后续帧中打印相同的绿色框。为了解决这个问题,想象一下在下一帧中你想绘制一个无框,所以你写

\gdef\tikzmarkhookinbeamerheadline{}

那么 Beamer 将不会画出任何方框。


原始定义中也可以包含自我毁灭

\gdef\tikzmarkhookinbeamerheadline{
    \gdef\tikzmarkhookinbeamerheadline{}
    \tikz[remember picture,overlay]\path ... 
}

或者更方便的是,定义一个定义自毁钩子的宏

\def\gdefdisposabletikzmarkhookinbeamerheadline#1{
    \gdef\tikzmarkhookinbeamerheadline{
        \gdef\tikzmarkhookinbeamerheadline{}
        #1
    }
}

这样你就可以这样写

\gdefdisposabletikzmarkhookinbeamerheadline{
    \tikz[remember picture,overlay]\path ... 
}

更加方便:(注意分号,它使语法更“Ti(Zy)

\def\tikzbackgroundpath#1;{
    \gdef\tikzmarkhookinbeamerheadline{
        \gdef\tikzmarkhookinbeamerheadline{}
        \tikz[remember picture,overlay]\path#1;
    }
}

这样你就可以这样写

\tikzbackgroundpath node[rounded corners,...]{};

它是否与覆盖规范兼容?

不一定。这取决于用途。

例如,可以把 放在\only<>外面\tikzbackgroundpath。像这样

\only<2>{
    \tikzbackgroundpath
        node[rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:a)(pic cs:b)(pic cs:c)}]{};
}
\only<3>{
    \tikzbackgroundpath
        node[rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:a)(pic cs:b)(pic cs:c)}]{}
        node[rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:d)(pic cs:e)(pic cs:f)}](G){};
}
\only<4>{
    \tikzbackgroundpath
        node[rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:a)(pic cs:b)(pic cs:c)}]{}
        node[rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:d)(pic cs:e)(pic cs:f)}](G){}(G.east)
        node[right=10,gray,draw,fill=white,text width=100,align=left]{The root node was found and the whole SCC gets popped from stack};
}

然后一切都会正常运作。由于 Beamer 是这里的主人,因此将覆盖规范放在外面是有意义的。

不,我想使用 pgfkeys 来指定覆盖

也是有可能的,见下文

\tikzset{
    only/.code args={<#1>}{
        \alt<#1>{\pgfkeysalso{opacity=1}}{\pgfkeysalso{opacity=0}}
    }
}

.......

\tikzbackgroundpath
    node[only=<3->,rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:a)(pic cs:b)(pic cs:c)}]{}
    node[only=<4->,rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:d)(pic cs:e)(pic cs:f)}](G){}(G.east)
    node[only=<5->,right=10,gray,draw,fill=white,text width=100,align=left]{The root node was found and the whole SCC gets popped from stack};

only=<5->不,你作弊了,只有四张幻灯片,那到底是什么呢?

让我解释一下:因为这些 TiZ图片没有展开的地方,有点奇怪滑动换档所以这only=<5->实际上意味着\only<4->。此外,我必须写信\begin{frame}<-4>通知 Beamer,这个框架有四张幻灯片。

如果在框架标题中插入钩子,则可以修复此问题。不幸的是,如果没有框架标题,框架标题根本就不会排版。

怎么样...不使用钩子?

这确实是个好主意。将其放在框架的开头可以解决问题。

\tikz[remember picture,overlay]\path
    node[only=<2->,rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:a2)(pic cs:b2)(pic cs:c2)}]{}
    node[only=<3->,rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:d2)(pic cs:e2)(pic cs:f2)}](G){}(G.east)
    node[only=<4->,right=10,gray,draw,fill=white,text width=100,align=left]{The root node was found and the whole SCC gets popped from stack};

然而,我不太愿意参考未来节点。有些时候,我会用同一个名字来命名不同的节点,以达到某些特殊目的。这样的技巧肯定会与这个技巧相冲突。

怎么样\againframe?第二个屏幕?无需填写讲义?

一般来说:我不知道。我只能向你展示逻辑。我无法处理所有可能性。如果你(以及所有潜在观众)是轻度用户,那么这是没有必要的。

不过,如果您确实有一些特定要求,请随时发表评论。我可以向您展示如何自定义代码以满足特定目标。

总体代码

\documentclass{beamer}
\usepackage{algorithm,algpseudocode}
\usepackage{tikz}
\usetikzlibrary{calc,fit,tikzmark}
\makeatletter

\begin{document}


\addtobeamertemplate{background}{}{\tikzmarkhookinbeamerbackground}
\def\tikzmarkhookinbeamerbackground{}
\def\tikzbackgroundpath#1;{
    \gdef\tikzmarkhookinbeamerbackground{
        \gdef\tikzmarkhookinbeamerbackground{}
        \tikz[remember picture,overlay]\path#1;
    }
}

\frame{This is an innocent that should contain no boxes.}

\frame{This is an innocent that should contain no boxes.}

\begin{frame}
\begin{algorithm}[H]
    \begin{algorithmic}
        \Function{tarjan}{Node* node}
            \State $node.visited \gets $ \textbf{true}
            \State $node.index \gets indexCounter$
            \State \tikzmark{a}$s.push(node)$
            \ForAll{$successor$ in $node.successors$}
                \If{$!node.visited$}
                    \Call{tarjan}{successor}
                \EndIf
                \State $node.lowlink \gets$ \Call{min}{$node.lowlink, successor.lowlink$}\tikzmark{b}
            \EndFor\tikzmark{c}     
            \State \tikzmark{d}
            \If{$node.lowlink == node.index$}\tikzmark{e}
                \Repeat 
                    \State $successor \gets stack.pop()$
                \Until{$successor == node$}
            \EndIf\tikzmark{f}
        \EndFunction
    \end{algorithmic}
\label{alg:seq2}
\end{algorithm}

\only<2>{
    \tikzbackgroundpath
        node[rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:a)(pic cs:b)(pic cs:c)}]{};
}
\only<3>{
    \tikzbackgroundpath
        node[rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:a)(pic cs:b)(pic cs:c)}]{}
        node[rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:d)(pic cs:e)(pic cs:f)}](G){};
}
\only<4>{
    \tikzbackgroundpath
        node[rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:a)(pic cs:b)(pic cs:c)}]{}
        node[rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:d)(pic cs:e)(pic cs:f)}](G){}(G.east)
        node[right=10,gray,draw,fill=white,text width=100,align=left]{The root node was found and the whole SCC gets popped from stack};
}
\end{frame}

\frame{This is an innocent that should contain no boxes.}

\frame{This is an innocent that should contain no boxes.}

\tikzset{
    only/.code args={<#1>}{
        \alt<#1>{\pgfkeysalso{opacity=1}}{\pgfkeysalso{opacity=0}}
    }
}

\begin{frame}<-4>
\begin{algorithm}[H]
    \begin{algorithmic}
        \Function{tarjan}{Node* node}
            \State $node.visited \gets $ \textbf{true}
            \State $node.index \gets indexCounter$
            \State \tikzmark{a}$s.push(node)$
            \ForAll{$successor$ in $node.successors$}
                \If{$!node.visited$}
                    \Call{tarjan}{successor}
                \EndIf
                \State $node.lowlink \gets$ \Call{min}{$node.lowlink, successor.lowlink$}\tikzmark{b}
            \EndFor\tikzmark{c}     
            \State \tikzmark{d}
            \If{$node.lowlink == node.index$}\tikzmark{e}
                \Repeat 
                    \State $successor \gets stack.pop()$
                \Until{$successor == node$}
            \EndIf\tikzmark{f}
        \EndFunction
    \end{algorithmic}
\label{alg:seq2}
\end{algorithm}

\tikzbackgroundpath
    node[only=<3->,rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:a)(pic cs:b)(pic cs:c)}]{}
    node[only=<4->,rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:d)(pic cs:e)(pic cs:f)}](G){}(G.east)
    node[only=<5->,right=10,gray,draw,fill=white,text width=100,align=left]{The root node was found and the whole SCC gets popped from stack};

\end{frame}

\frame{This is an innocent that should contain no boxes.}

\frame{This is an innocent that should contain no boxes.}

\begin{frame}
\tikz[remember picture,overlay]\path
    node[only=<2->,rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:a2)(pic cs:b2)(pic cs:c2)}]{}
    node[only=<3->,rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:d2)(pic cs:e2)(pic cs:f2)}](G){}(G.east)
    node[only=<4->,right=10,gray,draw,fill=white,text width=100,align=left]{The root node was found and the whole SCC gets popped from stack};
\begin{algorithm}[H]
    \begin{algorithmic}
        \Function{tarjan}{Node* node}
            \State $node.visited \gets $ \textbf{true}
            \State $node.index \gets indexCounter$
            \State \tikzmark{a2}$s.push(node)$
            \ForAll{$successor$ in $node.successors$}
                \If{$!node.visited$}
                    \Call{tarjan}{successor}
                \EndIf
                \State $node.lowlink \gets$ \Call{min}{$node.lowlink, successor.lowlink$}\tikzmark{b2}
            \EndFor\tikzmark{c2}     
            \State \tikzmark{d2}
            \If{$node.lowlink == node.index$}\tikzmark{e2}
                \Repeat 
                    \State $successor \gets stack.pop()$
                \Until{$successor == node$}
            \EndIf\tikzmark{f2}
        \EndFunction
    \end{algorithmic}
\label{alg:seq2}
\end{algorithm}
\end{frame}

\frame{This is an innocent that should contain no boxes.}

\frame{This is an innocent that should contain no boxes.}

\tikzset{
    alt/.code args={<#1>#2#3}{
        \alt<#1>{\pgfkeysalso{#2}}{\pgfkeysalso{#3}}
    }
}

\begin{frame}

\tikzbackgroundpath[alt=<3>{red}{blue}]
    node[rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:a)(pic cs:b)(pic cs:c)}]{};

\tikz[alt=<3>{red}{blue}]\draw[line width=1](0,0)--(10,0);

\only<1>{1}
\only<2>{2}
\only<3>{3}
\only<4>{4}

\end{frame}

\setbeamertemplate{background}{
    \tikz[remember picture,overlay]\fill[alt=<3>{yellow}{green}](current page.west)+(0,-1)rectangle+(2,1);
}

\begin{frame}{title}
    \only<1-5>{only?}
\end{frame}



\end{document}

相关内容