0

I just learn \pgfkeys, but don't quite understand how to use it for making a macro with key=value options.

I'd like to give the following simple example as a practice to show my idea.

\documentclass{article}
\usepackage{tikz}

\newcommand{\mycolorbox}[1][]{
  \pgfkeys{
  color/.initial=red,
  text/.initial=some text,
  #1,
  exe/.code=\colorbox{color}{text}
}
}
\begin{document}
\mycolorbox[color=blue, text=This is a practice.]
\end{document}

This does not work. Anyone can help me with this?

1
  • take a look here
    – JeT
    Jun 8 at 8:32
2

You want to define your own namespace for keys and separate key definition from usage.

\documentclass{article}
\usepackage{tikz}

\pgfkeys{/lyl/mycolorbox/.cd, % define your own space
  color/.store in=\mycolorboxcolor,
  text/.store in=\mycolorboxtext,
  color=red!40,
  text=some text,
}

\newcommand{\mycolorbox}[1][]{%
  \begingroup
  \pgfkeys{/lyl/mycolorbox/.cd,#1}%
  \colorbox{\mycolorboxcolor}{\mycolorboxtext}%
  \endgroup
}

\begin{document}

\mycolorbox[color=blue!20]

\mycolorbox[text=This is a practice.]

\mycolorbox[color=blue!20, text=This is a practice.]

\end{document}

The expl3 version:

\documentclass{article}
\usepackage{xcolor}

\ExplSyntaxOn

\keys_define:nn { lyl/mycolorbox }
 {
  color .tl_set:N  = \l__lyl_mycolorbox_color_tl,
  text  .tl_set:N  = \l__lyl_mycolorbox_text_tl,
  color .initial:n = red!40,
  text  .initial:n = some~text,
 }

\NewDocumentCommand{\mycolorbox}{O{}}
 {
  \group_begin:
  \keys_set:nn { lyl/mycolorbox } { #1 }
  \colorbox{\l__lyl_mycolorbox_color_tl}{\l__lyl_mycolorbox_text_tl}
  \group_end:
 }

\ExplSyntaxOff

\begin{document}

\mycolorbox[color=blue!20]

\mycolorbox[text=This is a practice.]

\mycolorbox[color=blue!20, text=This is a practice.]

\end{document}

enter image description here

7
  • Does that mean if I have 20 keys, then I have to use 20 macros to store them? in an article, maybe many commands needs key=value. So many marco names are too heavy to namespace? Do I understand it right?
    – lyl
    Jun 8 at 12:57
  • @lyl There is plenty of memory space for macros, don't worry.
    – egreg
    Jun 8 at 13:07
  • I tried this: \def\mycolorboxtext{aaa}\mycolorbox[color=blue!20], and aaa was typeset. Does that mean the namespace is polluted? It seems that \begingroup...\endgroup does not work?
    – lyl
    Jun 8 at 13:07
  • @lyl I added an expl3 version that I'd prefer. Anyway, don't do \def\mycolorboxtext.
    – egreg
    Jun 8 at 13:12
  • If you have lots of keys, I'd go for a programmatic set up of all of them
    – Joseph Wright
    Jun 8 at 13:12
3

Another way to store values is inside the key paths themselves (that doesn't mean you don't use as many commands, so this doesn't ease the namespace-heaviness).

\documentclass[]{article}

\usepackage{xcolor}
\usepackage{pgfkeys}

\pgfkeys
  {%
     /mycolorbox/.is family
    ,/mycolorbox
    ,color/.initial=blue
    ,text/.initial=some text
  }
\newcommand\mycolorbox[1][]
  {%
    \begingroup
      \pgfqkeys{/mycolorbox}{#1}%
      \colorbox
        {\pgfkeysvalueof{/mycolorbox/color}}
        {\pgfkeysvalueof{/mycolorbox/text}}%
    \endgroup
  }

\begin{document}
\mycolorbox

\mycolorbox[color=red]

\mycolorbox[text=foobar]
\end{document}

(note: \pgfqkeys{/<path>}{<keys>} is the same as \pgfkeys{/<path>/.cd,<keys>} but faster)

enter image description here

4
  • Thank you for this solution. And how does \begingroup...\endgroup here work?
    – lyl
    Jun 8 at 13:17
  • \begingroup...\endgroup just keeps the changes to the options local to this one command, so that the next invocation isn't dependent on the previous one. The two commands (\begingroup and \endgroup) are TeX primitives.
    – Skillmon
    Jun 8 at 13:23
  • Oh,I see. It's the cost of non-macro to store value of keys. Many thanks!
    – lyl
    Jun 8 at 13:44
  • @lyl no, you'd do the same if you used macros to store the values. All that \pgfkeys{/foo/bar/.initial={<value>}} does is store the value inside a macro with a long name that is \pgfk@/foo/bar (slashes are part of the macro name).
    – Skillmon
    Jun 8 at 17:09
2

If you're just setting up a simple macro with a few keys (and that's the only interface accessing and using those keys), you could as well build your macro with expkv-cs:

\documentclass[]{article}

\usepackage{xcolor}
\usepackage{expkv-cs}

\ekvcSplit\mycolorbox
  {
     color=blue
    ,text=some text
  }
  {\colorbox{#1}{#2}}%

\begin{document}
\mycolorbox{}

\mycolorbox{color=red}

\mycolorbox{text=foobar}
\end{document}

(expkv-cs defines the macro \mycolorbox with a mandatory argument, if you want to use an optional one, just add a wrapper like: \newcommand\mycolorbox[1][]{\mycolorboxSplit{#1}} and changing the name of the macro after \ekvcSplit to \mycolorboxSplit).

enter image description here

1
  • Many thanks for these good solution and suggestion!
    – lyl
    Jun 8 at 14:24

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.