Updating screen on the fly


  I have a Jscrollbar with an ms3d milkshape model loaded on a 3D canvas with predefined animations.

Is it possible to update the screen, i.e. update the model as the user moves the scroll bar ?

What I want is the user to see the static position at the particular point of time he has mentioned with the help of scroll bar as timeline.

Thank you


JSlider you mean right ?

That shouldn't be too hard, just add an action listener which reads the values 0 - 10 and set the current frame of the animation or something.

maybe something like this in the JSliders ChangeListener:


Yea… i meant jscrollbar… but I am not using AnimationController class for importing ms3d file… I am using the jointcontroller class…

and I can't figure out much in this complicated class…

plz help

thnk u

JointController also has setStart/EndTime so it should be the same thing.

Yes I found the settime and end time. But does this mean that for every state change of the scroll bar I need to do this ;

jc.setTimes(int start, int end);


But I want to retrieve the model at one particular time, at which the jscroll will point to.

And could you please tell me, what update statements need to be followed ?


Adding "jc.setTimes(1, 24);" to MilkToJME in the readJoints method gives me the error :

Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: -1
        at java.util.ArrayList.get(ArrayList.java:324)
        at com.jmex.model.animation.JointController.setTimes(Unknown Source)
        at com.jmex.model.animation.JointController.setTimes(Unknown Source)
        at MilkToJme.readJoints(MilkToJme.java:178)
        at MilkToJme.convert(MilkToJme.java:145)
        at TennisLanguage$ControlImplementor.setupCharacter(TennisLanguage.java:2089)
        at TennisLanguage$ControlImplementor.simpleSetup(TennisLanguage.java:1733)
        at com.jmex.awt.SimpleCanvasImpl.doSetup(Unknown Source)
        at com.jmex.awt.lwjgl.LWJGLCanvas.paintGL(Unknown Source)
        at org.lwjgl.opengl.AWTGLCanvas.paint(AWTGLCanvas.java:308)
        at sun.awt.RepaintArea.paintComponent(RepaintArea.java:248)
        at sun.awt.RepaintArea.paint(RepaintArea.java:224)
        at sun.awt.windows.WComponentPeer.handleEvent(WComponentPeer.java:301)
        at java.awt.Component.dispatchEventImpl(Component.java:4486)
        at java.awt.Component.dispatchEvent(Component.java:4240)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:273)
        at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:183)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:173)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:168)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:160)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:121)

Uhm, why are you modifying the MilkToJme class? You are supposed to call setTimes after you convert the model and have it rendering to the screen already.

Ok. But I couldn't find where the screen is being rendered in the TestMilkJmeWrite file or all those files included by this file.

It is only the rootNode.attachchild(i) which makes the model appear on screen and then the converted animation starts.

The game loop is implemented in SimpleGame, TestMilkJmeWrite is derived from SimpleGame.

You initialize your scene by creating objects and attaching them to the rootNode in the simpleInitGame() method.

Once that game runs, everything thats attached to the rootNode will be rendered for you in SimpleGame.render().

If you want to change something while the Game is running, you do that in the simpleUpdate() Method which gets called every frame.

You should take your time and read through the user guide in the wiki pretty much everything is well explained there.

Your case is a bit special, because you want to modify the game based on the values of a swing element.

You need to be able to access the reference of the JointController inside the ChangelListener of your JScrollBar, so that you can adjust the value of the JointController when the JScrollBar moves.

So, in your case you actually don’t need to do anything in simpleUpdate() :slight_smile:

core, why don't I need to do anything in simpleupdate… after all , any modifications to be made in the model… they hav to be made through update… in fact… don't I need to bring in the jscroll listener in the simple update…?

could you tell me how exactly should I call setTimes… coz once I call it… it just plays that set… and the next time I cal it… nothing happens…


if you use swing components, you have two threads running, the awt (or swing) thread and the jme thread.

If you pass a reference from the AnimationController or JointController to the ChangeListener, then the changes you make in the awt thread when moving the Scrollbar immediately take effect on the jme side.

So, no action needs to be done in SimpleGames simpleUpdate().

I can't give you any advice regarding the animation stuff tho, i never used it before.

Here is a small example of what i mean.

import java.awt.GridLayout;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.JFrame;
import javax.swing.JScrollBar;

import jmetest.renderer.loader.TestFireMilk;

import com.jme.app.SimpleGame;
import com.jme.math.Vector3f;
import com.jme.renderer.Renderer;
import com.jme.scene.Controller;
import com.jme.scene.Node;
import com.jme.scene.Spatial;
import com.jme.util.export.binary.BinaryImporter;
import com.jme.util.resource.ResourceLocatorTool;
import com.jme.util.resource.SimpleResourceLocator;
import com.jmex.model.animation.JointController;
import com.jmex.model.converters.MilkToJme;

public class MilkTest extends SimpleGame {

    private Spatial model;
    private Logger logger = Logger.getLogger(this.getClass().getName());
    protected void simpleInitGame() {
        try {
                    new SimpleResourceLocator(TestFireMilk.class
                    new SimpleResourceLocator(TestFireMilk.class
            } catch (URISyntaxException e1) {
                logger.log(Level.WARNING, "unable to setup texture directories.", e1);

        MilkToJme converter = new MilkToJme();
        URL MSFile = TestFireMilk.class.getClassLoader().getResource(
        ByteArrayOutputStream BO=new ByteArrayOutputStream();

        try {
        } catch (IOException e) {
            logger.info("IO problem writting the file!!!");
        model = null;
        try {
            model=(Node)BinaryImporter.getInstance().load(new ByteArrayInputStream(BO.toByteArray()));
        } catch (IOException e) {
            logger.info("darn exceptions:" + e.getMessage());
        JointController jc = ((JointController) model.getController(0));
        cam.setLocation(new Vector3f(15, 3, 30));
        cam.lookAt(model.getLocalTranslation(), Vector3f.UNIT_Y);
        // create a Swing frame and pass the JointControllers reference to it
        new MyFrame(((JointController) model.getController(0)));

    /** a simple Frame with a JScrollBar */
    class MyFrame extends JFrame {
        public MyFrame(final JointController jc) {
            setLayout(new GridLayout(1,1));
            JScrollBar scrollbar = new JScrollBar(JScrollBar.HORIZONTAL);
            scrollbar.addAdjustmentListener(new AdjustmentListener() {
                public void adjustmentValueChanged(AdjustmentEvent e) {
                    // run.ms3d has 23 Frames (1-23)
                    System.out.println("AdjustmentEvent value: " +e.getValue());
                    System.out.println("Setting times: " + (1+(23/100.0*e.getValue())));
                    jc.setTimes((int)(23/100.0*e.getValue()), (int)(1+(23/100.0*e.getValue())));
                    // setActive is needed if the RepeatType is set to RT_CLAMP
                    // jc.setActive(true);
            setSize(300, 70);

    public static void main(String[] args) {
        new MilkTest().start();

this post might also be of interest