Qt 中有布局的概念(例如,垂直布局将所有对象垂直排列并可能对齐它们,水平布局则水平排列,等等...)。
我正在尝试解决一个布局非常有用的问题。也就是说,我想指定 (1) 左侧节点 ( {n1}, {n2}, {n3}, {n4}, ...
)、(2) 中心节点的文本、(3) 右侧节点。并期望代码生成具有以下属性的多个节点:
- 左侧节点向右对齐,群组节点与中心节点的中心对齐。
- 与右节点相同,但是镜像。
- 每个节点都必须可以被外部引用
- 应该有一个带有锚点的边界框,以便整个“事物”能够排列它们。
下面是它在乳胶中的样子的一个例子:
\pic (a) [anchor=north] at(0, 0) { % `a` is the name of entire "thing"
lcrpic={{n1}, {n2}, {n3}, {n4}, {n5}, {n6}, {n7}} % List of nodes on the left
{Center1:\\many nodes on the left} % Center node
{{n1}} % Nodes on the right
};
我做过设法使下面的代码产生下面的图片:
\pic (a) [anchor=north] at(0, 0) {
lcrpic={{n1}, {n2}, {n3}, {n4}, {n5}, {n6}, {n7}} {Center1:\\many nodes on the left} {{n1}}
};
\pic (b) [anchor=north] at ({$(a-bb.south) - (0cm, 0.4cm)$} -| {$(a-center.south)$}) {
lcrpic={{111111111111111111111111}} {Center2:\\Long nodes on the left} {{11}, {22}, {33}, {44}}
};
\node (f) [nodefx_default] at (-6, -3) {Nodes must be reference-able outside:};
\draw[line width=1pt, draw=red!20] (f) -- (a-leftnodes-node-6);
\draw[line width=1pt, draw=red!20] (f) -- (b-leftnodes-node-1);
但
代码繁琐,效率低,而且丑陋。
我的问题是:在 tikz 中实现这一目标的正确方法是什么?
(也许有与 Qt 中的布局类似的东西?)
平均能量损失
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc, positioning}
\makeatletter
\newcommand{\gettikzxy}[3]{%
\tikz@scan@one@point\pgfutil@firstofone#1\relax
\edef#2{\the\pgf@x}%
\edef#3{\the\pgf@y}%
}
\begin{document}
\begin{tikzpicture}
\tikzstyle{noders_default} = [rectangle, rounded corners=8pt, minimum height=17pt, font=\footnotesize, text centered, draw=black!20, thick, fill=white]
\tikzstyle{nodefx_default} = [noders_default, text width=60pt]
% ============================== left ==============================
% the only useful "output" of the pic is "-bb" (invisible) node - it stores geometry of the left part and is used in pics/leftnodes
\tikzset{
pics/leftnodeslayout/.style n args = {1}{
code={
\begin{scope}[local bounding box = layoutBoundingBox]
\foreach [count=\ei, remember=\ei as \prevei (initially 0)] \elem in {#1} {
\ifnum \prevei=0
\node (-node-\ei) [noders_default, draw=none, opacity=0, text opacity=0] {\elem};
\else
\node (-node-\ei) [noders_default, anchor=north east, draw=none, opacity=0, text opacity=0] at (-node-\prevei.south east) {\elem};
\fi
}
\end{scope}
\gettikzxy{(layoutBoundingBox.north west)}{\xLeft}{\yTop};
\gettikzxy{(layoutBoundingBox.south east)}{\xRight}{\yBottom};
\node[draw=none, green, dashed, minimum height=\yTop - \yBottom, minimum width=\xRight - \xLeft] (-bb) at (0,0) {};
}
}
}
% Draw leftnodeslayout => get its "-bb" draw real nodes using "-bb" as reference:
\tikzset{
pics/leftnodes/.style n args = {1}{
code={
\pic (layout) {leftnodeslayout={#1}};
\gettikzxy{(layout-bb.north west)}{\xLeft}{\yTop};
\gettikzxy{(layout-bb.south east)}{\xRight}{\yBottom};
\node[draw, green, dashed, minimum height=\yTop - \yBottom, minimum width=\xRight - \xLeft] (-bb) at (0,0) {};
\begin{scope}
\foreach [count=\ei, remember=\ei as \prevei (initially 0)] \elem in {#1} {
\ifnum \prevei=0
\node (-node-\ei) [noders_default, anchor=north east] at (-bb.north east) {\elem};
\else
\node (-node-\ei) [noders_default, anchor=north east] at (-node-\prevei.south east) {\elem};
\fi
}
\end{scope}
}
}
}
% ============================== right ==============================
% the only useful "output" of the pic is "-bb" (invisible) node - it stores geometry of the right part and is used in pics/righttnodes
\tikzset{
pics/rightnodeslayout/.style n args = {1}{
code={
\begin{scope}[local bounding box = layoutBoundingBox]
\foreach [count=\ei, remember=\ei as \prevei (initially 0)] \elem in {#1} {
\ifnum \prevei=0
\node (-node-\ei) [noders_default, draw=none, opacity=0, text opacity=0] {\elem};
\else
\node (-node-\ei) [noders_default, anchor=north east, draw=none, opacity=0, text opacity=0] at (-node-\prevei.south east) {\elem};
\fi
}
\end{scope}
\gettikzxy{(layoutBoundingBox.north west)}{\xLeft}{\yTop};
\gettikzxy{(layoutBoundingBox.south east)}{\xRight}{\yBottom};
\node[draw=none, green, dashed, minimum height=\yTop - \yBottom, minimum width=\xRight - \xLeft] (-bb) at (0,0) {};
}
}
}
% Draw rightnodeslayout => get its "-bb" draw real nodes using "-bb" as reference:
\tikzset{
pics/rightnodes/.style n args = {1}{
code={
\pic (layout) {rightnodeslayout={#1}};
\gettikzxy{(layout-bb.north west)}{\xLeft}{\yTop};
\gettikzxy{(layout-bb.south east)}{\xRight}{\yBottom};
\node[draw, green, dashed, minimum height=\yTop - \yBottom, minimum width=\xRight - \xLeft] (-bb) at (0,0) {};
\begin{scope}
\foreach [count=\ei, remember=\ei as \prevei (initially 0)] \elem in {#1} {
\ifnum \prevei=0
\node (-node-\ei) [noders_default, anchor=north west] at (-bb.north west) {\elem};
\else
\node (-node-\ei) [noders_default, anchor=north west] at (-node-\prevei.south west) {\elem};
\fi
}
\end{scope}
}
}
}
% ============================== LeftCenterRight (lcr) ==============================
% The same approach here, but for the entire leftnodes-center-rigthnodes:
\tikzset{
pics/lcrlayout/.style n args = {3}{
code={
\pic (leftnodes) {leftnodeslayout={#1}};
\gettikzxy{(leftnodes-bb.north west)}{\xLeftL}{\yTopL};
\gettikzxy{(leftnodes-bb.south east)}{\xRightL}{\yBottomL};
\pic (rightnodes) {rightnodeslayout={#3}};
\gettikzxy{(rightnodes-bb.north west)}{\xLeftR}{\yTopR};
\gettikzxy{(rightnodes-bb.south east)}{\xRightR}{\yBottomR};
\begin{scope}[local bounding box = layoutBoundingBoxForLCR]
\node (-center) [nodefx_default, draw=none, opacity=0, text opacity=0] {#2};
\node (fakeleftbbrect) [draw=none, anchor=east, left=20pt of -center.west, minimum height=\yTopL - \yBottomL, minimum width=\xRightL - \xLeftL] {};
\node (fakerightbbrect) [draw=none, anchor=west, right=20pt of -center.east, minimum height=\yTopR - \yBottomR, minimum width=\xRightR - \xLeftR] {};
\end{scope}
\gettikzxy{(layoutBoundingBoxForLCR.north west)}{\xLeft}{\yTop};
\gettikzxy{(layoutBoundingBoxForLCR.south east)}{\xRight}{\yBottom};
\node[draw=none, green, dashed, anchor=south west, minimum height=\yTop - \yBottom, minimum width=\xRight - \xLeft] (-bb) at (\xLeft, \yBottom) {};
}
}
}
\tikzset{
pics/lcrpic/.style n args = {3}{
code={
\pic (-layout) {lcrlayout={{#1}}{#2}{{#3}}};
\gettikzxy{(-layout-bb.north west)}{\xLeft}{\yTop};
\gettikzxy{(-layout-bb.south east)}{\xRight}{\yBottom};
\gettikzxy{(-layout-bb.south)}{\xBbC}{\yBbC};
\gettikzxy{(-layout-center.south)}{\xC}{\yC};
\begin{scope}[xshift=\xBbC - \xC]
\node[draw, blue, dashed, minimum height=\yTop - \yBottom, minimum width=\xRight - \xLeft] (-bb) {};
\pic (-leftnodes) [anchor=west] at (-bb.west) {leftnodes={#1}};
\node (-center) [nodefx_default, anchor=west, right=20pt of -leftnodes-bb.east] {#2};
\pic (rightnodes) [anchor=west, right=20pt of -center.east] {rightnodes={#3}};
\foreach [count=\ei, remember=\ei as \prevei (initially 0)] \elem in {#1} {
\draw[line width=1pt, draw=black!20] (-center) -- (-leftnodes-node-\ei.east);
}
\foreach [count=\ei, remember=\ei as \prevei (initially 0)] \elem in {#3} {
\draw[line width=1pt, draw=black!20] (-center) -- (rightnodes-node-\ei.west);
}
\end{scope}
}
}
}
%
% The interface I want and tests:
%
\pic (a) [anchor=north] at(0, 0) {
lcrpic={{n1}, {n2}, {n3}, {n4}, {n5}, {n6}, {n7}} {Center1:\\many nodes on the left} {{n1}}
};
\pic (b) [anchor=north] at ({$(a-bb.south) - (0cm, 0.4cm)$} -| {$(a-center.south)$}) {
lcrpic={{111111111111111111111111}} {Center2:\\Long nodes on the left} {{11}, {22}, {33}, {44}}
};
\node (f) [nodefx_default] at (-6, -3) {Nodes must be reference-able outside:};
\draw[line width=1pt, draw=red!20] (f) -- (a-leftnodes-node-6);
\draw[line width=1pt, draw=red!20] (f) -- (b-leftnodes-node-1);
\end{tikzpicture}
\end{document}