![如何将 tikz 节点适配到包含多行的乳胶表?](https://linux22.com/image/355504/%E5%A6%82%E4%BD%95%E5%B0%86%20tikz%20%E8%8A%82%E7%82%B9%E9%80%82%E9%85%8D%E5%88%B0%E5%8C%85%E5%90%AB%E5%A4%9A%E8%A1%8C%E7%9A%84%E4%B9%B3%E8%83%B6%E8%A1%A8%EF%BC%9F.png)
我正在尝试以我习惯的方式创建一个 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}
有没有办法在不扩大行高的情况下实现拟合?最好使用乳胶表...但如果有类似于 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
绘制表格/图像要简单得多:
例如,您的 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}