如何将 tikz 节点适配到包含多行的乳胶表?

如何将 tikz 节点适配到包含多行的乳胶表?

我正在尝试以我习惯的方式创建一个 latex 表(没有 tikz 矩阵),但现在想在 tikz 中使用该表并从特定单元格到其他单元格绘制线条。因此,我需要将 tikz 节点适配到我的单元格中,这些单元格也包含多列和多行。

我想知道我是否可以以某种方式确定表格的行高,以便将节点的最小高度设置为该高度。这至少对宽度有效(因为我有固定的单元格宽度,所以可以计算这一点)。

我当前的代码如下所示(可能看起来令人不安):

\documentclass{standalone}
\usepackage{tikz,forloop,tabularx,tabulary,multicol,multirow,pgfmath}
\usetikzlibrary{positioning,arrows,chains,matrix,scopes,fit,calc}

\makeatletter

% 1. cols
% 2. pos
% 3. node name
% 4. text
\newcommand{\multicolx}[4]{
    \multicolumn{#1}{#2}{\tikz[remember picture]{ \node[anchor=base,inner sep=0pt, draw, color=red, minimum width=#1*4mm] (#3) {#4};}}
}

\makeatother
\begin{document}
\begin{tikzpicture}

\node[] (tableipv4) at (0,0)
{
    \setlength{\tabcolsep}{0.0pt}
    \begin{tabular}{|*{32}{m{4mm}}|}

        \multicolumn{32}{|c|}{IPv4 Header}\\\hline
        \multicolx{4}{|c}{tbl-ver}{Version} & \multicolx{4}{|c}{tbl-ihl}{IHL} & \multicolx{8}{|c}{tbl-tos}{Type of Service} & \multicolx{16}{|c|}{tbl-len}{Total Length}\\\hline

        \multicolumn{16}{|c}{Identification} & \multicolumn{3}{|c}{Flags} & \multicolumn{13}{|c|}{Fragment Offset} \\\hline

        \multicolumn{32}{|c|}{Source Address}\\\hline

        \multicolumn{32}{|c|}{Destination Address}\\\hline

        \multicolumn{24}{|c}{Options} & \multicolumn{8}{|c|}{Padding}\\\hline
    \end{tabular}
};

\end{tikzpicture}
\end{document}

图片: MWE 图片

有没有办法在不扩大行高的情况下实现拟合?最好使用乳胶表...但如果有类似于 tikz 矩阵的多列的东西,我会考虑切换 :)

提前非常感谢

编辑: 通过 John Kormylo 的改进,我的行高现在已经很好了,如您所见: 添加支柱并设置节点基线后

但是,自从我将剩余的多列更改为自定义多列后,我意识到将“位”的长度乘以跨列数并不是一个好主意。现在有些节点的宽度不足以填充外部多列...

更新的源代码:

\documentclass{standalone}
\usepackage{tikz,forloop,tabularx,tabulary,multicol,multirow,pgfmath}
\usetikzlibrary{positioning,arrows,chains,matrix,scopes,fit,calc}

\makeatletter

% 1. cols
% 2. pos
% 3. node name
% 4. text
\newcommand{\multicolx}[4]{
    \multicolumn{#1}{#2}{\tikz[remember picture,baseline=(#3.text)]{ \node[anchor=base,inner sep=0pt, draw, color=red, minimum width=#1*4mm] (#3) {\strut #4};}}
}

\makeatother
\begin{document}
\begin{tikzpicture}

\node[] (tableipv4) at (0,0)
{
    \setlength{\tabcolsep}{0.0pt}
    \begin{tabular}{|*{32}{m{4mm}}|}

        \multicolumn{32}{|c|}{IPv4 Header}\\\hline
        \multicolx{4}{|c}{tbl-ver}{Version} & \multicolx{4}{|c}{tbl-ihl}{IHL} & \multicolx{8}{|c}{tbl-tos}{Type of Service} & \multicolx{16}{|c|}{tbl-len}{Total Length}\\\hline

        \multicolx{16}{|c}{tbl-id}{Identification} & \multicolx{3}{|c}{tbl-flag}{Flags} & \multicolx{13}{|c|}{tbl-frag}{Fragment Offset} \\\hline

        \multicolx{32}{|c|}{tbl-src}{Source Address}\\\hline

        \multicolx{32}{|c|}{tbl-dest}{Destination Address}\\\hline

        \multicolx{24}{|c}{tbl-opts}{Options} & \multicolx{8}{|c|}{tbl-pad}{Padding}\\\hline
    \end{tabular}
};

\end{tikzpicture}
\end{document}

答案1

您可以使用 正确放置基线。您可以通过在节点内[baseline=(#3.text)]包含 来使所有节点具有相同的高度。这里没有效果,因为每个 中只有一个节点。\strut[anchor=base]tikzpicture

\documentclass{standalone}
\usepackage{tikz,forloop,tabularx,tabulary,multicol,multirow,pgfmath}
\usetikzlibrary{positioning,arrows,chains,matrix,scopes,fit,calc}

\makeatletter

% 1. cols
% 2. pos
% 3. node name
% 4. text
\newcommand{\multicolx}[4]{
    \multicolumn{#1}{#2}{\tikz[remember picture,baseline=(#3.text)]{\node[anchor=base,inner sep=0pt, draw, color=red, minimum width=#1*4mm] (#3) {\strut #4};}}
}

\makeatother
\begin{document}
\begin{tikzpicture}

\node[] (tableipv4) at (0,0)
{
    \setlength{\tabcolsep}{0.0pt}
    \begin{tabular}{|*{32}{m{4mm}}|}

        \multicolumn{32}{|c|}{IPv4 Header}\\\hline
        \multicolx{4}{|c}{tbl-ver}{Version} & \multicolx{4}{|c}{tbl-ihl}{IHL} & \multicolx{8}{|c}{tbl-tos}{Type of Service} & \multicolx{16}{|c|}{tbl-len}{Total Length}\\\hline

        \multicolumn{16}{|c}{Identification} & \multicolumn{3}{|c}{Flags} & \multicolumn{13}{|c|}{Fragment Offset} \\\hline

        \multicolumn{32}{|c|}{Source Address}\\\hline

        \multicolumn{32}{|c|}{Destination Address}\\\hline

        \multicolumn{24}{|c}{Options} & \multicolumn{8}{|c|}{Padding}\\\hline
    \end{tabular}
};

\end{tikzpicture}
\end{document}

演示


修订后的 MWE 的问题在于,所绘制的线的宽度未包含在计算中。以下并非完美匹配,因为 {|c|} 和 {c|} 的校正应该不同。

\documentclass{standalone}
\usepackage{tikz,forloop,tabularx,tabulary,multicol,multirow,pgfmath}
\usetikzlibrary{positioning,arrows,chains,matrix,scopes,fit,calc}

\makeatletter

% 1. cols
% 2. pos
% 3. node name
% 4. text
\newcommand{\multicolx}[4]{
    \multicolumn{#1}{#2}{\tikz[remember picture,baseline=(#3.text)]{ \node[inner sep=0pt,draw, color=red,minimum width={#1*4mm-.75pt}] (#3) {\strut #4};}}
}

\makeatother
\begin{document}
\begin{tikzpicture}

\node[] (tableipv4) at (0,0)
{
    \setlength{\tabcolsep}{0.0pt}
    \begin{tabular}{|*{32}{m{4mm}}|}

        \multicolumn{32}{|c|}{IPv4 Header}\\\hline
        \multicolx{4}{|c}{tbl-ver}{Version} & \multicolx{4}{|c}{tbl-ihl}{IHL} & \multicolx{8}{|c}{tbl-tos}{Type of Service} & \multicolx{16}{|c|}{tbl-len}{Total Length}\\\hline

        \multicolx{16}{|c}{tbl-id}{Identification} & \multicolx{3}{|c}{tbl-flag}{Flags} & \multicolx{13}{|c|}{tbl-frag}{Fragment Offset} \\\hline

        \multicolx{32}{|c|}{tbl-src}{Source Address}\\\hline

        \multicolx{32}{|c|}{tbl-dest}{Destination Address}\\\hline

        \multicolx{24}{|c}{tbl-opts}{Options} & \multicolx{8}{|c|}{tbl-pad}{Padding}\\\hline
    \end{tabular}
};

\end{tikzpicture}
\end{document}

演示 2

答案2

绘制表格/图像要简单得多:

![在此处输入图片描述

例如,您的 MWE(具有正确的 IP v4 标头结构...考虑 RFC 1122、RFC 2474 和 RFC 2481)作为纯 TikZ 图像:

\documentclass[tikz,margin=3mm]{standalone}
\usetikzlibrary{chains, positioning}

\begin{document}
    \begin{tikzpicture}[
node distance = 0mm,
  start chain = going right,
     N/.style = {draw, 
                 minimum width=#1 mm,
                 outer sep=0pt,
                 text height=2ex, text depth=0.5ex,
                 on chain},
                        ]
%--- 1
\node (n11) [N=20,right] at (0,0)        {version};
\node (n12) [N=20]  {IHL};
\node (n13) [N=30]  {DS fiesld};
\node (n14) [N=10]  {ECN};
\node (n15) [N=80]  {Total Length};
%--- 2
\node (n21) [N=80,
      below right=of n11.south west]    {Identification};
\node (n22) [N=15]  {Flags};
\node (n23) [N=65]  {Fragment Offset};
%--- 3
\node (n31) [N=40,
      below right=of n21.south west]    {Time to Leave};
\node (n32) [N=40]  {Protocol};
\node (n33) [N=80]  {Header Checksum};
%--- 4,5,6
\node (n41) [N=160,
      below right=of n31.south west]    {Source Address};
\node (n51) [N=160,below=of n41]        {Destination Address};
\node (n61) [N=160,below=of n51]        {Options + Padding (if any)};
%----------------
\foreach \i in {0,4,8,14,16,19,32}
    \draw (5*\i/10,0.4) -- ++ (0,0.2)
    \ifnum\i<31
                     node[midway,right=-1pt,font=\tiny] {\i}
    \else
                     node[midway,left=-1pt,font=\tiny] {31}
    \fi;
\node (00) [above=4mm of n14.north east] {IPv4 Header};
%---
    \end{tikzpicture}
\end{document}

相关内容