在 TikZ 中居中表格状节点

在 TikZ 中居中表格状节点

我最近决定正式学习 LaTeX,以便能够将自己的才能从“复制、粘贴和破解”TeX 用户提升为熟练使用这些工具的人。我正在尝试学习的一件事是使用 TikZ 绘制图形和图表。

因此,我尝试绘制三个表格结构,用箭头连接,使一个指向另一个。我将在这个问题的结论部分附上一张手绘草图,说明我的意图。

经过几个小时的挫折(当然,也对着电脑大喊大叫),我想出了以下 MWE,它产生了几乎一模一样我想要的是。

\documentclass{article}

\usepackage{tikz}
\usepackage{tabularx}
\usepackage{amsmath}
\usepackage{mathtools}

\usetikzlibrary{shapes}
\usetikzlibrary{arrows}
\usetikzlibrary{shadows}
\usetikzlibrary{positioning}

\begin{document}

    \tikzstyle{box} = [
        draw,
        fill=white!7,
        minimum width=5em, 
        text centered,
        minimum height=2em,
        drop shadow
    ]

    \begin{tikzpicture}
        \node (dir0) [box, minimum width=16em, minimum height=4em] {\vdots};

        \node (dir1)  [box, anchor=north, minimum width=16em] at
            (dir0.south) {\texttt{Kernel Memory Pages}};

        \node (dir2L) [box, anchor=north west, minimum width=8em] at 
            (dir1.south west) {\texttt{Permissions}};

        \node (dir2R) [box, anchor=north east, minimum width=8em] at
            (dir1.south east) {\texttt{Table Address}};

        \node (dir3)  [box, anchor=north, minimum width=16em] at
            (dir2R.south west) {\texttt{User Memory Pages}};

        \node (dir4L) [box, anchor=north west, minimum width=8em] at 
            (dir3.south west) {\texttt{Permissions}};

        \node (dir4R) [box, anchor=north east, minimum width=8em] at
            (dir3.south east) {\texttt{Table Address}};

        \node (dir5)  [box, anchor=north, minimum width=16em, minimum 
        height=4em] at (dir4R.south west) {\vdots};
    \end{tikzpicture}
\end{document}

这会产生以下输出,这是我第一次使用 TikZ 绘图:

TikZ 表 1

现在,虽然我对图形结果,我来自一个认为代码外观优雅是一种美德的学校,所以我开始用不同的风格重写上面的例子(比如此处“图表”下有记录的示例- “定义/声明/链接”样式),因为一旦我添加其他表,上面的代码必然会变得混乱,而且我担心如果以后需要调整它,它可能无法维护。

因此,我制作了以下表格,对此我非常满意。您可以看到,我还添加了其他两种类型的表格。

\documentclass{article}

\usepackage{tikz}
\usepackage{tabularx}
\usepackage{amsmath}
\usepackage{mathtools}

\usetikzlibrary{shapes}
\usetikzlibrary{arrows}
\usetikzlibrary{shadows}
\usetikzlibrary{positioning}

\begin{document}
    \begin{tikzpicture} [
            % ----- Node definitions ----- %
            dirtablenode/.style = {
                rectangle, 
                rectangle split,
                rectangle split parts = 6,
                fill = white!5,
                minimum width  = 5em,
                minimum height = 2em,
                text centered,
                drop shadow
            },
            pagetablenode/.style = {
                rectangle,
                rectangle split,
                rectangle split parts = 3,
                fill = white!5,
                minimum width  = 5em,
                minimum height = 2em,
                text centered,
                drop shadow
            },
            memmapnode/.style = {
                rectangle,
                rectangle split,
                rectangle split parts = 4,
                fill = white!5,
                minimum width  = 5em,
                minimum height = 2em,
                text centered,
                drop shadow
            }
    ]

        % ----- Node constructions ----- %
        \node [dirtablenode] (directory) {
            \nodepart [minimum width = 16em, minimum height = 4em] {one}
                \vdots
            \nodepart [minimum width = 16em, minimum height = 2em] {two}   
                \texttt{Kernel Memory Pages}
            \nodepart [minimum width = 8em, minimum height = 2em]  {three} 
                \texttt{Permissions}
            \nodepart [minimum width = 8em, minimum height = 2em]  {four}
                \texttt{Table Address}
            \nodepart [minimum width = 16em, minimum height = 2em] {five}   
                \texttt{User Memory Pages}
            \nodepart [minimum width = 8em, minimum height = 2em]  {six} 
                \texttt{Permissions}
            \nodepart [minimum width = 8em, minimum height = 2em]  {seven}
                \texttt{Table Address}
            \nodepart [minimum width = 16em, minimum height = 4em] {eight}
                \vdots
        };

        \node [pagetablenode] (kpagetable) [right=of directory] {
            \nodepart [minimum width = 16em] {kbase}  \texttt{Base Address}
            \nodepart [minimum width = 16em] {klimit} \texttt{Address Limit}
            \nodepart [minimum width = 16em] {kperms} \texttt{Permissions}
        };

        \node [pagetablenode] (upagetable) [below=of kpagetable] {
            \nodepart [minimum width = 16em] {ubase}  \texttt{Base Address}
            \nodepart [minimum width = 16em] {ulimit} \texttt{Address Limit}
            \nodepart [minimum width = 16em] {uperms} \texttt{Permissions}
        };

        \node [memmapnode] (sysmemory) [below=of directory] {
            \nodepart [minimum width = 16em, minimum height = 4em] {one} \vdots
            \nodepart [minimum width = 16em, minimum height = 4em] {kernel} 
                \texttt{Kernel \\ Memory \\ (Protected)}
            \nodepart [minimum width = 16em, minimum height = 4em] {user} 
                \texttt{User \\ Memory \\ (Unprivileged)}
            \nodepart [minimum width = 16em, minimum height = 4em] {one} \vdots
        };

        % ----- Connection lines ----- %
        % ??
    \end{tikzpicture}
\end{document}

为了将所有内容放在一起并更好地表明我正在尝试做的事情(而不是坐在这里假设 TeX.SE 上的人们能读懂我的想法),这里是我设想的整个外观的涂鸦tikzpicture

预期的桌子布局

因此,以下是问题的部分内容,我已将其分解。我尝试在这里搜索答案,但找不到任何可以解决这个问题的内容,而且对于初学者来说,浏览 TikZ 手册是令人生畏的(至少可以这么说)。

  1. 是否\nodepart支持与手动创建的节点对齐相同的对齐方式?您会注意到,我声明第一个 (directory节点有 6 个部分,但实际上它有 8 个节点部分。我可以使用相同的anchor和选项at <reference>内的\nodepart选项来对齐它们吗?

  2. \node对齐(即)是否[right=of directory]接受多个对齐约束,如果是,我该如何对齐它,以使相应实例的顶部和底部pagetablenode与目录正确对齐?

  3. 我该如何对齐底部表格(sysmemory),使其位于两个上方表格的中心,并且(理想情况下)使用半球形线条将右上方表格与其连接起来(如图所示)?

简而言之,我需要对第二个更有序的 MWE 进行哪些更改才能实现我所设想的图表?请记住,您可能需要为我稍微分解一下 - 我对 TikZ 一窍不通。我对如何答案是正确的,因为我的实际答案是这样的。

答案1

正如 Zarko 建议的那样,您应该阅读rectangle split信息(第 726 至 728 页)和positioning图书馆信息。

从一开始,您将了解到,minimum width对于垂直分割的矩形有效,但minimum height会被忽略。然后,每个节点部分中的所有这些选项都可以被抑制。矩形分割宽度将由内部部分宽度的最大值或固定minimum width。如果您想修复某个特定值,minimum width您可以在选项中进行操作,node如下所示kpagetable

minimum height某些节点部分需要某些工具时,我们需要其他工具。一个可能的工具可能是parbox(参见[Yiannis 的回答](https://tex.stackexchange.com/a/10273/1952 您还需要阅读)以了解所有参数),但也可以使用0 宽度规则\rule{0pt}{...}或文本。phantom

阅读有关positioning图书馆的信息,你会明白

right= 3cm of directory.north east, anchor=north west

将强制将相应节点放置在距节点右上角 3 厘米的位置directory并与其顶线对齐。

可以使用类似的结构将其他节点与底角对齐。

aux最后定义了一个节点来放置sysmemory节点。当然,还有其他构造方法可以得到类似的结果。

您的代码已进行了一些进一步的清理。首先,由于所有块仅在其部分上有所不同,因此仅定义了一种以拆分部分为参数的样式。如果需要,minimum width可以将选项添加到每个特定节点声明中。

第二,不再需要\texttt{...}为每个文本部分指定选项,而是font使用选项。这可以节省一些输入。

最后一条评论,由于无法水平划分部件,因此使用两个部件框和手动绘制的划分来表示包含permissions和的线table address

\documentclass{article}

\usepackage{tikz}

\usetikzlibrary{shapes}
\usetikzlibrary{arrows}
\usetikzlibrary{shadows}
\usetikzlibrary{positioning}

\begin{document}
    \begin{tikzpicture} [
            % ----- Node definitions ----- %
            dirtablenode/.style = {
                    draw,
                rectangle, 
                rectangle split,
                rectangle split parts = #1,
                fill = white!5,
                align=center,
                drop shadow,
                font=\ttfamily
            },
    ]

        % ----- Node constructions ----- %
        \node [dirtablenode=6] (directory) {
            \nodepart{one}
                \parbox[t][15mm][c]{1cm}{\vdots}
            \nodepart[]{two}   
                Kernel Memory Pages
            \nodepart{three} 
                \parbox[t][][c]{3cm}{\centering Permissions}\parbox[t][][c]{3cm}{\centering Table Address}
            \nodepart{four}
                User Memory Pages
            \nodepart{five}   
                \parbox[t][][c]{3cm}{\centering Permissions}\parbox[t][][c]{3cm}{\centering Table Address}
            \nodepart{six} 
                \parbox[t][15mm][c]{1cm}{\vdots}
        };
          \draw (directory.two split)--(directory.three split);
          \draw (directory.four split)--(directory.five split);

        \node [dirtablenode=3, minimum width=5cm, right= 3cm of directory.north east, anchor=north west] (kpagetable) {
            \nodepart{one} Base Address
            \nodepart{two}  Address Limit
            \nodepart{three} Permissions
        };

        \node [dirtablenode=3, right=3cm of directory.south east, anchor=south west] (upagetable) {
            \nodepart{one}  Base Address
            \nodepart{two} Address Limit
            \nodepart{three} Permissions
        };

          \path (directory.south east) -- (upagetable.south west) coordinate[midway] (aux);

        \node [dirtablenode=4, below=of aux, anchor=north](sysmemory) {
            \nodepart{one} \vdots
            \nodepart{two} 
                Kernel \\ Memory \\ (Protected)
            \nodepart{three} 
                User \\ Memory \\ (Unprivileged)
            \nodepart{four} \vdots
        };

        % ----- Connection lines ----- %
       \draw[rounded corners,->] (directory.three east)--++(0:1cm)--([xshift=-1cm]kpagetable.north west)--(kpagetable.north west);
       \draw[rounded corners,->] (directory.five east)--++(0:1cm)--([xshift=-1cm]upagetable.north west)--(upagetable.north west);
       \draw[->] (kpagetable.two east) to[out=-10,in=5] (sysmemory.two east);
       \draw[->] (upagetable.two east) to[out=-10,in=5] (sysmemory.three east);
    \end{tikzpicture}
\end{document}

在此处输入图片描述

答案2

...我改变了主意...过了一会儿,我再次将我的解决方案(基于 Ignasi 第一个解决方案)与 Ignasi 解决方案进行了比较,我估计差异很小,但不可忽略。所以,这是我的解决方案:

\documentclass{article}
\usepackage{tabularx}
\newcolumntype{C}{>{\centering\arraybackslash}X}

\usepackage{tikz}
\usetikzlibrary{arrows.meta,
                positioning,
                shadows,shapes}
\newcommand{\myvdots}{\vdots\rule[-2ex]{0ex}{5ex}}

\begin{document}
    \begin{tikzpicture} [% TikZ presets
                > = {Straight Barb[length=5pt]},
    node distance = 0mm and 24mm,
dirtablenode/.style args = {#1/#2}{%
        rectangle split,
        rectangle split parts = #1,
        draw,
        fill=white,
        inner sep=2mm,
        font=\ttfamily,
        text width=#2,
        align=center,
        drop shadow,
                },
                    ]
% ----- Node constructions ----- %
\node (directory)   [dirtablenode=6/16em]   
{
    \nodepart{one}      \myvdots
    \nodepart{two}      Kernel Memory Pages
    \nodepart{three}    \begin{tabularx}{\hsize}{C C} 
                Permissions &   Table Address
                        \end{tabularx}
    \nodepart{four}     User Memory Pages
    \nodepart{five}      \begin{tabularx}{\hsize}{C C} 
                Permissions &   Table Address
                        \end{tabularx}
    \nodepart{six}      \myvdots
};
\draw   (directory.two split)  -- (directory.three split)
        (directory.four split) -- (directory.five  split);
%
\node (kpagetable) [dirtablenode=3/12em, 
                    below right= of directory.north east]   
{
    \nodepart{one}      Base Address
    \nodepart{two}      Address Limit
    \nodepart{three}    Permissions
};
%
\node (upagetable) [dirtablenode=3/12em, 
                    above right=of directory.south east] 
{
    \nodepart{one}  Base Address
    \nodepart{two} Address Limit
    \nodepart{three} Permissions
};
\path (directory.south east)-- coordinate (mid) (upagetable.south west);
\node (sysmemory) [dirtablenode=4/12em, 
                   below=12mm of mid]
{
    \nodepart{one}      \myvdots
    \nodepart{two}      Kernel Memory  (Protected)
    \nodepart{three}    User   Memory  (Unprivileged)
    \nodepart{four}     \myvdots
};
% ----- Connection lines ----- %
\draw[rounded corners,->] 
(directory.three east) --++ (0:1cm) -- ([xshift=-1cm]kpagetable.north west) -- (kpagetable.north west);
\draw[rounded corners,->] 
(directory.five east) --++ (0:1cm) -- ([xshift=-1cm]upagetable.north west) -- (upagetable.north west);
\draw[->] (kpagetable.two east) to[out=-30,in=0,looseness=1.2] (sysmemory.two east);
\draw[->] (upagetable.two east) to[out=-30,in=0,looseness=1.5] (sysmemory.three east);
    \end{tikzpicture}
\end{document}

主要区别:对于垂直点,我定义了新命令,它为点添加了更多垂直空间,multipart节点有两个参数,一个用于部分数,第二个用于节点宽度(它由决定\text width,因此较长的文本可以自动分成更多行),对于箭头,我使用arrows.meta并将它们放大,这样更清晰可见,环更大,更接近对称。我还删除了所有不必要的选项(在我的评论中提到)和包。结果略有不同:

在此处输入图片描述

相关内容