forum icon indicating copy to clipboard operation
forum copied to clipboard

能否扩展diagbox的斜线类型

Open chenxiao445566 opened this issue 2 years ago • 6 comments

diagbox宏包定义了几种表格线样式,能满足基本需求。但是对于复杂的表格斜线就有些难以实现了,能否定义一个更自由的画线命令,通过平移左上角和右下角的坐标实现画线自由? 503d269759ee3d6d7133bc6941166d224e4ade9e

chenxiao445566 avatar May 20 '22 07:05 chenxiao445566

tikz 的路子。

  • 普通表格环境,见 https://tex.stackexchange.com/a/278162 ,
  • nicematrix 包的表格环境,见 https://ask.latexstudio.net/ask/question/7454.html ,
  • tabularray 包的表格环境,见下方例子。注意只是概念验证型尝试,主要模仿的 tabularray library diagbox 。(因为题主没有写出来的实际需求就是 tblr 环境)
\documentclass{article}
\usepackage{tabularray}

\ExplSyntaxOn
\NewTblrLibrary { tikzbox }
  {
    \RequirePackage{ tikz }
    \NewContentCommand \tikzbox [2] []
      {
        \__tblr_lib_tikzbox_fix:n
          {
            \tikz[baseline=\dim_use:N \box_dp:N \l__tblr_strut_dp_box + \belowsep, ##1] {##2}
          }
      }
  }

\box_new:N \l__tblr_tikz_box

\cs_new_protected:Npn \__tblr_lib_tikzbox_fix:n #1
  {
    \hbox_set:Nn \l__tblr_tikz_box {#1}
    \box_set_ht:Nn \l__tblr_tikz_box { \box_ht:N \l__tblr_tikz_box - \abovesep }
    \box_set_dp:Nn \l__tblr_tikz_box { \box_dp:N \l__tblr_tikz_box - \belowsep }
    \box_set_wd:Nn \l__tblr_tikz_box { \box_wd:N \l__tblr_tikz_box - \rightsep }
    \skip_horizontal:n { -\leftsep }
    \box_use:N \l__tblr_tikz_box
  }
\ExplSyntaxOff

\UseTblrLibrary{diagbox, tikzbox}

\begin{document}

\verb|\diagbox{Aa}{Pp}|\par
\begin{tblr}{hlines,vlines}
  \diagbox{Aa}{Pp} & Beta & Gamma \\
  Epsilon & Zeta & Eta \\
  Iota & Kappa & Lambda \\
\end{tblr}
\bigskip

\verb|\tikzbox{<tikz drawing code>}|\par
\begin{tblr}{hlines,vlines}
  \tikzbox{
    \useasboundingbox (0,0) rectangle (3,1);
    \pgfnodealias{cbb}{current bounding box}
    \draw
      (cbb.north west) -- (cbb.south east)
      (cbb.north west) -- (cbb.south);
  }
   & Beta & Gamma \\
  Epsilon & Zeta & Eta \\
  Iota & Kappa & Lambda \\
\end{tblr}

\end{document}

image

注意,\tikzbox 的限制和 \diagbox 相同,需要手动保证是所在行最高、所在列最宽的单元格。

diagbox 包不但支持绘制斜表线,而且能根据表头内容自动计算单元格大小(而且这是重头戏)。实现上,单元格内容是一个(pict2e 包拓展的)picture 环境,斜表线用 \Line 绘制,表头文字用 \put 添加。如果只是增加斜线,找到实现里 \Line 的地方,增加更多 \Line 就行。如果既要添加斜线,又要添加表头文字并自动计算位置关系,需要解更多的方程。

\tikzbox 就只能画线,表头内容要手动添加(\node),线和内容不重叠也要手动保证。

muzimuzhi avatar May 21 '22 03:05 muzimuzhi

感谢解答!表头内容手动添加没问题的,提一个建议,能否实现表头行文字竖直居中? QQ图片20220521173244 红圈的文字偏下了,能否垂直方向居中?

chenxiao445566 avatar May 21 '22 09:05 chenxiao445566

\NewTblrLibrary { tikzbox }
  {
    \RequirePackage{ tikz }
    \NewContentCommand \tikzbox [2] []
      {
        \__tblr_lib_tikzbox_fix:n
          {
-             \tikz[baseline=\dim_use:N \box_dp:N \l__tblr_strut_dp_box + \belowsep, ##1] {##2}
+             $\vcenter{\hbox{\tikz[##1] {##2}}}$
          }
      }
  }

这样就把纵向偏离值降到和 \diagbox 一个水平了

一些比较例子

image

\documentclass{article}
\usepackage[margin=1cm]{geometry}
\usepackage{tabularray}

\ExplSyntaxOn
\NewTblrLibrary { tikzbox }
  {
    \RequirePackage{ tikz }
    \NewContentCommand \tikzbox [2] []
      {
        \__tblr_lib_tikzbox_fix:n { $\vcenter{\hbox{\tikz[##1] {##2}}}$ }
      }
  }

\box_new:N \l__tblr_tikz_box

\cs_new_protected:Npn \__tblr_lib_tikzbox_fix:n #1
  {
    \hbox_set:Nn \l__tblr_tikz_box {#1}
    \box_set_ht:Nn \l__tblr_tikz_box { \box_ht:N \l__tblr_tikz_box - \abovesep }
    \box_set_dp:Nn \l__tblr_tikz_box { \box_dp:N \l__tblr_tikz_box - \belowsep }
    \box_set_wd:Nn \l__tblr_tikz_box { \box_wd:N \l__tblr_tikz_box - \rightsep }
    \skip_horizontal:n { -\leftsep }
    \box_use:N \l__tblr_tikz_box
  }
\ExplSyntaxOff

\UseTblrLibrary{diagbox, tikzbox}

\begin{document}

\noindent\verb|\diagbox[...]{...}{...}|\par

\newcommand\diagboxtest[3]{%
  \begin{tblr}{hlines, vlines, baseline=3, #1}
    \diagbox[#2]{Aa}{Pp} 
            & Beta  & #3      \\
    Epsilon & Zeta  & Eta     \\
       Iota & Kappa & Lambda \\
  \end{tblr}%
}

\def\diagboxtests#1#2{%
  \texttt{\detokenize{#1}}\quad
  \diagboxtest{#1}   {}            {Gamma}\quad
  \diagboxtest{#1,#2}{height=1.2cm}{{Gamma \\ Gamma}}\quad
  \diagboxtest{#1,#2}{height=1.3cm}{{Gamma \\ Gamma}}\par
}

\diagboxtests{row{1}=t}{cell{1}{1}=cyan!20}
\diagboxtests{row{1}=m}{}
\diagboxtests{row{1}=b}{cell{1}{1}=cyan!20}
\bigskip

\noindent\verb|\tikzbox{<tikz drawing code>}|\par

\newcommand\tikzboxtest[4]{%
  \begin{tblr}{hlines, vlines, baseline=3, #1}
    \tikzbox[#4]{
      \useasboundingbox (0,0) rectangle (2,#2);
      \pgfnodealias{cbb}{current bounding box}
      \draw
        (cbb.north west) -- (cbb.south east)
        (cbb.north west) -- (cbb.south);
    }
            & Beta  & #3      \\
    Epsilon & Zeta  & Eta     \\
       Iota & Kappa & Lambda \\
  \end{tblr}
}

\def\tikzboxtests#1#2{%
  \texttt{\detokenize{#1}}\quad
  \tikzboxtest{#1}   {1cm}  {Gamma}           {}\quad
  \tikzboxtest{#1,#2}{1.2cm}{{Gamma \\ Gamma}}{}\quad
  \tikzboxtest{#1,#2}{1.3cm}{{Gamma \\ Gamma}}{}\par
}

\tikzboxtests{row{1}=t}{cell{1}{1}=cyan!20}
\tikzboxtests{row{1}=m}{}
\tikzboxtests{row{1}=b}{cell{1}{1}=cyan!20}

\end{document}

muzimuzhi avatar May 21 '22 12:05 muzimuzhi

不错。其中 \NewContentCommand 用于在表格内重定义已有的命令。如果 \tikzbox 这个命令没有任何宏包用过,也可以直接用 \NewDocumentCommand 来定义它。

lvjr avatar May 22 '22 07:05 lvjr

如果只是画线的话,似乎用 l3draw 也可以?用 tikz 有点太重了。

stone-zeng avatar May 22 '22 11:05 stone-zeng

不错。其中 \NewContentCommand 用于在表格内重定义已有的命令。如果 \tikzbox 这个命令没有任何宏包用过,也可以直接用 \NewDocumentCommand 来定义它。

@lvjr 有点想让 \tikzbox 只在 tblr 环境内有定义

muzimuzhi avatar May 22 '22 12:05 muzimuzhi