![在 TikZ 中填写表格框](https://linux22.com/image/281697/%E5%9C%A8%20TikZ%20%E4%B8%AD%E5%A1%AB%E5%86%99%E8%A1%A8%E6%A0%BC%E6%A1%86.png)
我想创建一个附有 IBAN 的 SEPA 银行转账表
我如何创建一个带有N
字段的表单域,每个字段宽度为 5 毫米,并且像图片中那样有分隔线?
目前我使用 for 循环作为解决方法,但这会使代码难以维护。最后我需要一个函数\formline{N}{cellwidth}{label}{value}
来创建完整的表单字段并用可选值填充它:
以下代码可在https://github.com/jonasstein/bankformtex。
\documentclass[a4paper,11pt]{article}
\usepackage[utf8]{inputenc}
\usepackage{tikz}
\usetikzlibrary{shapes}
\thispagestyle{empty} % no pagenumber. The form should be a stand alone macro... later.
\definecolor{SEPAOrange}{RGB}{254,213,161}
\definecolor{SEPADOrange}{RGB}{253,185,19}
\definecolor{SEPABlindcolor}{RGB}{255,0,0}
\begin{document}
\begin{tikzpicture}[x=1 mm, y=-1mm]
\pgfmathsetmacro{\yh}{4.2333} % y heigth step defined as 1/6 inch => 1/6 * 25.4 mm = 4.2333 mm
\pgfmathsetmacro{\xs}{9} % x start (own definition)
\pgfmathsetmacro{\xe}{141.5} % x end (own definition)
\pgfmathsetmacro{\widefield}{4.9859} % def: 134.62 mm / 27
\pgfmathsetmacro{\narrowfiels}{3.9594} % def: 134.62 mm/ 34
\filldraw[draw=black,color=SEPAOrange] (7.62, 4.5*\yh) rectangle (149.86-7.62,105.83-1); %orange background
\filldraw[draw=black,color=white] (\xs, 5*\yh) rectangle (\xe, 6.5*\yh -1.5); %Recepient 27 Char
\foreach \x in {1,...,26}
{
\draw[color=SEPAOrange, line width=0.3mm] (7.62 + \x*\widefield, 5*\yh ) -- (7.62 + \x*\widefield, 6.5*\yh);
\draw[color=SEPAOrange, line width=0.7mm] (7.62 + \x*\widefield, 5.8*\yh ) -- (7.62 + \x*\widefield, 6.5*\yh);
}
\filldraw[draw=black,color=white] (\xs, 7*\yh) rectangle (\xe, 8.5*\yh -1.5); %IBAN 34 Char
\foreach \x in {1,...,33}
\draw[color=SEPAOrange, line width=0.3mm] (7.62 + \x*4, 7*\yh ) -- (7.62 + \x*4, 8.5*\yh);
\filldraw[draw=black,color=white] (\xs, 9*\yh) rectangle (\xe, 10.5*\yh -1.5); %BIC
\filldraw[draw=black,color=white] (\xe-12*5, 11*\yh) rectangle (\xe, 12.5*\yh -1.5); %Value 12 Char
\filldraw[draw=black,color=white] (\xs, 13*\yh) rectangle (\xe, 14.5*\yh -1.5); %Subject1
\filldraw[draw=black,color=white] (\xs, 15*\yh) rectangle (\xe, 16.5*\yh -1.5); %Subject2
\filldraw[draw=black,color=white] (\xs, 17*\yh) rectangle (\xe, 18.5*\yh -1.5); %Subject3
\filldraw[draw=black,color=white] (\xs, 19*\yh) rectangle (\xs+22*5, 20.5*\yh -1.5); % IBAN 22 Char
\filldraw[draw=black,color=white] (149.86-17.59, 19* \yh) rectangle (\xe, 20.5*\yh -1.5); % counter
\filldraw[draw=black,color=white] (\xs, 21* \yh) rectangle (42.52, 24.5*\yh); % date
\filldraw[draw=black,color=white] (42.52+5, 21*\yh) rectangle (149.86-17.59, 24.5*\yh); % signature
\draw[color=SEPADOrange] (0, 4.5 *\yh) --(149.86, 4.5*\yh); upper dark orange line
\draw[color=SEPADOrange] (0, 20.5 *\yh) --(149.86, 20.5*\yh); lower dark orange line
\draw[draw=black,color=black, line width=0.3mm] (0,0) rectangle (149.86,105.83); % black border
%\draw[align=left] at (\yh,\yh) {SEPA-Überweisung};
\end{tikzpicture}
\end{document}
答案1
用法
\formline*(coord)[field width][scope options]{N}{label}[value]<dividers>
强制参数
coord
:放置线的位置;锚点位于west
第一个字段。N
:字段数。label
:线路名称。
可选参数
*
:忽略中的空格value
。field width
:字段的宽度。scope options
:选项被传递给{scope}
。value
:填写一些内容,应仅包含普通的人物。dividers
:在文件之间添加分隔符;可以是文件编号的逗号列表,也可以是every n
(n
可以是正数或负数)。
例子
\begin{tikzpicture}
% background
\fill [SEPAOrange] (0,0) rectangle (15,12);
% formlines
\formline(1,10){25}{Bank}[Deutsche Bank Hamburg]
\formline(1,9)[6mm]{5}{Number 1}[123456]
\formline(1,8)[6mm]{5}{Number 2}[1234]
\formline*(1,7){22}{IBAN 1}[DE00 2105 0170 0012 3456 78]<every 4>
% dividers every 4th field from right
\formline*(1,6){22}{IBAN 2}<every -4>% dividers every 4th from left
\formline*(1,5){22}{IBAN 3}<2,5,10,15,20>% irregular dividers
\end{tikzpicture}
笔记
- 每个字段都是一个单独的节点,并以 命名
form field label n
,其中label
是参数值,n
是字段的编号(从 0 开始)。您可以使用此节点名称来添加框架或类似的东西。 - 有几种 TikZ 样式可用于改变外观。
- 我在代码中添加了一些解释——如有不清楚之处请询问!
完整代码
\documentclass{article}
% packages
\usepackage{tikz,xparse}
\usetikzlibrary{positioning,fit,calc}
% colors
\definecolor{SEPAOrange}{RGB}{254,213,161}
\definecolor{SEPADOrange}{RGB}{253,185,19}
% switch on expl3 syntax
% (_ and : become part of macro names; spaces are ignored; ~ is normal space)
\ExplSyntaxOn
% make @ available as part of macro name
\makeatletter
% commad to genreate internal lengths
% use \form_generate_lengths:n {<comma list>}
\cs_new:Npn \form_generate_lengths:n #1 {
\clist_set:Nn \l_tmpa_clist { #1 }
\clist_map_inline:Nn \l_tmpa_clist {
\expandafter\newlength \csname form @ x ##1 \endcsname
\expandafter\newlength \csname form @ y ##1 \endcsname
}
}
% gererate internal length used in node shapes
\form_generate_lengths:n {
A, Ab, At, Abt,
B, Bb, Bt, Bbt,
D,
C,
}
% sep between fields
\dim_new:N \g_form_sep_dim
\dim_set:Nn \g_form_sep_dim { 0.5pt }
% dimensions of the edges in fields
\dim_new:N \g_form_x_edge_dim
\dim_set:Nn \g_form_x_edge_dim { 0.5pt }
\dim_new:N \g_form_y_edge_dim
\dim_set:Nn \g_form_y_edge_dim { 3pt }
\dim_new:N \formdividerwidth
\dim_set:Nn \formdividerwidth { 2\g_form_x_edge_dim + \g_form_sep_dim }
\dim_new:N \formdividerheight
\dim_set:Nn \formdividerheight { \g_form_y_edge_dim }
% new node shapes for fields
\pgfdeclareshape{form~field~middle}{% from p. 631 in pgfmanual.pdf
\inheritsavedanchors[from=rectangle]
\inheritanchorborder[from=rectangle]
\inheritanchor[from=rectangle]{base}
\inheritanchor[from=rectangle]{center}
\inheritanchor[from=rectangle]{north}
\inheritanchor[from=rectangle]{north~east}
\inheritanchor[from=rectangle]{east}
\inheritanchor[from=rectangle]{south~east}
\inheritanchor[from=rectangle]{south}
\inheritanchor[from=rectangle]{south~west}
\inheritanchor[from=rectangle]{west}
\inheritanchor[from=rectangle]{north~west}
\backgroundpath{% this is new
% store corners
\southwest \form@xA = \pgf@x \form@yA = \pgf@y
\northeast \form@xC = \pgf@x \form@yC = \pgf@y
\form@xB = \form@xC \form@yB = \form@yA
\form@xD = \form@xA \form@yD = \form@yC
% calculate edges
\form@xAt = \form@xA
\form@yAt = \form@yA \advance \form@yAt by \g_form_y_edge_dim
\form@xAb = \form@xA \advance \form@xAb by \g_form_x_edge_dim
\form@yAb = \form@yA
\form@xAbt = \form@xAb
\form@yAbt = \form@yAt
\form@xBt = \form@xB
\form@yBt = \form@yB \advance \form@yBt by \g_form_y_edge_dim
\form@xBb = \form@xB \advance \form@xBb by -\g_form_x_edge_dim
\form@yBb = \form@yB
\form@xBbt = \form@xBb
\form@yBbt = \form@yBt
% construct main path
\pgfpathmoveto{\pgfpoint{\form@xAt}{\form@yAt}}
\pgfpathlineto{\pgfpoint{\form@xD}{\form@yD}}
\pgfpathlineto{\pgfpoint{\form@xC}{\form@yC}}
\pgfpathlineto{\pgfpoint{\form@xBt}{\form@yBt}}
\pgfpathlineto{\pgfpoint{\form@xBbt}{\form@yBbt}}
\pgfpathlineto{\pgfpoint{\form@xBb}{\form@yBb}}
\pgfpathlineto{\pgfpoint{\form@xAb}{\form@yAb}}
\pgfpathlineto{\pgfpoint{\form@xAbt}{\form@yAbt}}
\pgfpathlineto{\pgfpoint{\form@xAt}{\form@yAt}}
\pgfpathclose
}
}
\pgfdeclareshape{form~field~start}{
\inheritsavedanchors[from=rectangle]
\inheritanchorborder[from=rectangle]
\inheritanchor[from=rectangle]{center}
\inheritanchor[from=rectangle]{base}
\inheritanchor[from=rectangle]{north}
\inheritanchor[from=rectangle]{north~east}
\inheritanchor[from=rectangle]{east}
\inheritanchor[from=rectangle]{south~east}
\inheritanchor[from=rectangle]{south}
\inheritanchor[from=rectangle]{south~west}
\inheritanchor[from=rectangle]{west}
\inheritanchor[from=rectangle]{north~west}
\backgroundpath{% this is new
% store corners
\southwest \form@xA = \pgf@x \form@yA = \pgf@y
\northeast \form@xC = \pgf@x \form@yC = \pgf@y
\form@xB = \form@xC \form@yB = \form@yA
\form@xD = \form@xA \form@yD = \form@yC
% calculate edges
\form@xAt = \form@xA
\form@yAt = \form@yA \advance \form@yAt by \g_form_y_edge_dim
\form@xAb = \form@xA \advance \form@xAb by \g_form_x_edge_dim
\form@yAb = \form@yA
\form@xAbt = \form@xAb
\form@yAbt = \form@yAt
\form@xBt = \form@xB
\form@yBt = \form@yB \advance \form@yBt by \g_form_y_edge_dim
\form@xBb = \form@xB \advance \form@xBb by -\g_form_x_edge_dim
\form@yBb = \form@yB
\form@xBbt = \form@xBb
\form@yBbt = \form@yBt
% construct main path
\pgfpathmoveto{\pgfpoint{\form@xA}{\form@yA}}
\pgfpathlineto{\pgfpoint{\form@xD}{\form@yD}}
\pgfpathlineto{\pgfpoint{\form@xC}{\form@yC}}
\pgfpathlineto{\pgfpoint{\form@xBt}{\form@yBt}}
\pgfpathlineto{\pgfpoint{\form@xBbt}{\form@yBbt}}
\pgfpathlineto{\pgfpoint{\form@xBb}{\form@yBb}}
\pgfpathlineto{\pgfpoint{\form@xA}{\form@yA}}
\pgfpathclose
}
}
\pgfdeclareshape{form~field~end}{
\inheritsavedanchors[from=rectangle]
\inheritanchorborder[from=rectangle]
\inheritanchor[from=rectangle]{center}
\inheritanchor[from=rectangle]{base}
\inheritanchor[from=rectangle]{north}
\inheritanchor[from=rectangle]{north~east}
\inheritanchor[from=rectangle]{east}
\inheritanchor[from=rectangle]{south~east}
\inheritanchor[from=rectangle]{south}
\inheritanchor[from=rectangle]{south~west}
\inheritanchor[from=rectangle]{west}
\inheritanchor[from=rectangle]{north~west}
\backgroundpath{% this is new
% store corners
\southwest \form@xA = \pgf@x \form@yA = \pgf@y
\northeast \form@xC = \pgf@x \form@yC = \pgf@y
\form@xB = \form@xC \form@yB = \form@yA
\form@xD = \form@xA \form@yD = \form@yC
% calculate edges
\form@xAt = \form@xA
\form@yAt = \form@yA \advance \form@yAt by \g_form_y_edge_dim
\form@xAb = \form@xA \advance \form@xAb by \g_form_x_edge_dim
\form@yAb = \form@yA
\form@xAbt = \form@xAb
\form@yAbt = \form@yAt
\form@xBt = \form@xB
\form@yBt = \form@yB \advance \form@yBt by \g_form_y_edge_dim
\form@xBb = \form@xB \advance \form@xBb by -\g_form_x_edge_dim
\form@yBb = \form@yB
\form@xBbt = \form@xBb
\form@yBbt = \form@yBt
% construct main path
\pgfpathmoveto{\pgfpoint{\form@xAt}{\form@yAt}}
\pgfpathlineto{\pgfpoint{\form@xD}{\form@yD}}
\pgfpathlineto{\pgfpoint{\form@xC}{\form@yC}}
\pgfpathlineto{\pgfpoint{\form@xB}{\form@yB}}
\pgfpathlineto{\pgfpoint{\form@xAb}{\form@yAb}}
\pgfpathlineto{\pgfpoint{\form@xAbt}{\form@yAbt}}
\pgfpathlineto{\pgfpoint{\form@xAt}{\form@yAt}}
\pgfpathclose
}
}
% new command to draw a line of fiels
% usage: \formline*(coord)[field width][scope options]{N}{label}[value]<dividers>
% #1 #2 #3 #4 #5 #6 #7 #8
% * = ignore spaces in [value]
% required: #2, #5, #6,
% optional: #1, #3, #4, #7, #8
\NewDocumentCommand { \formline } { s r() O{3mm} O{} m m o d<> } {
% save field width
\dim_set:Nn \l_tmpa_dim { #3 }
% begin a scope
\begin{scope}
[every~form~field/.append~style={minimum~width=\dim_use:N \l_tmpa_dim}, #4]
% draw fields
%% set temp counter to 0
\int_set:Nn \l_tmpa_int {0}
%% first node (number 0)
\node (form~field~#6~0) [at={(#2)}, every~form~field~start] {\strut};
%% middle nodes, go through list form 1 to N-1
\int_step_inline:nnnn { 1 } { 1 } { #5 - 2 } {
%%% draw node
\node (form~field~#6~##1) [
every~form~field~middle,
right=\dim_use:N \g_form_sep_dim of~form~field~#6~\int_use:N \l_tmpa_int
] {\strut};
%%% incremet counter by 1
\int_incr:N \l_tmpa_int
}
%% draw last node (number N)
\node (form~field~#6~\int_eval:n { #5 - 1 }) [
every~form~field~end,
right=\dim_use:N \g_form_sep_dim of~form~field~#6~\int_use:N \l_tmpa_int
] {\strut};
% draw label
\node [every~form~label, above~right=0pt~of~form~field~#6~0.north~west] {#6};
% add value, if exist
\IfValueT { #7 } {
%% save value to token list
\tl_set:Nn \l_tmpa_tl { #7 }
%% replace input space with space token
\IfBooleanF { #1 } {
\tl_replace_all:Nnn \l_tmpa_tl { ~ } { \c_space_token }
}
%% set temp counter to 0
\int_set:Nn \l_tmpa_int { 0 }
%% iterate through tokes and print digits above fields
\tl_map_inline:Nn \l_tmpa_tl {
%%% chack overlong values
\int_compare:nT { \l_tmpa_int = #5 } {
\node at (form~field~#6~\int_eval:n { \l_tmpa_int - 1 })
[fill=red, font=\bfseries] {ERROR:~value~too~long};% some error message
\tl_map_break:
}
%%% draw digit
\node [every~form~digit] at (form~field~#6~\int_use:N \l_tmpa_int.base) { ##1 };
%%% incremet counter by 1
\int_incr:N \l_tmpa_int
}
}
% add sub-dividers, if exist
\IfValueT { #8 } {
%% save lowercase version of #7 to token list
\tl_set:Nn \l_tmpa_tl { #8 }
%% if it contains "every"
\tl_if_in:NnTF \l_tmpa_tl { every } {
%%% remove "every"
\tl_remove_all:Nn \l_tmpa_tl { every }
%%% save to int
\int_set:Nn \l_tmpa_int { \l_tmpa_tl }
%%% from left (> 0) or right (< 0)?
\int_compare:nTF { \l_tmpa_int > 0 } {
%%%% draw marks from left
\int_step_inline:nnnn { \l_tmpa_int - 1 } { \l_tmpa_int } { #5 - 2 } {
\node at
($(form~field~#6~##1.south~east)+(\dim_use:N \g_form_sep_dim / 2,0)$)
[every~form~divider] {};
}
} {
%%%% draw marks from right
\int_step_inline:nnnn { #5 - 1 + \l_tmpa_int } { \l_tmpa_int } { 0 } {
\node at
($(form~field~#6~##1.south~east)+(\dim_use:N \g_form_sep_dim / 2,0)$)
[every~form~divider] {};
}
}
} {
%%% iterate throug comma list
\clist_map_inline:nn { #8 } {
\node at
($(form~field~#6~##1.south~east)+(\dim_use:N \g_form_sep_dim / 2,0)$)
[every~form~divider] {};
}
}
}
\end{scope}
}
% switch off expl3 syntax and @
\ExplSyntaxOff\makeatother
\tikzset{
every form field/.style = {
fill=white,
inner sep=0pt,
minimum height=4mm,
align=center,
},
every form field middle/.style = {
every form field,
form field middle,
},
every form field start/.style = {
every form field,
form field start,
anchor=south west,
},
every form field end/.style = {
every form field,
form field end,
},
every form label/.style = {
fill=white, text=SEPADOrange,
inner sep=1pt,
outer sep=0pt,
font=\tiny\sffamily\bfseries,
},
every form digit/.style = {
anchor=base,
font=\ttfamily,
inner sep=0pt,
},
every form divider/.style = {
fill=black,
inner sep=0pt,
outer sep=0pt,
anchor=south,
minimum width=\formdividerwidth,
minimum height=\formdividerheight,
},
}
\begin{document}
\begin{tikzpicture}
% background
\fill [SEPAOrange] (0,0) rectangle (15,12);
% formlines
\formline(1,10){25}{Bank}[Deutsche Bank Hamburg]
\formline(1,9)[6mm]{5}{Number 1}[123456]
\formline(1,8)[6mm]{5}{Number 2}[1234]
\formline*(1,7){22}{IBAN 1}[DE00 2105 0170 0012 3456 78]<every 4>
% dividers every 4th field from left
\formline*(1,6){22}{IBAN 2}<every -4>% dividers every 4th from right
\formline*(1,5){22}{IBAN 3}<2,5,10,15,20>% irregular dividers
\end{tikzpicture}
\end{document}