# How do I define tikz styles with a xkeyval command?

I would like to write a command which allows the user to change tikz styles. My code goes like this:

\documentclass{article}
\usepackage{tikz,xkeyval}

\makeatletter
\def\DEFstyle{}
\define@key{styles}{styleA}{\def\DEFstyle{#1}}
\newcommand{\setstyles}[1]{%
\setkeys{styles}{styleA={}}
\setkeys{styles}{#1}
\tikzstyle{TIKZSTYLE}=[\DEFstyle]
}
\makeatother

\begin{document}
\setstyles{styleA={top color=green,bottom color=red}}
\end{document}


However, I always get an error message:

! Package pgfkeys Error: I do not know the key '/tikz/top color=green,bottom color=red' and I am going to ignore it. Perhaps you misspelled it.

But the content of \DEFstyle is definitely top color=green,bottom color=red and when I directly write \tikzstyle{TIKZSTYLE}=[top color=green,bottom color=red] then everything works fine. Where does the bug hide?

-
– Claudio Fiandrino Mar 5 '13 at 18:28
The exact option is not important as long as it works. \tikzset{TIKZSTYLE/.style/.expand once=\DEFstyle} seems to work! Thanks a lot! May you consider to explain your solution? Otherwise I can answer this question myself. Also: thanks for the link. – Andreas Milford Mar 5 '13 at 18:42
I cant answer my own question yet due to stackexchange spam limits. – Andreas Milford Mar 5 '13 at 19:04

First of all,

\tikzstyle{<key>}=[<value>]


is the same as

\tikzset{<key>/.style={<value>}}


From this point I will only use the \tikzset syntax (→ Should \tikzset or \tikzstyle be used to define TikZ styles?). But you would've had the same problem with \tikzset.

The assignment is not a problem, the style TIKZStyle contains simply your argment to styleA. But when TikZ executes this style (say when \draw[TIKZSTYLE]) it sees firstly \DEFstyle and its definition and tries it as a key, but a key named top color=green,bottom color=red (for TikZ this is just one “string” at this moment) does not exist.

Even top color=green won’t work because, again, TikZ does not see the = hidden in \DEFstyle.
The only thing that would work is is a style without a parameter, say

\setstyles{styleA={rounded corners}}%
\tikz \draw[TIKZSTYLE] (0,0) rectangle (1em,2ex);


which results in . But even that is not safe enough:

\setstyles{styleA={rounded corners}}%
\def\DEFstyle{fill}%
\tikz \draw[TIKZSTYLE] (0,0) rectangle (1em,2ex);


(But then again, throw some @ in the \DEFstyle macro’s name …).

These are the reasons we need to expand \DEFstyle before assigning it to the TIKZSTYLE style:

\tikzset{TIKZSTYLE/.style/.expand once=\DEFstyle}%


In your definition of the \setstyles macro are some spurious spaces:

I do not know much about your project, but as a reminder, you can do this all with PGF keys. See the second Code block.

## Code

\documentclass[tikz]{standalone}
\usepackage{xkeyval}

\makeatletter
\def\DEFstyle{}
\define@key{styles}{styleA}{\def\DEFstyle{#1}}
\newcommand{\setstyles}[1]{%
\setkeys{styles}{styleA={}}%
\setkeys{styles}{#1}%
\tikzset{TIKZSTYLE/.style/.expand once=\DEFstyle}%
}
\makeatother

\begin{document}
\setstyles{styleA={top color=green,bottom color=red}}
\tikz \draw[TIKZSTYLE] (0,0) rectangle (1em,2ex);
\end{document}


## Code (sans-xkeyval)

\documentclass[tikz]{standalone}

\pgfkeys{
/no xkeyval/styleA/.style={
/tikz/TIKZSTYLE/.style={#1}
}
}
\newcommand*{\setstyles}[1]{%
\pgfqkeys{/no xkeyval}{#1}%
}
\begin{document}%
\setstyles{styleA={top color=green,bottom color=red}}%
\tikz \draw[TIKZSTYLE] (0,0) rectangle (1em,2ex);
\end{document}

-

One use of xkeyval package might be to preset some keys, so that their preset values can be used when no user value is provided for them.

\documentclass{article}
\usepackage{tikz,xkeyval}

\makeatletter
\define@key{styles}{color set}{\def\rectstyle{#1}}
\define@key{styles}{rect size}{\def\rectsize{#1}}
\presetkeys{styles}{color set={top color=white,bottom color=gray},rect size={5em,5em}}{}
\newcommand*{\setstyles}[1][]{%
\setkeys{styles}{#1}%
\edef\tempa{\unexpanded{\tikz\draw}[\rectstyle](0,0)rectangle(\rectsize)}\tempa;
}
\makeatother

\begin{document}
\begin{tikzpicture}
\setstyles
\hspace{1cm}
\setstyles[color set={top color=green,bottom color=red},rect size={5ex,6ex}]
\hspace{1cm}
\setstyles[rect size={10ex,8ex}]
\end{tikzpicture}
\end{document}


-