我想创建一个自动计算发票的环境。
表格可以完美地适应页面(当然)tabularx
。但是,计算出错了,因为 LaTeX 多次创建表格以找出列宽X
。
计算工作很顺利,tabular
但表格是否完全适合页面则取决于字体设置。
因此,我尝试手动计算一个变量列的宽度,但效果并不理想。有没有更好的方法可以解决这个问题?
\documentclass{scrlttr2}
\usepackage{tgheros}
\renewcommand\familydefault{\sfdefault}
\RequirePackage{xspace}
% =====================================
% correct number displaying
\usepackage[mode=text, reset-text-series = false, separate-uncertainty, group-digits=integer, group-minimum-digits = 4]{siunitx}
\sisetup{group-separator = {\,}, input-decimal-markers={,.}, output-decimal-marker = {,}}
\newcommand{\EURsimple}[1]{
\sisetup{minimum-decimal-digits=2, group-separator = {.}, output-decimal-marker = {,}}
#1
\sisetup{minimum-decimal-digits=0, group-separator = {\,}, output-decimal-marker = {,}}
}
\newcommand{\EUR}[1]{
\num[minimum-decimal-digits=2, group-separator = {.}, output-decimal-marker = {,}]{#1}\,€
}
% =====================================
% automatic item numbering
\newcommand{\startnumberedlist}{\newcounter{numberedlistcounter}}
\newcommand{\numberedlistitem}{\stepcounter{numberedlistcounter}\thenumberedlistcounter}
% =====================================
% calculation
\RequirePackage{calculator}
\newcommand{\resetinvoicesum}{\ADD{0}{0}{\invoicesum}}
\newcommand{\addtoinvoicesum}[1]{\ADD{\invoicesum}{#1}{\invoicesum}\GLOBALCOPY{\invoicesum}{\invoicesum}}
% =====================================
% trying to calculate the needed width of the variable width column
\newlength{\invoicedescwidth}
\setlength{\invoicedescwidth}{\textwidth}
\newlength{\invoicerestwidth}
\settowidth{\invoicerestwidth}{\textbf{Pos. Anzahl Rechnungsbetrag Gesamtpreis}}
\addtolength{\invoicedescwidth}{-\invoicerestwidth}
\addtolength{\invoicedescwidth}{-15ex} % <= this is not variable enough for different fonts.
% =====================================
% invoice environment
\RequirePackage{booktabs}
\newenvironment{invoice}[1][]{\startnumberedlist\resetinvoicesum\par\noindent
\centering\begin{tabular}{rp{\invoicedescwidth}S[table-format=5.1]S[table-format=5.4]r}%
\toprule[0.7pt]\textbf{Pos.} & \textbf{Beschreibung} & \textbf{Anzahl} & \textbf{Einzelpreis} & \textbf{Gesamtpreis} \\ \toprule[0.7pt]}
{\midrule[0.7pt]
&&& \textbf{Rechnungsbetrag} & \textbf{\EUR{\invoicesum}} \\ \cmidrule[0.7pt]{4-5} \end{tabular}%
}
% invoiceitem, #1: description, #2: count, #3: price per item
\newcommand{\invoiceitem}[3]{
\numberedlistitem & #1 & #2 & \EURsimple{#3} & \MULTIPLY{#2}{#3}{\tempsum} \ROUND[2]{\tempsum}{\tempsum} \addtoinvoicesum{\tempsum} \EUR{\tempsum}\\} % price calculation and sum up all prices
\usepackage{Blindtext}
\begin{document}
\begin{letter}{recipient}
\opening{Hello}
\Blindtext[1]
\begin{invoice}
\invoiceitem{Arbeitszeit in h}{800}{15}
\invoiceitem{Schrauben}{2134}{0.1}
\invoiceitem{Strommenge in kWh}{303.5}{0.3175}
\invoiceitem{Position C}{2}{1123.1}
\end{invoice}
\end{letter}
\end{document}
附言:我也尝试过,tabularray
但是这似乎无法正确地将小数点处的数字排列起来S
。siunitx
答案1
一些计算
\newlength{\invoicedescwidth}
\setlength{\invoicedescwidth}{\textwidth}
\newlength{\invoicerestwidth}
\settowidth{\invoicerestwidth}{\textbf{Pos. Anzahl Rechnungsbetrag Gesamtpreis}}
\addtolength{\invoicedescwidth}{-\invoicerestwidth}
\addtolength{\invoicedescwidth}{-15ex} % <= this is not variable enough for different fonts.
是可疑的。例如,你为什么不把文本部分转换为\textsf
?为什么字符串中有空格Pos. Anzahl Rechnungsbetrag Gesamtpreis
?从哪里来的15ex
?我建议你用
% manual calculation of required column width
\newlength\mylenA
\newlength\invoicedescwidth
\settowidth\mylenA{% some text, some numbers, no spaces, all \textsf
\textsf{\textbf{Pos.Gesamtpreis}22\,124,511.123,3175}}
\setlength\invoicedescwidth{%
\dimexpr\textwidth-\mylenA-8\tabcolsep\relax}
\documentclass{scrlttr2}
\usepackage{tgheros}
\renewcommand\familydefault{\sfdefault}
\usepackage{xspace}
\usepackage{booktabs}
\usepackage{blindtext}
% correct number displaying
\usepackage[mode=text,
reset-text-series = false,
separate-uncertainty,
group-digits=integer,
group-minimum-digits = 4
]{siunitx}
\sisetup{group-separator = {\,},
input-decimal-markers={,.},
output-decimal-marker = {,}}
\newcommand{\EURsimple}[1]{
\sisetup{minimum-decimal-digits=2,
group-separator = {.},
output-decimal-marker = {,}}
#1
\sisetup{minimum-decimal-digits=0,
group-separator = {\,},
output-decimal-marker = {,}}
}
\newcommand{\EUR}[1]{
\num[minimum-decimal-digits=2,
group-separator = {.},
output-decimal-marker = {,}]{#1}\,€%
}
% automatic item numbering
\newcounter{numberedlistcounter}
\newcommand{\resetnumberedlist}{%
\setcounter{numberedlistcounter}{0}}
\newcommand{\numberedlistitem}{%
\stepcounter{numberedlistcounter}%
\thenumberedlistcounter}
% manual calculation of required column width
\newlength\mylenA
\newlength\invoicedescwidth
\settowidth\mylenA{%
\textsf{\textbf{Pos.Gesamtpreis}22\,124,511.123,3175}}
\setlength\invoicedescwidth{%
\dimexpr\textwidth-\mylenA-8\tabcolsep\relax}
% calculations
\RequirePackage{calculator}
\newcommand{\resetinvoicesum}{\ADD{0}{0}{\invoicesum}}
\newcommand{\addtoinvoicesum}[1]{\ADD{\invoicesum}{#1}{\invoicesum}\GLOBALCOPY{\invoicesum}{\invoicesum}}
% invoice environment
\newenvironment{invoice}{%
\resetnumberedlist\resetinvoicesum
\medskip\par\noindent
\begin{tabular}{@{}
l
>{\raggedright}p{\invoicedescwidth}
S[table-format=5.1]
S[table-format=5.4]
r @{}}%
\toprule[0.7pt]
\textbf{Pos.} &
\textbf{Beschreibung} &
{\textbf{Anzahl}} &
{\textbf{Einzelpreis}} &
\textbf{Gesamtpreis} \\
\midrule[0.7pt]}{%
\bottomrule[0.7pt]
\addlinespace
\multicolumn{5}{r@{}}{%
\textbf{Rechnungsbetrag}\hspace{0.75em}%
\textbf{\EUR{\invoicesum}}} \\
\addlinespace
\end{tabular}
\par
}
\newcommand{\invoiceitem}[3]{
\numberedlistitem &
#1 & #2 &
\EURsimple{#3} &
\MULTIPLY{#2}{#3}{\tempsum}
\ROUND[2]{\tempsum}{\tempsum}
\addtoinvoicesum{\tempsum}
\EUR{\tempsum}\\}
\begin{document}
\begin{letter}{recipient}
\opening{Hello}
\Blindtext[1]
\begin{invoice}
\invoiceitem{Arbeitszeit in h}{800}{15}
\invoiceitem{Schrauben}{2134}{0.1}
\invoiceitem{Strommenge in kWh}{303.5}{0.3175}
\invoiceitem{Position C}{2}{1123.1}
\end{invoice}
\end{letter}
\end{document}
附录解决 OP 的后续评论之一:如果您使用非默认的无衬线字体 - 尤其是使用可变宽度数字的字体 - 我建议您延迟计算长度参数\mylenA
,\invoicedescwidth
直到之后\begin{document}
并将代码块更改为
\newlength\mylenA
\newlength\invoicedescwidth
\settowidth\mylenA{%
\textsf{\textbf{Pos.Gesamtpreis}%
\num[group-separator={\,}]{22222,2}%
\num[group-separator={.}]{22222,2222}}}
\setlength\invoicedescwidth{%
\dimexpr\textwidth-\mylenA-8\tabcolsep\relax}
答案2
环境{NiceTabular}
提供了使用与 类似的列的nicematrix
能力。与 不同,不会在运行 LaTeX 期间多次编译临时框中的表格,而是将信息写入文件(并且需要运行几次 LaTeX)。X
tabularx
tabularx
nicematrix
aux
\documentclass{scrlttr2}
\usepackage{nicematrix}
\usepackage{tgheros}
\renewcommand\familydefault{\sfdefault}
\RequirePackage{xspace}
% =====================================
% correct number displaying
\usepackage[mode=text, reset-text-series = false, separate-uncertainty, group-digits=integer, group-minimum-digits = 4]{siunitx}
\sisetup{group-separator = {\,}, input-decimal-markers={,.}, output-decimal-marker = {,}}
\newcommand{\EURsimple}[1]{
\sisetup{minimum-decimal-digits=2, group-separator = {.}, output-decimal-marker = {,}}
#1
\sisetup{minimum-decimal-digits=0, group-separator = {\,}, output-decimal-marker = {,}}
}
\newcommand{\EUR}[1]{
\num[minimum-decimal-digits=2, group-separator = {.}, output-decimal-marker = {,}]{#1}\,€
}
% =====================================
% automatic item numbering
\newcommand{\startnumberedlist}{\newcounter{numberedlistcounter}}
\newcommand{\numberedlistitem}{\stepcounter{numberedlistcounter}\thenumberedlistcounter}
% =====================================
% calculation
\RequirePackage{calculator}
\newcommand{\resetinvoicesum}{\ADD{0}{0}{\invoicesum}}
\newcommand{\addtoinvoicesum}[1]{\ADD{\invoicesum}{#1}{\invoicesum}\GLOBALCOPY{\invoicesum}{\invoicesum}}
% =====================================
% invoice environment
\RequirePackage{booktabs}
\newenvironment{invoice}[1][]{\startnumberedlist\resetinvoicesum\par\noindent
\centering\begin{NiceTabular}{rX[l]S[table-format=5.1]S[table-format=5.4]r}%
\toprule[0.7pt]\textbf{Pos.} & \textbf{Beschreibung} & \textbf{Anzahl} & \textbf{Einzelpreis} & \textbf{Gesamtpreis} \\ \toprule[0.7pt]}
{\midrule[0.7pt]
&&& \textbf{Rechnungsbetrag} & \textbf{\EUR{\invoicesum}}\\ \cmidrule[0.7pt]{4-5} \end{NiceTabular}%
}
% invoiceitem, #1: description, #2: count, #3: price per item
\newcommand{\invoiceitem}[3]{
\numberedlistitem & #1 & #2 & \EURsimple{#3} & \MULTIPLY{#2}{#3}{\tempsum} \ROUND[2]{\tempsum}{\tempsum} \addtoinvoicesum{\tempsum} \EUR{\tempsum}\\} % price calculation and sum up all prices
\usepackage{Blindtext}
\begin{document}
\begin{letter}{recipient}
\opening{Hello}
\Blindtext[1]
\begin{invoice}
\invoiceitem{Arbeitszeit in h}{800}{15}
\invoiceitem{Schrauben}{2134}{0.1}
\invoiceitem{Strommenge in kWh and some other long text}{303.5}{0.3175}
\invoiceitem{Position C}{2}{1123.1}
\end{invoice}
\end{letter}
\end{document}
您需要几个编译(几个工具,例如latexmk
将为您完成这些编译)。