将 TikZ 图形垂直对齐到多列中​​的邻居

将 TikZ 图形垂直对齐到多列中​​的邻居

为了在 Prolog 中记录块世界问题,我想展示示例代码(使用 listing 包)以及我使用 TikZ 制作的真实世界等效代码。为此,我使用了多列包和 2 列。

不幸的是,这两个元素的两个框架不是从同一高度开始的。我希望这两个元素的顶部边框从同一垂直点开始。

以下是示例代码:

\documentclass[11pt]{article}
\usepackage{tikz}
\usepackage{multicol}
\usepackage{listings}

\lstset{ %
  language=Prolog,                % the language of the code
  basicstyle=\scriptsize\ttfamily,     % the size of the fonts that are used for the code
  numbers=left,                   % where to put the line-numbers
  numberstyle=\tiny\color{gray},  % the style that is used for the line-numbers
  stepnumber=1,                   % the step between two line-numbers. If it's 1, each line will be numbered
  numbersep=5pt,                  % how far the line-numbers are from the code
  backgroundcolor=\color{white},  % choose the background color. You must add \usepackage{color}
  showspaces=false,               % show spaces adding particular underscores
  showstringspaces=false,         % underline spaces within strings
  showtabs=false,                 % show tabs within strings adding particular underscores
  frame=single,                   % adds a frame around the code
  rulecolor=\color{black},        % if not set, the frame-color may be changed on line-breaks within not-black text
  tabsize=4,                      % sets default tabsize to 4 spaces
  captionpos=b,                   % sets the caption-position to bottom
  breaklines=true,                % sets automatic line breaking
  breakatwhitespace=false,        % sets if automatic breaks should only happen at whitespace
  title=\lstname,                 % show the filename of files included with \lstinputlisting;
                                  % also try caption instead of title
  keywordstyle=\color{blue},      % keyword style
  commentstyle=\color{dkgreen},   % comment style
  stringstyle=\color{mauve},      % string literal style
  escapeinside={\%*}{*)},         % if you want to add LaTeX within your code
}

\begin{document}
\tikzstyle{block} = [rectangle, draw, minimum height=1cm, minimum width=1cm]
\tikzstyle{table} = [rectangle, draw, minimum width=5cm, minimum height=0.5cm, fill=gray!50]
\tikzstyle{b1} = [fill=orange!50]
\tikzstyle{b2} = [fill=green!50]
\tikzstyle{b3} = [fill=cyan!50]
\tikzstyle{b4} = [fill=red!50]

This is an example paragraph.

\begin{multicols}{2}
\begin{lstlisting}[language=Prolog]
[
    block(block1),
    block(block2),
    block(block3),
    block(block4),
    on(table,block2),
    on(table,block3),
    on(block2,block1),
    on(table,block4),
    clear(block1),
    clear(block3),
    clear(block4),
    handempty
]
\end{lstlisting}

\begin{tikzpicture}
    \draw(-2,-2) rectangle (5,4);
    \node[block, b3] at (1.5,0) {3};
    \node[block, b2] at (0,0) {2};
    \node[block, b1] at (0,1) {1};
    \node[block, b4] at (3,0) {4};
    \node[table] at (1.5,-0.75) {Table};
\end{tikzpicture}
\end{multicols}

Another paragraph can follow here.
\end{document}

这是结果,显示了顶部边框不在同一垂直水平上的问题:

在此处输入图片描述

答案1

如果不使用 multicol,而是将列表放入 tikz 节点中,则可以得到以下结果:

在此处输入图片描述

代码

这段代码相当脏,因为它包含很多硬编码的长度。为了完全自动化这些测量,需要精确地知道列表节点的高度。这可以通过以下方法实现:这个问题,但由于某种原因,列表改变了节点的排版方式,导致测量的高度过大。因此,在我找到更好的方法之前,我将在这里留下一个肮脏但有效的代码。

\documentclass[11pt]{article}
\usepackage{tikz}
% \usepackage{multicol} % no longer necessary
\usepackage{listings}
\usepackage{lipsum}

\lstset{ %
  language=Prolog,                % the language of the code
  basicstyle=\scriptsize\ttfamily,     % the size of the fonts that are used for the code
  numbers=left,                   % where to put the line-numbers
  numberstyle=\tiny\color{gray},  % the style that is used for the line-numbers
  stepnumber=1,                   % the step between two line-numbers. If it's 1, each line will be numbered
  numbersep=5pt,                  % how far the line-numbers are from the code
  backgroundcolor=\color{white},  % choose the background color. You must add \usepackage{color}
  showspaces=false,               % show spaces adding particular underscores
  showstringspaces=false,         % underline spaces within strings
  showtabs=false,                 % show tabs within strings adding particular underscores
  frame=single,                   % adds a frame around the code
  rulecolor=\color{black},        % if not set, the frame-color may be changed on line-breaks within not-black text
  tabsize=4,                      % sets default tabsize to 4 spaces
  captionpos=b,                   % sets the caption-position to bottom
  breaklines=true,                % sets automatic line breaking
  breakatwhitespace=false,        % sets if automatic breaks should only happen at whitespace
  title=\lstname,                 % show the filename of files included with \lstinputlisting;
                                  % also try caption instead of title
  keywordstyle=\color{blue},      % keyword style
  commentstyle=\color{dkgreen},   % comment style
  stringstyle=\color{mauve},      % string literal style
  escapeinside={\%*}{*)},         % if you want to add LaTeX within your code
}


\begin{document}
\tikzstyle{block} = [rectangle, draw, minimum height=1cm, minimum width=1cm]
\tikzstyle{table} = [rectangle, draw, minimum width=5cm, minimum height=0.5cm, fill=gray!50]
\tikzstyle{b1} = [fill=orange!50]
\tikzstyle{b2} = [fill=green!50]
\tikzstyle{b3} = [fill=cyan!50]
\tikzstyle{b4} = [fill=red!50]

\lipsum[1]

%\begin{multicols}{2}

\begin{tikzpicture}

  \node at (-5,0) {
    \begin{lstlisting}[language=Prolog,linewidth=5cm]
      [ 
           block(block1),
           block(block2),
           block(block3),
           block(block4),
           on(table,block2),
           on(table,block3),
           on(block2,block1),
           on(table,block4),
           clear(block1),
           clear(block3),
           clear(block4),
           handempty 
      ]
    \end{lstlisting}
  };

  \draw(-1.5,-2.05) rectangle (4.5,2.8);
  \node[block, b3] at (1.5,0) {3};
  \node[block, b2] at (0,0) {2};
  \node[block, b1] at (0,1) {1};
  \node[block, b4] at (3,0) {4};
  \node[table] at (1.5,-0.75) {Table};
\end{tikzpicture}
%\end{multicols}

\lipsum[2]

\end{document}

编辑(根据 OP 的评论)

下面的代码在某种程度上完成了对齐所需的高度计算。

\documentclass[11pt]{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{multicol}
\usepackage{listings}
\usepackage{lipsum}

\lstset{ %
  language=Prolog,                % the language of the code
  basicstyle=\scriptsize\ttfamily,     % the size of the fonts that are used for the code
  numbers=left,                   % where to put the line-numbers
  numberstyle=\tiny\color{gray},  % the style that is used for the line-numbers
  stepnumber=1,                   % the step between two line-numbers. If it's 1, each line will be numbered
  numbersep=5pt,                  % how far the line-numbers are from the code
%  backgroundcolor=\color{white},  % choose the background color. You must add \usepackage{color}
  showspaces=false,               % show spaces adding particular underscores
  showstringspaces=false,         % underline spaces within strings
  showtabs=false,                 % show tabs within strings adding particular underscores
%  frame=single,                   % adds a frame around the code
%  rulecolor=\color{black},        % if not set, the frame-color may be changed on line-breaks within not-black text
  tabsize=4,                      % sets default tabsize to 4 spaces
  captionpos=b,                   % 
  breaklines=true,                % sets automatic line breaking
  breakatwhitespace=false,        % sets if automatic breaks should only happen at whitespace
%  title=\lstname,                 % show the filename of files included with \lstinputlisting;
                                  % also try caption instead of title
  keywordstyle=\color{blue},      % keyword style
  commentstyle=\color{dkgreen},   % comment style
  stringstyle=\color{mauve},      % string literal style
  escapeinside={\%*}{*)},         % if you want to add LaTeX within your code
}

\makeatletter
\newcommand\getheightofnode[2]{%
    \pgfextracty{#1}{\pgfpointanchor{#2}{north}}%
    \pgfextracty{\pgf@xa}{\pgfpointanchor{#2}{south}}% \pgf@xa is a length defined by PGF for temporary storage. No need to create a new temporary length.
    \addtolength{#1}{-\pgf@xa}%
}
\makeatother

\newlength{\myheight}

\begin{document}
\tikzstyle{block} = [rectangle, draw, minimum height=1cm, minimum width=1cm]
\tikzstyle{table} = [rectangle, draw, minimum width=5cm, minimum height=0.5cm, fill=gray!50]
\tikzstyle{b1} = [fill=orange!50]
\tikzstyle{b2} = [fill=green!50]
\tikzstyle{b3} = [fill=cyan!50]
\tikzstyle{b4} = [fill=red!50]

\lipsum[1]

\begin{tikzpicture}

  \node[anchor=south west,inner xsep=15pt,inner ysep=5pt,draw] (listing) at (-7,0) {%
\begin{lstlisting}[language=Prolog,aboveskip=0,belowskip=0,abovecaptionskip=0pt,belowcaptionskip=0pt]
[
    block(block1),
    block(block2),
    block(block3),
    block(block4),
    on(table,block2),
    on(table,block3),
    on(block2,block1),
    on(table,block4),
    clear(block1),
    clear(block3),
    clear(block4),
    handempty
]
\end{lstlisting}};

    \getheightofnode{\myheight}{listing}

    \begin{scope}[shift={($ - 0.5*(0,\myheight) + (0,2.5)$)}]
      % The second term's y coordinate is 2.5 = height of the boxes + table
      \draw (-1.5,0) rectangle ($(4.5,0) + (0,\myheight) $);
      \begin{scope}[shift={($0.5*(0,\myheight) - (0,0.25)$)}] % Why do I need this 0.25?
        \node[block, b3] at (1.5,0) {3};
        \node[block, b2] at (0,0) {2};
        \node[block, b1] at (0,1) {1};
        \node[block, b4] at (3,0) {4};  
        \node[table] at (1.5,-0.75) {Table};
      \end{scope}
    \end{scope}

\end{tikzpicture}

\lipsum[2]

\end{document}

我从 listings 包中注释掉一些选项,让 tikz 进行框架等操作。结果在高度方面是正确的,但是我仍然不完全满意,因为这仍然需要用户输入框的高度(但我不打算将其自动化),并且有 0.2 这个“神奇”值是块的垂直对齐所必需的。我想我的计算在某些地方是错误的。

在此处输入图片描述

将这个 0.2 魔法值替换为 0.4,它不再对齐,但在我看来它更加平衡:

在此处输入图片描述

如果右侧图片较高,则采用 (半脏) 解决方案

对齐可以从那里进行或多或少的调整。但在这种情况下语法有点不同

\documentclass[11pt]{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{multicol}
\usepackage{listings}
\usepackage{lipsum}

\lstset{ %
  language=Prolog,                % the language of the code
  basicstyle=\scriptsize\ttfamily,     % the size of the fonts that are used for the code
  numbers=left,                   % where to put the line-numbers
  numberstyle=\tiny\color{gray},  % the style that is used for the line-numbers
  stepnumber=1,                   % the step between two line-numbers. If it's 1, each line will be numbered
  numbersep=5pt,                  % how far the line-numbers are from the code
%  backgroundcolor=\color{white},  % choose the background color. You must add \usepackage{color}
  showspaces=false,               % show spaces adding particular underscores
  showstringspaces=false,         % underline spaces within strings
  showtabs=false,                 % show tabs within strings adding particular underscores
%  frame=single,                   % adds a frame around the code
%  rulecolor=\color{black},        % if not set, the frame-color may be changed on line-breaks within not-black text
  tabsize=4,                      % sets default tabsize to 4 spaces
  captionpos=b,                   % 
  breaklines=true,                % sets automatic line breaking
  breakatwhitespace=false,        % sets if automatic breaks should only happen at whitespace
%  title=\lstname,                 % show the filename of files included with \lstinputlisting;
                                  % also try caption instead of title
  keywordstyle=\color{blue},      % keyword style
  commentstyle=\color{dkgreen},   % comment style
  stringstyle=\color{mauve},      % string literal style
  escapeinside={\%*}{*)},         % if you want to add LaTeX within your code
}

\makeatletter
\newcommand\getheightofnode[2]{%
    \pgfextracty{#1}{\pgfpointanchor{#2}{north}}%
    \pgfextracty{\pgf@xa}{\pgfpointanchor{#2}{south}}% \pgf@xa is a length defined by PGF for temporary storage. No need to create a new temporary length.
    \addtolength{#1}{-\pgf@xa}%
}
\makeatother

\newlength{\myheight}

\begin{document}
\tikzstyle{block} = [rectangle, draw, minimum height=1cm, minimum width=1cm]
\tikzstyle{table} = [rectangle, draw, minimum width=5cm, minimum height=0.5cm, fill=gray!50]
\tikzstyle{b1} = [fill=orange!50]
\tikzstyle{b2} = [fill=green!50]
\tikzstyle{b3} = [fill=cyan!50]
\tikzstyle{b4} = [fill=red!50]

\begin{tikzpicture}

  \node[anchor=south west,inner xsep=15pt,inner ysep=5pt] (listing) at (-7,0) {%
\begin{lstlisting}[language=Prolog,aboveskip=0,belowskip=0,abovecaptionskip=0pt,belowcaptionskip=0pt]
[
    block(block1),
    block(block2),
    block(block3),
    block(block4),
    on(table,block2),
    on(table,block3),
    on(block2,block1),
    on(table,block4),
    clear(block1),
    clear(block3),
    clear(block4),
    handempty
]
\end{lstlisting}};

    \def\myheight{7}

    \begin{scope}[shift={($ - 0.5*(0,\myheight) + (0,2.5)$)}]
      % The second term is 2.5 (height of the boxes + table)
      \draw (-1.5,0) rectangle ($(4.5,0) + (0,\myheight) $);
      \begin{scope}[shift={($(0,1.5)$)}] % Why do I need this 0.25?
        \node[block, b3] at (1.5,0) {3};
        \node[block, b2] at (0,0) {2};
        \node[block, b1] at (0,1) {1};
        \node[block, b4] at (3,0) {4};  
        \node[block, b2] at (0,2) {5};  
        \node[block, b3] at (0,3) {6};  
        \node[block, b4] at (0,4) {7};  
        \node[table] at (1.5,-0.75) {Table};
      \end{scope}
    \end{scope}

    \draw ($(listing) - 0.5*(5,\myheight)$) rectangle ($(listing) + 0.5*(5,\myheight)$);

\end{tikzpicture}


\end{document}

在此处输入图片描述

相关内容