7. Creating Graphical User Interfaces in the Jess Language

Jess, being just a set of Java classes, is easily incorporated as a library into graphical applications written in Java. It is also possible, though, to write graphical applications in the Jess language itself. The details of this are outlined in this chapter.

7.1. Handling Java AWT events

It should now be obvious that you can easily construct GUI objects from Jess. For example, here is a Button:
Jess> (defglobal ?*b* = (new java.awt.Button "Hello"))
What should not be obvious is how, from Jess, you can arrange to have something happen when the button is pressed. For this, I have provided a full set of EventListener classes: Each of these classes implements one of the Listener interfaces from the java.awt.event package in Java 1.1 and later. Each implementation packages up any event notifications it receives and forwards them to a Jess function, which is supplied as a constructor argument to the Listener object.

An example should clarify matters. Let's say that when the Hello button is pressed, you would like the string Hello, World! to be printed to standard output (how original!). What you need to do is:
  1. Define a deffunction which prints the message. The deffunction will be called with one argument: the event object that would be passed to actionPerformed(). (If this is gibberish to you, pick up a book on Java AWT programming.)
  2. Create a jess.awt.ActionListener object, telling it about this deffunction, and also which Jess engine it belongs to. You simply use Jess' new command to do this.
  3. Tell the Button about the ActionListener using the addActionListener method of java.awt.Button.
Here's a complete program in Jess:
Jess> ;; Create the widgets
  (defglobal ?*f* = (new java.awt.Frame "Button Demo"))
  Jess> (defglobal ?*b* = (new java.awt.Button "Hello"))
  Jess> ;; Define the deffunction
  (deffunction say-hello "Unconditionally print a message" (?evt)
    (printout t "Hello, World!" crlf))

  Jess> ;; Connect the deffunction to the button
  (?*b* addActionListener
    (new jess.awt.ActionListener say-hello (engine)))
  Jess> ;; Assemble and display the GUI
  (?*f* add ?*b*)
  Jess> (?*f* pack)
  Jess> (set ?*f* visible TRUE)
The Jess engine function returns the jess.Rete object in which it is executed, as an external address. You'll have to quit this program using ^C. To fix this, you can add a WindowListener which handles WINDOW_CLOSING events to the above program:

Jess> ;; If the event is a WINDOW_CLOSING event, exit the program
  (deffunction frame-handler (?evt)
    (if (= (?evt getID) (get-member ?evt WINDOW_CLOSING)) then 
        (call (get ?evt source) dispose)

  Jess>  ;; Connect this deffunction to the frame
  (?*f* addWindowListener
    (new jess.awt.WindowListener frame-handler (engine)))
Now when you close the window Jess will exit. Notice how we can examine the ?evt parameter for event information.

We have used the "raw" AWT widgets here, but this same technique works fine with Swing as well (the new GUI toolkit for Java 1.2).
Jess> (defglobal ?*f* = (new javax.swing.JFrame "Button Demo"))
  Jess> (defglobal ?*b* = (new javax.swing.JButton "Hello"))
  Jess> (defglobal ?*p* = (get ?*f* "contentPane"))
  Jess> (deffunction say-hello (?evt)
    (printout t "Hello, World!" crlf))

  Jess> (call ?*b* addActionListener
    (new jess.awt.ActionListener say-hello (engine)))
  Jess> (call ?*p* add ?*b*)
  Jess> (call ?*f* pack)
  Jess> (set ?*f* visible TRUE)

  Jess> (deffunction frame-handler (?evt)
    (if (= (?evt getID) (get-member ?evt WINDOW_CLOSING)) then 
        (call (get ?evt source) dispose)

  Jess> (?*f* addWindowListener
    (new jess.awt.WindowListener frame-handler (engine)))

See the demo examples/frame.clp for a slightly more complex example of how you can build an entire Java graphical interface from within Jess.

7.2. Screen Painting and Graphics

As you may know, the most common method of drawing pictures in Java is to subclass java.awt.Canvas, overriding the void paint(Graphics g) method to call the methods of the java.awt.Graphics argument to do the drawing. Well, Jess can't help you to subclass a Java class (at least not yet!), but it does provide an adaptor class, much like the event adaptors described above, that will help you draw pictures. The class is named jess.awt.Canvas, and it is a subclass of java.awt.Canvas. As such it can be used as a normal Java GUI component. When you construct an instance of this class, you pass in the name of a Jess function and a reference to the Rete engine. Whenever paint() is called to render the jess.awt.Canvas, the jess.awt.Canvas in turn will call the given function. The function will be passed two arguments: the jess.awt.Canvas instance itself, and the java.awt.Graphics argument to paint(). In this way, Jess code can draw pictures using Java calls. An example looks like this:
Jess> ;; A painting deffunction. This function draws a red 'X' between the
  ;; four corners of the Canvas on a blue field.
  (deffunction painter (?canvas ?graph)
    (bind ?x (get-member (call ?canvas getSize) width))
    (bind ?y (get-member (call ?canvas getSize) height))
    (?graph setColor (get-member java.awt.Color blue))
    (?graph fillRect 0 0 ?x ?y)
    (?graph setColor (get-member java.awt.Color red))
    (?graph drawLine 0 0 ?x ?y)
    (?graph drawLine ?x 0 0 ?y))

  Jess> ;; Create a canvas and install the paint routine.
  (bind ?c (new jess.awt.Canvas painter (engine)))
A simple but complete program built on this example is in the file examples/draw.clp in the Jess distribution.

Back to index