This class allows you to access Java classes in a rather direct way. last mod: 15-Jan-08 sciss
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").
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; }); }; )
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; )
...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.
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.
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" );
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;
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
.