但

Qt 中有布局的概念(例如,垂直布局将所有对象垂直排列并可能对齐它们,水平布局则水平排列,等等...)。

我正在尝试解决一个布局非常有用的问题。也就是说,我想指定 (1) 左侧节点 ( {n1}, {n2}, {n3}, {n4}, ...)、(2) 中心节点的文本、(3) 右侧节点。并期望代码生成具有以下属性的多个节点:

  1. 左侧节点向右对齐,群组节点与中心节点的中心对齐。
  2. 与右节点相同,但是镜像。
  3. 每个节点都必须可以被外部引用
  4. 应该有一个带有锚点的边界框,以便整个“事物”能够排列它们。

下面是它在乳胶中的样子的一个例子:

\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}

相关内容