1.. currentmodule:: dialog
2
3A gentle introduction
4=====================
5
6A minimal program using pythondialog starts with the creation of a
7:class:`Dialog` instance::
8
9  from dialog import Dialog
10
11  d = Dialog(dialog="cdialog")
12
13The *dialog* parameter indicates the executable to use to invoke the backend
14(which must be compatible with dialog_). For instance, one might use something
15like ``dialog="/home/dave/src/dialog-1.2-20140219/dialog"``. The default value
16is ``"dialog"``, and since it does not contain any slash (``/``), it is looked
17up according to the :envvar:`PATH` environment variable. See
18:meth:`Dialog.__init__` for a description of all parameters that can be passed
19to the :class:`Dialog` constructor.
20
21.. _dialog: https://invisible-island.net/dialog/dialog.html
22
23
24Offering a choice between several options using :meth:`!menu`
25-------------------------------------------------------------
26
27Once you have a :class:`Dialog` instance, you can call any widget-producing
28method, as documented in :ref:`widgets`. For instance, if you want to display
29a menu offering three choices::
30
31  code, tag = d.menu("Some text that will be displayed above the menu entries",
32                     choices=[("Tag 1", "Item text 1"),
33                              ("Tag 2", "Item text 2"),
34                              ("Tag 3", "Item text 3")])
35
36When the method returns:
37
38  - *code* will be equal to ``d.OK`` if there was no error and the user chose
39    an entry (instead of pressing :kbd:`Esc`). See :ref:`Dialog-exit-code` for
40    more details on how to interpret the value of *code*.
41  - *tag* will contain the name of the tag corresponding to the selected
42    entry: ``"Tag 1"``, ``"Tag 2"`` or ``"Tag 3"`` (assuming that ``code ==
43    d.OK``).
44
45While we kept this :meth:`~Dialog.menu` example as simple as possible, it
46would be very easy to add a title line at the top of the widget window. For
47this, all you need to do is to add a :samp:`title={...}` keyword argument to
48the :meth:`~!Dialog.menu` method call. It is also possible to display a
49background title using :samp:`backtitle={...}`, and in case you want the same
50background title for all widgets, :meth:`Dialog.set_background_title` is your
51friend.
52
53.. figure:: ../screenshots/intro/example-menu.png
54   :align: center
55
56   A simple example using :meth:`Dialog.menu`
57
58
59Displaying a message with :meth:`~!Dialog.msgbox`
60-------------------------------------------------
61
62We can expand on the previous example by displaying an :meth:`~Dialog.msgbox`
63indicating what the user has done to exit from the :meth:`~Dialog.menu`.
64First, we can define a mapping from the :term:`Dialog exit codes <Dialog exit
65code>` for the standard buttons to the corresponding button labels::
66
67  button_names = {d.OK:     "OK",
68                  d.CANCEL: "Cancel",
69                  d.HELP:   "Help",
70                  d.EXTRA:  "Extra"}
71
72Of course, in the previous :meth:`~Dialog.menu` widget call, the only codes
73that can be returned are ``d.OK`` and ``d.CANCEL``, respectively corresponding
74to the :guilabel:`OK` and :guilabel:`Cancel` buttons. Thus, we could do with
75only two key-value pairs in ``button_names`` for this particular example,
76however it seems cleaner and not outrageously expensive to declare the codes
77for the four standard buttons like this.
78
79In addition to these :term:`Dialog exit codes <Dialog exit code>`, the
80:meth:`~Dialog.menu` widget call can return ``d.ESC``, indicating that the
81user pressed the :kbd:`Esc` key. Therefore, we are going to check for this one
82too. Here it goes::
83
84  if code == d.ESC:
85      d.msgbox("You got out of the menu by pressing the Escape key.")
86  else:
87      text = "You got out of the menu by choosing the {} button".format(
88          button_names[code])
89
90      if code != d.CANCEL:
91          text += ", and the highlighted entry at that time had tag {!r}".format(
92          tag)
93
94      d.msgbox(text + ".", width=40, height=10)
95
96(users of Python < 3.1 should replace ``{}`` with ``{0}`` and ``{!r}`` with
97``{0!r}``)
98
99The above code for dealing with the :kbd:`Esc` key is pretty straightforward.
100It relies on the default values to determine the width and height of the
101:meth:`~Dialog.msgbox`, which are acceptable in this case. On the other hand,
102the default width for :meth:`~!Dialog.msgbox` seemed too small for the message
103displayed in the *else* clause, causing very irregular line lengths. In order
104to compensate for this problem, we have explicitely specified the width and
105height of the :meth:`~!Dialog.msgbox` using keyword arguments
106(``width=40, height=10``).
107
108.. figure:: ../screenshots/intro/example-msgbox.png
109   :align: center
110
111   A message displayed with :meth:`Dialog.msgbox`
112
113
114Displaying a transient message with :meth:`~!Dialog.infobox`
115------------------------------------------------------------
116
117We can finish this little example with a widget call that displays a message
118and immediately returns to the caller without waiting for the user to react.
119Typically, the :meth:`~Dialog.infobox` is used to display some information
120while  a time-consuming operation is being performed. In this case, since we
121don't have anything particularly useful to do but still want the user to be
122able to read the message, we are going to wait using :func:`time.sleep`::
123
124  d.infobox("Bye bye...", width=0, height=0, title="This is the end")
125  time.sleep(2)
126
127We also addressed the problem of determining the widget size in a different
128way as exposed earlier. By using ``width=0, height=0``, we ask
129:program:`dialog` to automatically determine suitable width and height
130parameters for the dialog box. If you like this method and would like to have
131it used by default for all widgets without having to specify ``width=0,
132height=0`` every time, you can enable the :ref:`autowidgetsize feature
133<autowidgetsize>`.
134
135For the sake of the example, we've also specified a window title for the
136:meth:`~Dialog.infobox` using a :samp:`title={...}` keyword argument. This can
137be done with most widgets, and is entirely optional.
138
139.. figure:: ../screenshots/intro/example-infobox.png
140   :align: center
141
142   A transient message displayed with :meth:`Dialog.infobox`
143
144Of course, the :func:`time.sleep` call requires an::
145
146  import time
147
148statement that you, careful reader, had already added. In order to exit
149cleanly from our program, I also suggest to end with::
150
151  sys.exit(0)
152
153which requires an::
154
155  import sys
156
157at the top of your script. And finally, since you don't want to take bad
158habits, I would also suggest starting your program with::
159
160  locale.setlocale(locale.LC_ALL, '')
161
162which in turn requires an::
163
164  import locale
165
166at the top.
167
168
169Putting it all together
170-----------------------
171
172If we put all the pieces from this chapter together and reorder a tiny bit to
173improve readability, we obtain the code for our example program::
174
175  import sys
176  import locale
177  import time
178
179  from dialog import Dialog
180
181  # This is almost always a good thing to do at the beginning of your programs.
182  locale.setlocale(locale.LC_ALL, '')
183
184  d = Dialog(dialog="cdialog")
185
186  button_names = {d.OK:     "OK",
187                  d.CANCEL: "Cancel",
188                  d.HELP:   "Help",
189                  d.EXTRA:  "Extra"}
190
191  code, tag = d.menu("Some text that will be displayed above the menu entries",
192                     choices=[("Tag 1", "Item text 1"),
193                              ("Tag 2", "Item text 2"),
194                              ("Tag 3", "Item text 3")])
195
196  if code == d.ESC:
197      d.msgbox("You got out of the menu by pressing the Escape key.")
198  else:
199      text = "You got out of the menu by choosing the {} button".format(
200          button_names[code])
201
202      if code != d.CANCEL:
203          text += ", and the highlighted entry at that time had tag {!r}".format(
204          tag)
205
206      d.msgbox(text + ".", width=40, height=10)
207
208  d.infobox("Bye bye...", width=0, height=0, title="This is the end")
209  time.sleep(2)
210
211  sys.exit(0)
212
213
214Other examples
215--------------
216
217For an example that is slightly different from the one exposed in this
218chapter, you can look at the :file:`simple_example.py` file that comes with
219pythondialog, in the :file:`examples` directory. It is a very simple and
220straightforward example using a few basic widgets. The `pythondialog website
221<http://pythondialog.sourceforge.net/>`_ also has a very simple example that
222can be used to get started.
223
224Once you are comfortable with the basics, you can study the :file:`demo.py`
225file that illustrates most features of pythondialog (also from the
226:file:`examples` directory), or more directly :file:`dialog.py`.
227