PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Maximalwert für Länge bestimmen -- zurückgegebener Wert ist keine Länge?



pi-c
15-10-2015, 10:46
Hallo!

Ich bin gerade dabei, mir eine lco-Datei für scrlttr2 zu basteln. Im Fuß möchte ich mehrere Blöcke (Adresse, Bankverbindung, Telefonnummer/E-Mail/URL) haben, die jeweils aus drei Zeilen bestehen. Die einzelnen Blöcke wollte ich in eine parbox oder auch eine einspaltige Tabelle packen; um deren Breite zu bestimmen, benötige ich die Länge der längsten Zeile im jeweiligen Block.

Dazu habe ich ein einfaches Makro erstellt, das die einzelnen Zeilen ausmisst und den größten Wert zurückgibt. Im Prinzip funktioniert das auch -- wenn ich das Makro im Textteil aufrufe, wird die Länge der längsten Zeile ausgegeben. Versuche ich allerdings, einer Länge den vom Makro zurückgegebenen Wert zuzuweisen, bricht LaTeX mit folgender Fehlermeldung ab:


! Missing number, treated as zero.
<to be read again>
\let
l.52 ...ength{\test}{\maxwidth{asdf}{ASDF}{asdfg}}

?

Anscheinend wird des Makros Rückgabewert also als Text interpretiert, nicht als Längenangabe. Was mache ich falsch?

Hier noch das Minimalbeispiel:



\documentclass[version=last,visualize]{scrlttr2}

\usepackage{filecontents}

\begin{filecontents}{minimal.lco}
\ProvidesFile{minimal.lco}
\LetterOptionNeedsPapersize{paper=a4}{a4}

\RequirePackage[utf8]{inputenc}
\RequirePackage[T1]{fontenc}
\RequirePackage{calc}
\RequirePackage{printlen}
\RequirePackage{xifthen}

\@newplength{maxwidth}
\@newplength{testwidth1}
\@newplength{testwidth2}
\newcommand{\maxwidth}[3]{%
\@setplength{maxwidth}{\widthof{#1}}
\@setplength{testwidth1}{\widthof{#2}}
\@setplength{testwidth2}{\widthof{#3}}

\ifthenelse{%
\lengthtest{\useplength{testwidth1} > \useplength{maxwidth}}
}
{\@setplength{maxwidth}{\useplength{testwidth1}}}
{}

\ifthenelse{%
\lengthtest{\useplength{testwidth2} > \useplength{maxwidth}}
}
{\@setplength{maxwidth}{\useplength{testwidth2}}}
{}%

\printlength{\useplength{maxwidth}}
}
\end{filecontents}

\LoadLetterOption{minimal}

\setlength{\parindent}{0cm}


\begin{document}

\begin{letter}{~}
\opening{}

Länge der längsten Zeile: \maxwidth{asdf}{ASDF}{asdfg}\\[1cm]

\newlength{\test}
\setlength{\test}{\maxwidth{asdf}{ASDF}{asdfg}}

\fbox{\parbox{\test}{asdf\\ASDF\\asdfg}}

\closing{}
\end{letter}
\end{document}


Beste Grüße!

Andreas

klops
15-10-2015, 11:41
\printlength ist keine Länge, sondern die Ausgabe einer Länge. Wäre es wenigstens eine reine Ziffernfolge gefolgt von einer Maßeinheit, würde es sogar trotzdem funktionieren. Aber \printlength ist nicht vollständig expandierbar und liefert deshalb nichts, was als Länge verwendebar wäre. Ein besserer Name für Deine Anweisung wäre also \printmaxwidth. Ganz ähnlich könntest Du Dir natürlich ein \settomaxwidth definieren, bei dem \printlength durch \setlength{…} ersetzt wird. Allerdings wäre es dann sinnvoller, statt mit Pseudolängen direkt idealer Weise als Parameter übergebene Länge für das Ausmessen zu verwenden, also etwas in der Art
\newcommand*{\settomaxwidth}[4]{%
\ifthenelse{\withof{#2}>\widthof{#3}}{%
\ifthenelse{\widtof{#2}>\widthof{#4}}{\settowidth{#1}{#2}}{\settowidth{#1} {#4}}%
}{%
\ifthenelse{\widthof{#3}>\widthof{#4}}{\settowidth{#1}{#3}}{\settowidth{#1} {#4}}%
}%
}
...
\settomaxwidth{\test}{abcd}{efgH}{IJKLMO}

Aber: Für eine einspaltige Tabelle musst Du die Länge gar nicht wissen. Da sollte ein
\begin{tabular}{@{}l@{}}
abcd\\
efgH\\
JKLMO\\
\end{tabular} vollkommen genügen. Davon abgesehen gibt es auch noch das Paket varwidth (http://ctan.org/pkg/varwidth), das eine Art minipage-Umgebung zur Verfügung stellt, die sich selbst an die benötigte Breite anpasst.

pi-c
16-10-2015, 15:49
Schönen Dank erstmal, das waren doch recht hilfreiche Anregungen!


\printlength ist keine Länge, sondern die Ausgabe einer Länge. Wäre es wenigstens eine reine Ziffernfolge gefolgt von einer Maßeinheit, würde es sogar trotzdem funktionieren.Genau das hatte ich mir auch gedacht -- und im Beispiel (ohne die fehlerhafte Zeile) erhielt ich ja tatsächlich als Ausgabe "31.96996pt"!


Aber \printlength ist nicht vollständig expandierbar und liefert deshalb nichts, was als Länge verwendebar wäre.
\printlength hatte ich eigentlich eh nur verwendet, weil ich nicht wusste, wie ich das Ergebnis aus dem Makro zurückgeben sollte. Zuerst hatte ich es mit \useplength versucht, war aber eigentlich nicht wirklich überrascht, dass das nicht funktioniert. :-)


Ein besserer Name für Deine Anweisung wäre also \printmaxwidth. Ganz ähnlich könntest Du Dir natürlich ein \settomaxwidth definieren, bei dem \printlength durch \setlength{…} ersetzt wird.Das ist natürlich viel eleganter! Ich hatte überhaupt nicht daran gedacht, dass man die Längen auch direkt setzen kann, und war voll auf etwas wie eine Funktion mit Rückgabewert fixiert. :-)


Allerdings wäre es dann sinnvoller, statt mit Pseudolängen direkt idealer Weise als Parameter übergebene Länge für das Ausmessen zu verwendenIch arbeite zwar schon einige Jahre mit LaTeX, das Projekt "Neuer Briefbogen" ist aber meine erste wirkliche Begegnung mit KOMA-Script. Deshalb würde mich jetzt doch einmal interessieren, ob es denn überhaupt sinnvoll ist, eigene Pseudolängen und komavars zu verwenden, oder ob die herkömmliche Methode (\newlength, \newcommand) nicht doch ausreicht. Laut scrguide ist ja mittlerweile der Grund für die Einführung der Pseudolängen -- die beschränkte Registerzahl unter TeX -- durch Verwendung von eTeX nicht mehr gegeben. Umständlich zu handhaben sind die Pseudolängen ja schon, weil man sie immer erst in reale Längen konvertieren muss, wenn man mit ihnen arbeiten will.


Aber: Für eine einspaltige Tabelle musst Du die Länge gar nicht wissen.
Stimmt. Meistens hatte ich aber doch längere Texte in den Tabellen, so dass ich auch dort parbox-ähnliche Spalten (also solche, in denen Zeilenumbrüche erlaubt sind) verwendet hatte -- und *dafür* ist dann wieder die Breite wichtig.


Davon abgesehen gibt es auch noch das Paket varwidth (http://ctan.org/pkg/varwidth), das eine Art minipage-Umgebung zur Verfügung stellt, die sich selbst an die benötigte Breite anpasst.
Das kannte ich noch gar nicht! Damit wird die Datei gleich um einiges kürzer. Allerdings gibt es da noch ein kleines Positionierungsproblem:

Ich will ja mehrere dieser Blöcke nebeneinander setzen, so dass sie oben bündig sind. Nun verwende ich als Schrift mathpazo, mit "oldstyle figures", also Ziffern mit Unterlänge. Die Blöcke für Adresse und Bankverbindung haben in der letzten Zeile Ziffern, der Block mit den Kontaktmöglichkeiten (Telefon/Mail/URL) nicht. Aufgrund der Unterlängen in der letzten Zeile haben die ersten beiden Blöcke eine etwas größere Höhe als der dritte. Dummerweise wird dieser Block nun zentriert -- er sitzt also tiefer und die Zeilen hier sind nicht mehr bündig mit den Zeilen in den anderen Blöcken. Natürlich könnte ich die Telefonnummer (die ja ebenfalls Ziffern enthält) in die unterste Zeile setzen, aber für mein Empfinden gehört sie ganz nach oben. Einer normalen parbox oder minipage kann man ja einen Positionsparameter mitgeben -- mit "\parbox[t]" würden dann alle Boxen nach oben ausgerichtet sein. Anscheinend ist das aber mit varwidth nicht möglich, oder habe ich da etwas übersehen?

Beste Grüße

Andreas

klops
17-10-2015, 07:59
\documentclass{article}
\usepackage{varwidth}
\begin{document}
\begin{varwidth}[t]{.4\linewidth}
Hast Du\\
irgendwie
\end{varwidth}
\begin{varwidth}[t]{.4\linewidth}
Nicht\\
so\\
ganz\\
\"uberblickt.
\end{varwidth}
\end{document}
Unterschiedlich hohe oder tiefe Zeilen kann man übrigens mit einem \strut angleichen:
\documentclass{article}
\usepackage{varwidth}
\begin{document}
\begin{varwidth}{.4\linewidth}
\strut Das
\end{varwidth}
\begin{varwidth}{.4\linewidth}
geht.\strut
\end{varwidth}
\end{document}

pi-c
17-10-2015, 10:55
\documentclass{article}
\usepackage{varwidth}
\begin{document}
\begin{varwidth}[t]{.4\linewidth}
Hast Du\\
irgendwie
\end{varwidth}
\begin{varwidth}[t]{.4\linewidth}
Nicht\\
so\\
ganz\\
\"uberblickt.
\end{varwidth}
\end{document}
Stimmt -- da habe ich wohl das "(based on minipage)" in der Dokumentation überlesen! In dem Beispiel dort wird der optionale Parameter nicht verwendet, deshalb dachte ich, es gäbe ihn gar nicht. :-)


Unterschiedlich hohe oder tiefe Zeilen kann man übrigens mit einem \strut angleichen:
Für dieses Problem habe ich hier eine ganz andere Lösung gefunden: Mein verlässlicher Berater in Sachen Typographie hat mich davon überzeugt, dass die "hüpfenden Zahlen" zwar im normalen Text dem Lesefluss förderlich, für den Fußbereich aber nicht geeignet sind. Dort, so meinte er, gehe es um nüchterne Fakten, und die "hüpfenden Zahlen" wären da eher verwirrend, wenn man etwa die Telefonnummer oder gar die lange IBAN abschreiben wolle. Im Fußbereich wechsele ich deshalb jetzt zur Ausgabe von Ziffern in den mathematischen Modus ($123$) -- keine Unterlängen mehr, also auch keine verschieden große Boxen!

Besten Dank für Deine Hilfe, und ein schönes Wochenende noch!

Andreas