1

I have a simple class diagram drawn with pgf-umlcd, but using an underscore within the class name leads to an error message.

\begin{tikzpicture}
  \begin{class}{foo\_bar}{0,0}
    % some stuff here
  \end{class}
\end{tikzpicture}

The message appears on the \end{class} line:

Missing \endcsname inserted. \end{class}

I also tried \textunderscore from the underscore package (same result) and \verb|_| (which hangs the compilation process).

Is this a bug in pgf-umlcd? Using underscores in attributes and operations works just fine. Is there a workaround or something i am missing?

  • 1
    I can offer you \begin{class}{class\string_name} but it requires \usepackage[T1]{fontenc} – egreg Feb 8 '16 at 16:50
  • 1
    Unfortunately, the package uses the second argument both for node names and for typesetting, which is a big nuisance; I see no other method than the above: _ is illegal in printing, whereas \_ is illegal in node names. – egreg Feb 8 '16 at 17:05
2

The package uses the argument to \begin{class} for two distinct purposes, that is, both for typesetting and for making node names.

When it is used for typesetting, _ is illegal, whereas \_ is illegal in a node name.

The simplest workaround is adding

\usepackage[T1]{fontenc}

and use

\begin{class}{Class\string_Name}

You can also avoid the (quite ugly) underscore you get with T1 encoded fonts with a more complex workaround, which basically is rewriting the package so that it uses two distinct strings for the two purposes; one has the simple underscores, the other one has them replaced by \_.

\documentclass{article}
\usepackage{pgf-umlcd}
\usepackage{xpatch}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\defineclassname}{m}
 {
  \tl_set:Nn \umlcdClassName { #1 }
  \tl_set_eq:NN \umlcdClassNameString \umlcdClassName
  \tl_replace_all:Nfn \umlcdClassName { \char_generate:nn { `_ } { 8 } } { \_\kern1pt }
 }
\cs_generate_variant:Nn \tl_replace_all:Nnn { Nf }
\ExplSyntaxOff
\xpatchcmd{\classAndInterfaceCommon}
 {\def\umlcdClassName}
 {\defineclassname}
 {}{}
\xpatchcmd{\endclass}
 {(\umlcdClassName)}
 {(\umlcdClassNameString)}
 {}{\ddt}
\xpatchcmd{\endinterface}
 {(\umlcdClassName)}
 {(\umlcdClassNameString)}
 {}{\ddt}
\xpatchcmd{\endabstractclass}
 {(\umlcdClassName)}
 {(\umlcdClassNameString)}
 {}{\ddt}
\xpatchcmd{\endobject}
 {(\umlcdClassName)}
 {(\umlcdClassNameString)}
 {}{\ddt}
\xpatchcmd{\endclassAndInterfaceCommon}
 {(\umlcdClassName)}
 {(\umlcdClassNameString)}
 {}{\ddt}
\xpatchcmd{\endclassAndInterfaceCommon}
 {(\umlcdClassName)}
 {(\umlcdClassNameString)}
 {}{\ddt}
\xpatchcmd{\endclassAndInterfaceCommon}
 {(\umlcdClassName)}
 {(\umlcdClassNameString)}
 {}{\ddt}
\begin{document}

\begin{tikzpicture}
\begin{class}[text width=8cm]{Class_Name}{0,0}
\attribute{name : attribute type}
\attribute{name : attribute type = default value}
\operation{name(parameter list) : type of value returned}
% virtual operation
\operation[0]{name(parameters list) : type of value returned}
\end{class}
\end{tikzpicture}

\end{document}

enter image description here

  • thank you. my document is quit short so i will use the simple workaround at first. – user1810087 Feb 8 '16 at 18:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.