tcolorbox でノート用紙の外観を作成する; 正しい数の線を描く際の問題

tcolorbox でノート用紙の外観を作成する; 正しい数の線を描く際の問題

水平線と垂直線を描いて、環境内にノートの紙の断片のようなものを作成しようとしていますtcolorbox。問題は、ハードコードしない限り、線の数の上限を定義する方法がわからないことです。これにより、カラー ボックスがページを超えて分割され、ボックスの高さが異なる場合に問題が発生します。線はボックスの下部から描画されます。ボックスに 2 つの異なる長さがある場合、上から均等間隔で描画された線のように見せるのは困難です。

tcolorboxの高さを取得するにはどうすればいいですか?試してみました\tcbテキスト高さしかし、それを垂直線に使用しても機能しません。また、イベント分割を使用してループを記述する方法もわかりません。できれば、線をドキュメントの行間隔のサイズにしたいのですが、これは必須ではありません。高さを取得した後、ボックスの下ではなく上から線画を開始する必要があります。

\documentclass[letterpaper, 10pt]{article}

\usepackage[skins, raster, breakable]{tcolorbox}
\usepackage{tikz}
\usetikzlibrary{decorations,decorations.markings,optics}
\usepackage[english]{babel}
\usepackage{blindtext}

\begin{document}
\pagestyle{empty}

\tikzset{normal lines/.style={gray, very thin}} 

\tcbset{paper/.style={enhanced,colback=green!10,colframe=green!65!black,width=\textwidth,breakable,left=1.3in,
        overlay={
            \begin{tcbclipframe}
              \foreach \y in {0.25, 0.5,...,10.25}
                  \draw[style=normal lines](0,\y in) -- (8.5in, \y in);
              \draw[style=normal lines] (1.25in,0)--(1.25in, 3in);
            \end{tcbclipframe}
        }   
    }   
}
\blindtext[5]
\begin{tcolorbox}[paper]
\blindtext[2]
\end{tcolorbox}

\end{document}

ここに画像の説明を入力してください

答え1

tcolorbox私はこれを のサブスキンで行うことを提案しますenhanced(これは壊れやすいボックスに適しています)。以下に示すコードでは、paperから派生した というスキンを定義しenhancedtcolorboxスタイルpaperを実行させますskin=paper(特に、希望するフレームと背景色の設定など)。また、 、、からそれぞれ派生した 、 のpaperfirst3つのサブスキンも定義します。これらにより、すべてのケースでボックスに希望する外観を与えることができます (壊れていない、上部が壊れていて下部は壊れていない、下部が壊れていて上部は壊れていない、上部と下部の両方が壊れている)。papermiddlepaperlastenhancedfirstenhancedmiddleenhancedlast

enhancedスキンは を設定するため、 、、/tcb/geometry nodes=trueというノードを定義し、の興味深い点にアクセスできるようにします。ここで、 または を使用してボックスの高さを計算できます( 、、は に属しますが には属さないため、これらはまったく同じ結果にはなりません)。以下で定義するスキンでは、ノード を使用して、描画する水平罫線の数を計算し、ボックスが上部で分割されているかどうか、および下部で分割されているかどうかに応じて、垂直罫線の範囲としてとの適切な組み合わせを計算します。描画する水平罫線の数の計算は、たとえば を使用して行うことができます(呼び出し内でを使用して行うこともできます)。frameinteriorsegmentationtitletcolorboxframeinterior/tcb/leftrule/tcb/toprule/tcb/rightrule/tcb/bottomruleframeinteriorpaperinteriorframeinterior\pgfmathtruncatemacroint()\pgfmathsetmacro

注: スタイルに少し変更を加えましたnormal lines。 は大きくなっていますが、で定義されているように、line width罫線は で描画されています。 この描画は 内で行われ、その目的は、罫線の交差部分が罫線内の他の部分よりも暗くならないようにすることです。opacity=.../tcb/paper/rule opacitytransparency group

\documentclass{article}
\usepackage{tcolorbox}
\tcbuselibrary{breakable, skins}
\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{lipsum}

\makeatletter

\tikzset{normal lines/.style={gray, thin}}
\tcbset{paper/left margin/.initial=1.25in,
        paper/line spacing/.initial=1cm,
        paper/rule opacity/.initial=0.4,
        paper/.style={
          skin=paper, colback=green!10, colframe=green!65!black,
          breakable, left=1.3in,
        }
}

\newif\if@paper@broken@top
\newif\if@paper@broken@bottom
\pgfkeys{/tcb/paper/broken top/.is if=@paper@broken@top,
         /tcb/paper/broken bottom/.is if=@paper@broken@bottom
}

% The various parts don't have the same skin when a box is broken. This also
% influences where we want the vertical rule to extend to.
\tcbsubskin{paperfirst}{enhancedfirst}{
  paper/broken top=false, paper/broken bottom=true
}
\tcbsubskin{papermiddle}{enhancedmiddle}{
  paper/broken top=true, paper/broken bottom=true
}
\tcbsubskin{paperlast}{enhancedlast}{
  paper/broken top=true, paper/broken bottom=false
}

\tcbsubskin{paper}{enhanced}{
  skin first=paperfirst, skin middle=papermiddle, skin last=paperlast,
  paper/broken top=false, paper/broken bottom=false,
  overlay={
    \begin{tcbclipinterior}
    \begin{scope}[opacity=\pgfkeysvalueof{/tcb/paper/rule opacity},
                  transparency group]
    % Make sure the vertical rule extends exactly as far as we want, depending
    % on where the box is broken.
    \if@paper@broken@top
      \coordinate (top for vert rule) at (frame.north west);
    \else
      \coordinate (top for vert rule) at (interior.north west);
    \fi
    %
    \if@paper@broken@bottom
      \coordinate (bottom for vert rule) at (frame.south west);
    \else
      \coordinate (bottom for vert rule) at (interior.south west);
    \fi
    %
    \draw[transform canvas={xshift=\pgfkeysvalueof{/tcb/paper/left margin}},
          style=normal lines] (top for vert rule) -- (bottom for vert rule);
    %
    \path let \p1=($(interior.north)-(interior.south)$) in
      \pgfextra{%
        \pgfmathtruncatemacro{\tmp}{veclen(\p1) /
                                    \pgfkeysvalueof{/tcb/paper/line spacing}}%
        \xdef\paperskin@nblines{\tmp}};
    \foreach \i in {1,..., \paperskin@nblines} {
       \pgfmathsetlengthmacro{\paperskin@shift}{
         -\i*\pgfkeysvalueof{/tcb/paper/line spacing}}
       \draw[style=normal lines]
         ([yshift=\paperskin@shift]interior.north west) --
         ([yshift=\paperskin@shift]interior.north east);
    }
    \end{scope}
    \end{tcbclipinterior}
  },
}

\makeatother

\pagestyle{empty}

\begin{document}

\lipsum[1]
\begin{tcolorbox}[paper]
\lipsum[2]
\end{tcolorbox}

\lipsum[3]
\begin{tcolorbox}[paper]
\lipsum[4-5]
\end{tcolorbox}

\end{document}

スクリーンショット

壊れていない箱:

壊れていない箱のクローズアップ

first壊れた箱の一部:

壊れた箱のクローズアップ、最初の部分

last壊れた箱の一部:

壊れた箱の最後の部分のクローズアップ

一部middle(上部が破損)そして下部の縦線も、縦線が必要なだけ伸びた状態で描画できます。

箱の上部と下部が破損しています

注: 私のコードの次の部分:

\tcbsubskin{paper}{enhanced}{
  ...
  overlay={
    ...
    % Make sure the vertical rule extends exactly as far as we want, depending
    % on where the box is broken.
    \if@paper@broken@top
      \coordinate (top for vert rule) at (frame.north west);
    \else
      \coordinate (top for vert rule) at (interior.north west);
    \fi
    %
    \if@paper@broken@bottom
      \coordinate (bottom for vert rule) at (frame.south west);
    \else
      \coordinate (bottom for vert rule) at (interior.south west);
    \fi

次のように書くこともできます:

\newcommand*{\paper@defcoord}[3]{
  \coordinate (#2 for vert rule) at (#1.#3 west);
}

\tcbsubskin{paper}{enhanced}{
  ...
  overlay={
    ...
    % Make sure the vertical rule extends exactly as far as we want, depending
    % on where the box is broken.
    \edef\tmp{\if@paper@broken@top frame\else interior\fi}
    \expandafter\paper@defcoord\expandafter{\tmp}{top}{north}
    \edef\tmp{\if@paper@broken@bottom frame\else interior\fi}
    \expandafter\paper@defcoord\expandafter{\tmp}{bottom}{south}

しかし、最初の方法の方がはるかに読みやすいと思われるため、完全な例ではこれを残しておくことにしました。

答え2

手描きのグリッドの代わりに、TikZ大きな のグリッドを使用できますxstep。次のコードは、考えられる解決策を示しています (tcolorboxドキュメントの 131 ページの例を参考にしています)。壊れたボックスの問題や垂直位置の調整の問題は解決されません。

\documentclass{article}
\usepackage[most]{tcolorbox}
\usepackage{lmodern}
\usepackage{blindtext}

\newtcolorbox{notebook}{
    enhanced,
    breakable,
    colback=green!10,
    colframe=green!65!black,
    left=1.3in,
    underlay={%
        \begin{tcbclipinterior}
        \draw[help lines, ystep=\baselineskip, xstep=\linewidth, 
            shift={(interior.north west)}](interior.south west) grid (interior.north east);
        \draw[help lines] ([xshift=1.25in]interior.north west)--
            ([xshift=1.25in]interior.south west);
        \end{tcbclipinterior}}
    }

\begin{document}
\blindtext[1]
\begin{notebook}
\blindtext[3]
\end{notebook}
\end{document}

ここに画像の説明を入力してください

関連情報