If you're new to Python
A VPython tutorial
Pictures of 3D objects
What's new in VPython 6
wxPython is a Python library that makes it possible to create windows and handle events cross-platform, with native look-and-feel on Windows, Mac, and Linux (see wxpython.org). The VPython example program widgets.py uses VPython to handle 3D graphics, and wxPython statements to create buttons, sliders, etc. In the image above, produced by widgets.py, the widgets are buttons, radio buttons (two of them, in a "radio box"), a text control into which the user can type, and a slider. There is also a regular pull-down menu, and the user is about to choose "Make cyan". (At the time of writing, pull-down menus do not yet work on the Macintosh.)
Among the documentation mentioned at wxpython.org, a particularly useful reference manual is docs.wxwidgets.org/2.8/wx_contents.html. (VPython uses wxPython 2.9, but the 2.8 documentation is similar, and at the time of writing the 2.9 documentation is labeled at wxwidgets.org/docs as being in "testing" mode.)
At docs.wxwidgets.org/2.8/wx_contents.html, the section "Classes by category" gives a useful overview of the components of wxPython, and the category "Controls" describes all the things you can do with buttons, sliders, etc. One needs to know that when you see "wxButton" that actually means wx.Button, after executing import wx. Also, it is helpful to know that wxPython is based on wxWidgets, a library for C++ programs, and the documentation for wxPython and wxWidgets is very similar. Because of the connection to C++, some of the documentation may look strange to those familar with Python. For example, suppose you have made a button named B of the wx.Button class. To change the label on the button to "Start" you say B.SetLabel("Start"). In the documentation for wx.Button you'll find wxButton::SetLabel and void SetLabel(const wxString& label). The translation of these C++ statements to Python is that there is a class wx.Button which has a method SetLabel which takes a character string as an argument; that is, B.SetLabel("Start") if B is a wx.Button object.
For simplicity, widgets.py places the various widgets at specific positions within the window. However, wxPython also offers the option to allow it to rearrange the positioning of widgets as a function of window size and shape. A good tutorial on wxPython, which includes a discussion of "Layout Management", is found at zetcode.com/wxpython.
As you can see in widgets.py, to add widgets to a window you first create a window, whose defaults are shown here, followed by a standard display statement, except that the x and y specifications are relative to the display region of the window, and you have to specify in what window the 3D display will appear:
w = window(menus=False, title="VPython",
The position and size of the display is relative to the display region of the window, with (0,0) at the upper left of the region. The embedded 3D display behaves exactly as any other VPython display, such as the default display "scene". As usual, if you move the mouse into the 3D display portion of the window, you can rotate and zoom the camera.
To facilitate adding wxPython widgets to the window, the window and display objects provide references to the display region of the window. If as above the window is named w, the display region is referred to as w.panel. Also, w.win is the wxPython "frame" that constitutes the window, and w.menubar is the wxPython menubar to which you can add pull-down menus. For convenience you can also reference these objects from a display named d: d.win, d.panel, and d.menubar.
At times you may need to know how large is the display region inside a window: window.dwidth and window.dheight (not w.dwidth or w.dheight) are the extra width and height of windows compared to the display region.
If there is a menu bar, the extra height is window.dheight+window.menuheight. See widgets.py for examples of the use of these references.
Menus: If you do not specify menus=True for either the window or display object, no menu bar is created, and w.menubar and d.menubar will be None. Menus do not yet work on the Macintosh.
Be prepared for possible future developments
A VPython program that uses these wxPython capabilities should always end with an infinite loop containing a rate statement, as future developments may require this to keep a display active. Here is a simple example:
Older controls mechanism
In VPython 5 there was a way to make controls that had much less capability and the controls were rather unattractive. You are encouraged to use the scheme described above. The following information is provided because you may encounter a program that uses the old scheme, which will still function.
You can create buttons, sliders, toggle switches, and pull-down menus to control your program. You import these capabilities with these statements:
from visual import * # must first import visual or vis
Importing from visual.controls makes available all VPython objects plus the controls module. To use the control features, you create a special controls window and add control objects to that window, specifying what actions should take place when the controls are manipulated. For example, an action associated with a button might be the execution of a function to change the color of a VPython object. For a detailed example, see the VPython demo program controlstest.py.
Here is a small example. All it does is change the button text when you click the button. The Python construction "lambda:" is required for the controls module to have the correct context ("namespace") for calling the specified routine.
from visual import * # must first import visual or vis
Technical note: It used to be necessary to call c.interact() repeatedly in order for the controls to be active, but this is no longer necessary. The interact function still exists for backward compatibility, but it does nothing.
controls() Creates a controls window with the specified attributes, and returns it. For example, the following creates a controls window 300 by 300, located at (0,400) with respect to the upper left corner of the screen, with 'Controlling the Scene' in the title bar, and a range of 50 (window coordinates from -50 to +50 in x and y):
c = controls(title='Controlling the Scene',
Controls window parameters
x, y Position of the window on the screen (pixels from upper left)
width, height Width and height of the display area in pixels.
title Text in the control window's title bar.
range The extent of the region of interest away from the center along each axis. The default is 100. The center of a controls window is always (0,0).
display Every controls window has the attribute display; sphere(display=c.display) will place a sphere in the controls window named c.
After creating a controls window, you can create the following control objects that will appear in that window:
button A button to click.
slider Drag a slider to enter a numeric value graphically.
toggle Click on the handle to flip a toggle switch.
menu A pull-down menu of options.
Control objects have the following attributes:
pos Position of the control (center of button or toggle, one end of slider, upper left corner of menu title)
color Gray by default
width Width of button, toggle, or menu
height Height of button, toggle, or menu
axis Axis for slider, pointing from pos to other end (as for cylinder or arrow)
length Length of slider (in direction of axis)
min, max Minimum and maximum values for a slider
value Value of toggle (0 or 1), slider (depends on slider min and max), or menu (the text just selected on the menu). The value of a toggle or slider (but not a menu) can be set as well as read. If you set the value of a toggle or slider, the control moves to the position that corresponds to that value.
text Text to display on a button, or the header at the top of a menu
text0 Text to display below a toggle switch (associated with toggle value = 0)
text1 Text to display above a toggle switch (associated with toggle value = 1)
action Specify Python statement to be executed when a control is manipulated
items For menus only, list of menu items to choose from. Here is how to add a menu item to a menu named m1:
m1.items.append( ('Red', lambda: cubecolor(color.red)) )
This adds to the pull-down menu an item 'Red' which when chosen will pass the value color.red to the subroutine cubecolor(). The Python construction "lambda:" is required for the controls module to have the correct context ("namespace") for calling the specified routine.