13. 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.

13.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 might not be obvious is how, from Jess, you can arrange to have something happen when the button is pressed. This section of this manual shows how to implement an interface using only Jess code. Therefore, all you need to do to create event handlers in Jess is to implement the appropriate interface.

An example should clarify matters. Let's say that when a Hello button is pressed, you would like the string Hello, World! to be printed to standard output (how original!). Here's a complete program in Jess that demonstrates how to do it:


Jess> (import java.awt.*)
Jess> (import java.awt.event.*)
Jess> ;; Create the widgets
(defglobal ?*f* = (new Frame "Button Demo"))
Jess> (defglobal ?*b* = (new Button "Hello"))

Jess> ;; Add a listener to the button
(?*b* addActionListener (implement ActionListener using (lambda (?name ?evt)
    (printout t "Hello, World!" crlf))))

Jess> ;; Assemble and display the GUI
(?*f* add ?*b*)
Jess> (?*f* pack)
Jess> (set ?*f* visible TRUE)
You'll have to quit this program using ^C. To fix this, you can add a java.awt.event.WindowListener which handles WINDOW_CLOSING events to the above program:

Jess>  ;; Add a WINDOW_CLOSING listener
(import java.awt.event.WindowEvent)
(?*f* addWindowListener  (implement WindowListener using (lambda (?name ?event)
    (if (= (?event getID) (WindowEvent.WINDOW_CLOSING)) then
        (exit))))
Now when you close the window Jess will exit. Notice how we can examine the ?event parameter for event information.

Because we imported the WindowEvent class, we were able to use "(WindowEvent.WINDOW_CLOSING)" to access this static data member. See the documentation for the import function for details. This technique is very often useful when programming GUIs with Jess.

We have used the "raw" AWT widgets here, but this same technique works fine with Swing as well.

Jess> (import javax.swing.*)
Jess> (import java.awt.event.*)
Jess> (import javax.swing.JFrame)
Jess> (defglobal ?*f* = (new JFrame "Button Demo"))
Jess> (defglobal ?*b* = (new JButton "Hello"))
Jess> (defglobal ?*p* = (get ?*f* contentPane))

Jess> (?*b* addActionListener (implement ActionListener using (lambda (?name ?event)
     (printout t "Hello, World!" crlf))))

Jess> (?*p* add ?*b*)
Jess> (?*f* pack)
Jess> (set ?*f* visible TRUE)

Jess> (?*f* setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE))
  

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

13.2. Screen Painting and Graphics

As you may know, the most common method of drawing pictures in Java is to subclass either or , overriding the void paint(Graphics g) or void paintComponent(Graphics g) method, respectively, to call the methods of the argument to do the drawing. Well, Jess can't help you to subclass a Java class (at least not yet!), but it does provide adaptor classes, much like the event adaptors described above, that will help you draw pictures. The classes are named jess.awt.Canvas and jess.swing.JPanel. They can be used as normal Java GUI components: Canvas in AWT applications, and JPanel with Swing. When you construct an instance of these classes, you pass in the name of a Jess function and a reference to a jess.Rete object. Whenever the Java painting method is called to render the Jess component, the Jess component in turn will call the given function. The function will be passed two arguments: the or jess.swing.JPanel instance itself, and the java.awt.Graphics argument. 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.
(import java.awt.Color)
(deffunction painter (?canvas ?graph)
  (bind ?x (get-member (?canvas getSize) width))
  (bind ?y (get-member (?canvas getSize) height))
  (?graph setColor (Color.blue))
  (?graph fillRect 0 0 ?x ?y)
  (?graph setColor (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)))
Complete programs built on this example are in the files examples/jess/awtdraw.clp and examples/jess/swingdraw.clp in the Jess distribution.