Introduction to Jython
First, a list of names is created by enclosing the names inside
brackets. In Python, a list is similar to Java's ArrayList
class, but with more functionality and tighter
integration to the core language. This line shows one example of that
integration--the ability to type new lists directly without calling functions
or explicit constructors. In this example, names
is
set to a list containing three strings. The assignment returns no value--in
Python, an assignment is a statement, not an expression. Python's list type is
an example of the high-level basic types that make programming in Python so
easy to manage.
The actual buttons are created from the list of names using a different Python method for creating a list called a list comprehension.
>>> buttons = [swing.JButton(each) for each in names]
>>>
The line of code can be read almost as it looks in English:
"Perform the statement swing.JButton( )
once for
each element in the list called names
." That code
creates a new JButton
with each string in the list
names
as an argument. When evaluating a list
comprehension, Python holds onto the values for each statement and returns
them as a list. In this case, the variable buttons
now contains a list of three JButton
instances.
Now that we have a list of buttons, we can add them to the
window with the use of a simple for
loop.
>>> for eachButton in buttons:
... eachButton.preferredSize = (100, 20)
... win.contentPane.add(eachButton)
...
javax.swing.JButton[,0,0,0x0,invalid,layout. . .
In the interpreter, ...
is used to
indicate that the next line of code is part of a block--you don't actually
type the dots. However, you must indent the last two lines by the same amount
(at least one character) for Jython to read the block properly. The top line
of this block contains a for
statement. In Python,
for
statements work only for iterating over
sequences. They are roughly the equivalent of a Java Iterator
, however the loop in the Python case is executed
automatically once for each element of the sequence without having to either
explicitly ask the iterator for the next object or cast the object to any
specific type. From the interpreter, a blank line indicates the end of a block
(outside the interpreter, you'd just start the next line back at column
one).
Inside the loop, the code sets the preferred size of each button and adds it to the window's content pane, again using the introspection shortcuts. Once all the buttons are added, we can pack the window again.
>>> win.pack( )
But now, the window is a mess--the buttons are placed on top of each other, and on top of the text field. We've forgotten to give the window a layout manager (which is the mechanism Swing uses to automatically place items within a window). No problem, we can just add it after we import the appropriate package.
>>> import java.awt as awt
>>> win.contentPane.layout = awt.FlowLayout( )
>>> win.pack( )
Adding Behavior
At this point, the window should look right, but it doesn't do anything. We I want it to place some text in the text field depending on what button you push. First, we need to create the text we want used.
>>> quotes = {"Groucho": "Say the secret word", "Chico": "Viaduct?", "Harpo": "HONK!"}
This line sets up a Python dictionary. A
dictionary in Python is more or less equivalent to a Java HashMap
: a collection of key/value pairs designed to be
accessed in constant time no matter which element is accessed or how large the
dictionary is. Again, the Python type is well integrated with the core
language, allowing the creation in one line of what would take a series of
put(key, value)
calls in Java.
Once the text is in place, we can define a function that will perform the actual text replacement.
>>> def buttonPressed(event):
... field.text = quotes[event.source.text]
...
>>>
This pair of lines defines a function to be called when a button
is pressed. The event
parameter in the first line
will be the actual Java Event
object created from
the mouseclick. The line of code inside the function uses Jython shortcuts,
looks up the quotes
dictionary with the text of the
source button, and sets the field with that value. The Java equivalent would
be something like:
field.setText(quotes.get((javax.swing.JTextField) event.getSource( )).getText( )))
We hope that we aren't losing credibility by suggesting that the Python example is a little bit easier to read.
Finally, we associate the function with the buttons.>>> for eachButton in buttons:
... eachButton.actionPerformed = buttonPressed
...
>>>
This for
loop puts the buttonPressed
function in the actionPerformed
slot for each button. This is another
Jython shortcut--as used in Java, buttons don't have an actionPerformed
attribute. Instead, actionPerformed
is the method defined inside an ActionListener
interface. When you assign to actionPerformed
Jython performs the appropriate call to
the button's addActionListener( )
method, such that
the function buttonPressed
is triggered when the
action is performed. Also notice that Jython allows us to use a function as
the righthand side of an assignment statement, we're using the function as a
value. At this point, the window should work, and look more or less like Figure
1-1.
|
Of course, Jython does not have to be run interactively. The
code that we used in the interactive shell session is shown as a standalone
file in Example
1-1. The code is equivalent to the preceding session, but we did clean it
up some, removing duplicate calls to pack( )
,
putting import
and definitions where they would
more typically come in a Python module, adding code to exit Jython when the
window closes, and refactoring button creation into a separate function. Example
1-1 is typical of a Jython script as it would actually be written.
Example 1-1: The sample standalone window
import java.lang as lang
import javax.swing as swing
import java.awt as awt
names = ["Groucho", "Chico", "Harpo"]
quotes = {"Groucho": "Say the secret word",
"Chico": "Viaduct?", "Harpo": "HONK!"}
def buttonPressed(event):
field.text = quotes[event.source.text]
def exit(event):
lang.System.exit(0)
def createButton(name):
return swing.JButton(name, preferredSize=(100,20),
actionPerformed=buttonPressed)
win = swing.JFrame("Welcome to Jython", size=(200, 200),windowClosing=exit)
win.contentPane.layout = awt.FlowLayout( )
field = swing.JTextField(preferredSize=(200,20))
win.contentPane.add(field)
buttons = [createButton(each) for each in names]
for eachButton in buttons:
win.contentPane.add(eachButton)
win.pack( )
win.show( )
Running this script from Jython (for example, by executing jython
filename at an ordinary
command prompt) will give you the same window and behavior as in Figure
1-1.
Page 2 of 4
This article was originally published on March 25, 2003