## SwingOSC – Java-based GUI classes

This class allows you to access Java classes in a rather direct way. last mod: 15-Jan-08 sciss

# JavaObject

`JavaObject` is a client-side representation of some java object created on the SwingOSC server instance. You can use this object to "script" java in more intuitive way than sending explict OSC messages. Every method you call on a JavaObject gets automatically translated into an appropriate OSC message. For example, if your `JavaObject` `x` was to reference an instance of `java.awt.Frame`, calling `x.toFront` would bring that frame to the front, etc. There are a few exceptions where the method names are reserved by `JavaObject` itself or its superclass `Object`. Also, methods that should return a value have a special underscore trailing character (see section "Client-Side Retrieval").

## Instantiation

You create an instance of a java class by calling

        JavaObject.new( <fullyQualifiedJavaClassName>, [ <swingOSCserver>, [ … <constructorArgs> ]])

You can then access that instance just like you would in java, by calling any of its methods. Note however, that methods defined in `Object.sc` are often handled by SuperCollider and are not forwarded to java. Some of these have been overriden to be usable in java, like `free`, `stop`, `update`, but others not (e.g. `equals`). In case of a name conflict, you must make direct use of `SwingOSC -> sendMsg`.

Example:

    (
    var cx, cy, rx, ry, sh, sw, dur;

    // create an instance of java.awt.Robot
    x   = JavaObject( "java.awt.Robot" );
    sw  = JSCWindow.screenBounds.width;
    sh  = JSCWindow.screenBounds.height;
    cx  = sw.div( 2 );
    cy  = sh.div( 2 );
    rx  = cx.div( 2 );
    ry  = cy.div( 2 );
    dur = 5;
    fork {
        360.do({ arg i;
            // call the method 'moveMouse' in java.awt.Robot
            x.mouseMove( cx + (cos( i * pi / 180 ) * rx),
                         cy - (sin( i * pi / 180 ) * ry));
            (dur/360).wait;
        });
    };
    )

## Server-Side Assignment

Getting results from java objects is tricky as this is essentially an asynchronous process. one workaround is to store results of java calls in a new java object (instead of transferring it to the client side / supercollider), using the special method `*newFrom` :

    	JavaObject.newFrom( <anExistingJavaObject>, <aMethodInExistingObject>, [ ... <argsToTheMethodCall> ]])

Example:

    (
    // assumes 'x' is still assigned from the example above!
    // x = JavaObject( "java.awt.Robot" );

    // call the method 'createScreenCapture' in java.awt.Robot and store the result in a new
    // object 'a'. notice how we use another JavaObject (the rectangle) as a regular method argument
    a = JavaObject.newFrom( x, \createScreenCapture, JavaObject( "java.awt.Rectangle", nil, 0, 0, 256, 256 ));

    // create an icon view from the image. note: the second argument is always the SwingOSC server (nil = default)
    b = JavaObject( "javax.swing.ImageIcon", nil, a );

    // create a panel that contains the icon view
    c = JavaObject( "javax.swing.JOptionPane", nil, "Here's a part of your screen", -1, 0, b );

    // create a dialog that contains the panel
    d = JavaObject.newFrom( c, \createDialog, nil, "Test" );

    // show the dialog
    d.show;
    )

## Client-Side Retrieval

...if you really need the values inside SuperCollider, you can use asynchronous getter methods. These are named as the regular java methods but with a trailing underscore `_` character. these methods must be run inside a Routine (as they wait for the reply from the server). You can only read primitive values. Java objects need to be decomposed using several getter calls that return primitive values. For example, a `java.awt.Color` object cannot be transferred to SuperCollder, but its R/G/B components can:

    e = JavaObject.newFrom( x, \getPixelColor, 30, 10 );
    (
    // note: fork { } is short for Routine({ }).play
    fork { var red, green, blue;
        red     = e.getRed_;
        green   = e.getGreen_;
        blue    = e.getBlue_;
        ("screen pixel (30,10) has : red = "++red++"; green = "++green++"; blue = "++blue).postln;
    }
    )

Please note the example of `notNull` in the next section to see how `NullPointerException`s can be avoided.

## Accessing classes

Sometimes you will want to access static methods, i.e. you need access to a class object which you don"t instantiate. One example is showing a dialog using javax.swing.JOptionPane. To do this, use `*getClass` :

    	JavaObject.getClass( <fullyQualifiedJavaClassName>, [ <swingOSCserver> ])

Example:

    f = JavaObject.getClass( 'javax.swing.JOptionPane' );
    f.showMessageDialog( nil, "Il arrive que la realite\nsoit trop complexe\npour la transmission orale" );
    // after the user has confirmed the input dialog, the result (java.lang.String) is stored in server-side h:
    h = JavaObject.newFrom( f, \showInputDialog, nil, "Votre marque de voiture?" );
    // let's read that string:
    fork { if( h.notNull, { ("Result: " ++ h.toString_).postln }, { "Dialog still open!".postln })}; // tricky ;-3

Note the security check `notNull` to see if the server object `h` is actually existing.

## Accessing fields

Sometimes you will want to access an object's field, for example because you don't have an appropriate getter method at hand. You can do a server-side creation of an object holding a field's value by using the `*getField` method:

    	JavaObject.getField( <javaObject>, <fieldName> )

Example:

    x = JavaObject.getClass( "java.lang.System" );
    y = JavaObject.getField( x, \out ); // the output stream
    y.println( "Hola Mundo" );

## Wrapping existing server-side objects

If you wish to access an already existing object on the server whose identifier you know, you can create a wrapper object:

    	JavaObject.basicNew( <identifier>, [ <swingOSCserver> ])

Example:

    w = JSCWindow.new.front;
    // wrap the window in a JavaObject instance:
    x = JavaObject.basicNew( w.id, w.server );
    // call setCursor (which is a method in java.awt.Component and thus also applies to javax.swing.JFrame)
    x.setCursor( JavaObject( 'java.awt.Cursor', x.server, 1 ));   // 1 = crosshair shape

For quick checking, the method `print` is directly translated into a SwingOSC `[ "/print" … ]` command:

    x.print;

## Cleaning up

When you plan to use JavaObject extensively in your projects, make sure to delete the object references when they are not needed anymore, otherwise these objects cannot be processed by java"s garbage collector:

    a.destroy;
    b.destroy;
    // etc.
    a.toString; // --> FAILURE /method Object not found (reference was deleted)

or shortcut (beware!):

    JavaObject.destroyAll;
    f.toString; // --> FAILURE /method Object not found (reference was deleted)

Note that `*destroyAll` is called upon shutdown (quitting SuperCollider or recompiling the class library)! `*destroyAll` ignores objects created using `*basicNew`.