Scroll panel in lemur

I always thought about porting this back from my own ui back then, but did not find time(and need) to do so.

Basically I used a own material (e.g replace all lemur default ones for this) that contains a cliprectangle as an shader parameter. Everything outside those is then getting discarded in the fragment shader. This way a proper scroll is implementable without having to use a secondary viewport. Scrolltables would be required to set the cliprectange for all children recursivly if the child is not a scrollpane itself. Also they need to merge a cliprectangle from the parent. Further optimisation is to simply flip the cullhint, if a objects cliprectangle is 0 in any direction.

Isn’t that too much work for something that can be easily done with a viewport?.

What about efficiency?, is any of the methods noticeable more/less efficient than the other? (I don’t really know how a new viewport can impact in the overall performance)

Well using a cliprectangle is extremly fast, because all extra work (appart from setting and updating it) is exclusivly done by the gpu. It further allows other similar features, like a button to cutoff text, if it does not fit without resorting to manually manipulating strings.

However I think a viewport will not be noticeably slower, after all we talk about like 1-3 Panels max at a given ui.
Theoretically could a Viewport also render with slower framerate than the main window.

How exactly is the work to make event handling properly work trough a viewport is however outside of my knowledge, but it might work just out of the box with the system pspeed provides.

I actually do not care much about the technical way this is done, after all if it has a clean interface it could be easily replaced later on if problems appear, no matter what approach was choosen. I’m more interested in a working Scrolllpanel that just works out of the box :slight_smile:

The viewportpanel I shared manages the pspeed’s input correctly. Which is the one is using OP (or that I assume after receiving some PM from him… I never verified it O.o).

I use the 2D version to create a scroll panel too:

However, it scrolls with the mouse or the arrows (not bar). It’s as easy as translate it up/down when desired. It should be easy to make a generic scrollpanel to use in most common cases (with toggleable horizontal/vertical bars) but didn’t have the time yet.

I did a profile:

No ViewportPanel :

Four empty ViewportPanel :

And four ViewportPanel with high poly child (~ 12K face) attached

Edit:

And one ViewportPanel with four child:

1 Like

As I said it is probably not that much.
However might I ask, why you render that items with a Viewport? Do they change frequently? or is it just to get a Model there?
I use a system for inventorys, where I generate a image via a secondary viewport only once, and then reuse that image.

(Of course that would not be useable for scrolls, but for a character select it might be an alternative option)

I am using a Viewport because :

Yes I want a mode there (and I am playing tween animation on them).
Which will participate on drag & drop stuff on scene.
But it is not a must to put 3D models in there, of course I can just put an icon instead, and I will do if I run to performance issues.

can i put a example
when i try put
tab1.addChild(panel);
give this error
Uncaught exception thrown in Thread[jME3 Main,5,main]
NullPointerException

You’ve left out all of the important parts of the exception.

Don’t bother posting exceptions without a track trace. They aren’t useful.

i fix the error but i have this result
how put a scroll bar in my panel

    package mygame;

    import com.jme3.app.Application;
    import com.jme3.app.state.BaseAppState;
    import com.jme3.math.Vector3f;
    import com.jme3.renderer.ViewPort;
    import com.jme3.scene.Node;
    import com.simsilica.lemur.ActionButton;
    import com.simsilica.lemur.Axis;
    import com.simsilica.lemur.CallMethodAction;
    import com.simsilica.lemur.Container;
    import com.simsilica.lemur.FillMode;
    import com.simsilica.lemur.Insets3f;
    import com.simsilica.lemur.Label;
    import com.simsilica.lemur.Panel;
    import com.simsilica.lemur.PasswordField;
    import com.simsilica.lemur.TabbedPanel;
    import com.simsilica.lemur.TextField;
    import com.simsilica.lemur.component.SpringGridLayout;
    import com.simsilica.lemur.style.ElementId;
    import com.simsilica.lemur.RollupPanel;
    import mygame.panels.ViewportPanel;

    /**
     *
     * @author Pedro Alves
     */
    public class OptionsState  extends BaseAppState  {
        private Container loginPanel;
        private TextField nameField;
        private PasswordField passwordfield;
          private ViewPort  viewPort;
     protected void apply() {
            
           // String name = nameField.getText().trim();
          // String password= passwordfield.getText().trim();
           // if( getState(ConnectionState.class).joinserver(nameField.getText(),passwordfield.getText()) ) {
            //    getStateManager().detach(this);
            //}
        } 
      protected void join() {
            
           // String name = nameField.getText().trim();
          // String password= passwordfield.getText().trim();
           // if( getState(ConnectionState.class).joinserver(nameField.getText(),passwordfield.getText()) ) {
            //    getStateManager().detach(this);
            //}
        } 
     protected void cancel() {
         getStateManager().attach(new MainMenuState());
         getStateManager().detach(this); 
           // String name = nameField.getText().trim();
          // String password= passwordfield.getText().trim();
           // if( getState(ConnectionState.class).joinserver(nameField.getText(),passwordfield.getText()) ) {
            //    getStateManager().detach(this);
            //}
        } 
        public OptionsState() {
        
        }
        @Override
        protected void initialize(Application app) {
          loginPanel = new Container();
            loginPanel.addChild(new Label("Options", new ElementId("title")));
            
            Container props = loginPanel.addChild(new Container(new SpringGridLayout(Axis.Y, Axis.X, FillMode.None, FillMode.Last)));
            props.setBackground(null);    
            TabbedPanel tabs = new TabbedPanel();
            Panel panel1=new Panel(500,200);
            panel1.setInsets(new Insets3f(10, 10, 10, 10));
            ViewportPanel panel= new ViewportPanel(getStateManager(),panel1.getElementId(),panel1.getStyle());
    panel.attachScene(panel1);

    Container tab1 = tabs.addTab("Game Options", new Container());
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));

    tab1.addChild(panel1);

    tab1.addChild(panel);
    Container tab2 = tabs.addTab("Graphic Options", new Container());
    tab2.addChild(new Label("Grapicos options"));
    Container tab3 = tabs.addTab(" Audio Options", new Container());
    tab3.addChild(new Label("Audio"));
    Container tab4 = tabs.addTab("Key Mapping ", new Container());
    tab4.addChild(new Label("Key Mapping"));
     loginPanel.addChild(tabs);

         Container buttons = loginPanel.addChild(new Container(new SpringGridLayout(Axis.X, Axis.Y)));
            buttons.setBackground(null);
            buttons.setLayout(new SpringGridLayout(Axis.X, Axis.Y));
           buttons.addChild(new ActionButton(new CallMethodAction("Default", this, "join"))); 
           buttons.addChild(new ActionButton(new CallMethodAction("Reset", this, "join")));
           buttons.addChild(new ActionButton(new CallMethodAction("Apply", this, "join"))); 
             buttons.addChild(new ActionButton(new CallMethodAction("OK", this, "join"))); 
             buttons.addChild(new ActionButton(new CallMethodAction("Cancel", this, "cancel"))); 
            float scale = 1.5f * getState(MainMenuState.class).getStandardScale();
            loginPanel.setLocalScale(scale);
            Vector3f prefs = loginPanel.getPreferredSize().clone();
            prefs.x = Math.max(300, prefs.x);
            loginPanel.setPreferredSize(prefs.clone());
            // Now account for scaling
            prefs.multLocal(scale);
            int width = app.getCamera().getWidth();
            int height = app.getCamera().getHeight();
            loginPanel.setLocalTranslation(width * 0.5f - prefs.x * 0.5f, height * 0.5f + prefs.y * 0.5f, 10);       
        }

        @Override
        protected void cleanup(Application app) {
            
        }

        @Override
        protected void onEnable() {
             Node root = ((Main)getApplication()).getGuiNode();
            root.attachChild(loginPanel);
        }

        @Override
        protected void onDisable() {
            //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
        loginPanel.removeFromParent();
        }
        
    }

can you put the code with viewportpanel

Link to ViewportPanel is available here

i want know how you put the view port panel to work
i can´t make it work

I am not sure if this will help you or not.
I am using it in my CellRenderer for GridPanel

/**
 * Used to render 3D Items (items which have spatial) in a Gui panel
 *
 * @author Ali-RS <ali_codmw@yahoo.com>
 */
public class ItemRenderer extends DefaultCellRenderer<Item> {

    protected Map<Item, Spatial> spatials = new HashMap<>();
    private final AppStateManager stateManager;

    public ItemRenderer(AppStateManager stateManager) {
        super(null);
        this.stateManager = stateManager;
    }

    @Override
    public Panel getView(Item item, boolean selected, Panel existing) {

        if (existing == null) {

            //Container container = new Container();
            ViewportPanel container = new ViewportPanel(stateManager, new ElementId(Container.ELEMENT_ID), null);
            existing = container;

            /**
             * A white, directional light source
             */
            DirectionalLight sun = new DirectionalLight();
            sun.setDirection(Vector3f.UNIT_Z.negate());
            sun.setColor(ColorRGBA.White);
            container.addLight(sun);

            GuiGlobals.getInstance().getAnimationState().
                    add(new TweenAnimation(true, Tweens.smoothStep(SpatialTweens.rotate(container.getViewPortNode(), new Quaternion().fromAngleAxis(-FastMath.QUARTER_PI, Vector3f.UNIT_Y), new Quaternion().fromAngleAxis(FastMath.QUARTER_PI, Vector3f.UNIT_Y), 2)),
                            Tweens.smoothStep(SpatialTweens.rotate(container.getViewPortNode(), new Quaternion().fromAngleAxis(FastMath.QUARTER_PI, Vector3f.UNIT_Y), new Quaternion().fromAngleAxis(-FastMath.QUARTER_PI, Vector3f.UNIT_Y), 2))));

//            GuiGlobals.getInstance().getAnimationState().
//                    add(new TweenAnimation(true, (new RotateSpatial(container.getViewPortNode(),
//                            new Quaternion().fromAngleAxis(FastMath.PI, Vector3f.UNIT_Y), 5))));
        }

        if (item != null) {
            if (!spatials.containsKey(item)) {
                Spatial spatial = loadSpatial(item);
                spatials.put(item, spatial);

                //No need when using ViewportPanel  
//                Tween attachTween = Tweens.callTweenMethod(5, this, "inset", (Container) existing, (Container) existing.getChild(0), spatial);
//                GuiGlobals.getInstance().getAnimationState().add(attachTween);
            }

            Spatial spatial = spatials.get(item);
            spatial.removeFromParent();
            ((ViewportPanel) existing).attachScene(spatial);
        } else {
            ((ViewportPanel) existing).getViewPortNode().detachAllChildren();
        }

        return existing;
    }

    public Spatial getSpatial(Item item) {
        return spatials.get(item);
    }

    public Spatial removeSpatial(Item item) {
        return spatials.remove(item);
    }

    protected Spatial loadSpatial(Item item) {
        return ItemLoader.getSpatial(item);
    }

}

I am using ViewportPanel to display jme spatials inside gui elements.

Note, for scrolling I am not using viewport at all, it’s just a Lemur Slider with a GridPanel just like ListBox.

i want create a options menu with scrollpanel
i can´t make work
tanks for the help
can you se my code and what i doing wrong

 package mygame;

    import com.jme3.app.Application;
    import com.jme3.app.state.BaseAppState;
    import com.jme3.math.Vector3f;
    import com.jme3.renderer.ViewPort;
    import com.jme3.scene.Node;
    import com.simsilica.lemur.ActionButton;
    import com.simsilica.lemur.Axis;
    import com.simsilica.lemur.CallMethodAction;
    import com.simsilica.lemur.Container;
    import com.simsilica.lemur.FillMode;
    import com.simsilica.lemur.Insets3f;
    import com.simsilica.lemur.Label;
    import com.simsilica.lemur.Panel;
    import com.simsilica.lemur.PasswordField;
    import com.simsilica.lemur.TabbedPanel;
    import com.simsilica.lemur.TextField;
    import com.simsilica.lemur.component.SpringGridLayout;
    import com.simsilica.lemur.style.ElementId;
    import com.simsilica.lemur.RollupPanel;
    import mygame.panels.ViewportPanel;

    /**
     *
     * @author Pedro Alves
     */
    public class OptionsState  extends BaseAppState  {
        private Container loginPanel;
        private TextField nameField;
        private PasswordField passwordfield;
          private ViewPort  viewPort;
     protected void apply() {
            
           // String name = nameField.getText().trim();
          // String password= passwordfield.getText().trim();
           // if( getState(ConnectionState.class).joinserver(nameField.getText(),passwordfield.getText()) ) {
            //    getStateManager().detach(this);
            //}
        } 
      protected void join() {
            
           // String name = nameField.getText().trim();
          // String password= passwordfield.getText().trim();
           // if( getState(ConnectionState.class).joinserver(nameField.getText(),passwordfield.getText()) ) {
            //    getStateManager().detach(this);
            //}
        } 
     protected void cancel() {
         getStateManager().attach(new MainMenuState());
         getStateManager().detach(this); 
           // String name = nameField.getText().trim();
          // String password= passwordfield.getText().trim();
           // if( getState(ConnectionState.class).joinserver(nameField.getText(),passwordfield.getText()) ) {
            //    getStateManager().detach(this);
            //}
        } 
        public OptionsState() {
        
        }
        @Override
        protected void initialize(Application app) {
          loginPanel = new Container();
            loginPanel.addChild(new Label("Options", new ElementId("title")));
            
            Container props = loginPanel.addChild(new Container(new SpringGridLayout(Axis.Y, Axis.X, FillMode.None, FillMode.Last)));
            props.setBackground(null);    
            TabbedPanel tabs = new TabbedPanel();
            Panel panel1=new Panel(500,200);
            panel1.setInsets(new Insets3f(10, 10, 10, 10));
            ViewportPanel panel= new ViewportPanel(getStateManager(),panel1.getElementId(),panel1.getStyle());
    panel.attachScene(panel1);

    Container tab1 = tabs.addTab("Game Options", new Container());
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));

    tab1.addChild(panel1);

    tab1.addChild(panel);
    Container tab2 = tabs.addTab("Graphic Options", new Container());
    tab2.addChild(new Label("Grapicos options"));
    Container tab3 = tabs.addTab(" Audio Options", new Container());
    tab3.addChild(new Label("Audio"));
    Container tab4 = tabs.addTab("Key Mapping ", new Container());
    tab4.addChild(new Label("Key Mapping"));
     loginPanel.addChild(tabs);

         Container buttons = loginPanel.addChild(new Container(new SpringGridLayout(Axis.X, Axis.Y)));
            buttons.setBackground(null);
            buttons.setLayout(new SpringGridLayout(Axis.X, Axis.Y));
           buttons.addChild(new ActionButton(new CallMethodAction("Default", this, "join"))); 
           buttons.addChild(new ActionButton(new CallMethodAction("Reset", this, "join")));
           buttons.addChild(new ActionButton(new CallMethodAction("Apply", this, "join"))); 
             buttons.addChild(new ActionButton(new CallMethodAction("OK", this, "join"))); 
             buttons.addChild(new ActionButton(new CallMethodAction("Cancel", this, "cancel"))); 
            float scale = 1.5f * getState(MainMenuState.class).getStandardScale();
            loginPanel.setLocalScale(scale);
            Vector3f prefs = loginPanel.getPreferredSize().clone();
            prefs.x = Math.max(300, prefs.x);
            loginPanel.setPreferredSize(prefs.clone());
            // Now account for scaling
            prefs.multLocal(scale);
            int width = app.getCamera().getWidth();
            int height = app.getCamera().getHeight();
            loginPanel.setLocalTranslation(width * 0.5f - prefs.x * 0.5f, height * 0.5f + prefs.y * 0.5f, 10);       
        }

        @Override
        protected void cleanup(Application app) {
            
        }

        @Override
        protected void onEnable() {
             Node root = ((Main)getApplication()).getGuiNode();
            root.attachChild(loginPanel);
        }

        @Override
        protected void onDisable() {
            //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
        loginPanel.removeFromParent();
        }
        
    }

Sorry I have no time right now, I could not look at your code,

Do not know how to do that,

But instead better way is to break your options to TabbedPanels and RollupPanels

like this

and

ok
when you have time to see my code
or make a simple example how to use viewportpanel

I created a simple example with your code

    import com.jme3.app.Application;
    import com.jme3.app.SimpleApplication;
    import com.jme3.app.state.BaseAppState;
    import com.jme3.math.Vector3f;
    import com.jme3.renderer.ViewPort;
    import com.jme3.scene.Node;
    import com.overthemoon.core.inventory.panel.ViewportPanel;
    import com.overthemoon.core.inventory.panel.ViewportPanel2D;
    import com.simsilica.lemur.ActionButton;
    import com.simsilica.lemur.Axis;
    import com.simsilica.lemur.CallMethodAction;
    import com.simsilica.lemur.Container;
    import com.simsilica.lemur.DefaultRangedValueModel;
    import com.simsilica.lemur.FillMode;
    import com.simsilica.lemur.Insets3f;
    import com.simsilica.lemur.Label;
    import com.simsilica.lemur.Panel;
    import com.simsilica.lemur.PasswordField;
    import com.simsilica.lemur.Slider;
    import com.simsilica.lemur.TabbedPanel;
    import com.simsilica.lemur.TextField;
    import com.simsilica.lemur.component.BorderLayout;
    import com.simsilica.lemur.component.SpringGridLayout;
    import com.simsilica.lemur.core.GuiControl;
    import com.simsilica.lemur.style.ElementId;
    import com.simsilica.lemur.style.Styles;

    /**
     *
     * @author Pedro Alves
     */
    public class OptionsState  extends BaseAppState  {
        private Container loginPanel;
        private TextField nameField;
        private PasswordField passwordfield;
          private ViewPort  viewPort;
     protected void apply() {
            
           // String name = nameField.getText().trim();
          // String password= passwordfield.getText().trim();
           // if( getState(ConnectionState.class).joinserver(nameField.getText(),passwordfield.getText()) ) {
            //    getStateManager().detach(this);
            //}
        } 
      protected void join() {
            
           // String name = nameField.getText().trim();
          // String password= passwordfield.getText().trim();
           // if( getState(ConnectionState.class).joinserver(nameField.getText(),passwordfield.getText()) ) {
            //    getStateManager().detach(this);
            //}
        } 
     protected void cancel() {
         getStateManager().attach(new MainMenuState());
         getStateManager().detach(this); 
           // String name = nameField.getText().trim();
          // String password= passwordfield.getText().trim();
           // if( getState(ConnectionState.class).joinserver(nameField.getText(),passwordfield.getText()) ) {
            //    getStateManager().detach(this);
            //}
        } 
        public OptionsState() {
        
        }
        @Override
        protected void initialize(Application app) {
          loginPanel = new Container();
            loginPanel.addChild(new Label("Options", new ElementId("title")));
            
            Container props = loginPanel.addChild(new Container(new SpringGridLayout(Axis.Y, Axis.X, FillMode.None, FillMode.Last)));
            props.setBackground(null);    
            TabbedPanel tabs = new TabbedPanel();
            Panel panel1=new Panel(500,200);
            panel1.setInsets(new Insets3f(10, 10, 10, 10));
            ViewportPanel panel= new ViewportPanel(getStateManager(),panel1.getElementId(),panel1.getStyle());
    panel.attachScene(panel1);

    Container tab1 = tabs.addTab("Game Options", new Container());
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));
    panel1=tab1.addChild(new Label("Game Options"));

    tab1.addChild(panel1);

    tab1.addChild(panel);
    Container tab2 = tabs.addTab("Graphic Options", new Container());
    tab2.addChild(new Label("Grapicos options"));
    Container tab3 = tabs.addTab(" Audio Options", new Container());
    tab3.addChild(new Label("Audio"));
    Container tab4 = tabs.addTab("Key Mapping ", new Container());
    tab4.addChild(new Label("Key Mapping"));
     loginPanel.addChild(tabs);

         Container buttons = loginPanel.addChild(new Container(new SpringGridLayout(Axis.X, Axis.Y)));
            buttons.setBackground(null);
            buttons.setLayout(new SpringGridLayout(Axis.X, Axis.Y));
           buttons.addChild(new ActionButton(new CallMethodAction("Default", this, "join"))); 
           buttons.addChild(new ActionButton(new CallMethodAction("Reset", this, "join")));
           buttons.addChild(new ActionButton(new CallMethodAction("Apply", this, "join"))); 
             buttons.addChild(new ActionButton(new CallMethodAction("OK", this, "join"))); 
             buttons.addChild(new ActionButton(new CallMethodAction("Cancel", this, "cancel"))); 
            float scale = 1.5f * getState(MainMenuState.class).getStandardScale();
            loginPanel.setLocalScale(scale);
            Vector3f prefs = loginPanel.getPreferredSize().clone();
            prefs.x = Math.max(300, prefs.x);
            loginPanel.setPreferredSize(prefs.clone());
            // Now account for scaling
            prefs.multLocal(scale);
            int width = app.getCamera().getWidth();
            int height = app.getCamera().getHeight();
            //loginPanel.setLocalTranslation(width * 0.5f - prefs.x * 0.5f, height * 0.5f + prefs.y * 0.5f, 10);       
        }

        @Override
        protected void cleanup(Application app) {
            
        }

        @Override
        protected void onEnable() {
            ViewportPanel2D viewportPanel = new ViewportPanel2D(getStateManager(), new ElementId(Container.ELEMENT_ID), Styles.ROOT_STYLE);
            viewportPanel.setPreferredSize(new Vector3f(600,400 , 1));
            int width = getApplication().getCamera().getWidth();
            int height = getApplication().getCamera().getHeight();
            viewportPanel.setLocalTranslation((width - 600) / 2, (height + 400) / 2, 100);
            BorderLayout layout = new BorderLayout();
            viewportPanel.getControl(GuiControl.class).setLayout(layout);
            Slider slider_V = new Slider(new DefaultRangedValueModel(), Axis.Y);
            layout.addChild(BorderLayout.Position.East, slider_V);
            
            Slider slider_H = new Slider(new DefaultRangedValueModel(), Axis.X);
            layout.addChild(BorderLayout.Position.South, slider_H);
            
            Node root = ((SimpleApplication)getApplication()).getGuiNode();
            root.attachChild(viewportPanel);
            viewportPanel.attachScene(loginPanel);
            
        }

        @Override
        protected void onDisable() {
            //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
        loginPanel.removeFromParent();
        }
        
    }

changed parts :

  • removed :
    //loginPanel.setLocalTranslation(width * 0.5f - prefs.x * 0.5f, height * 0.5f + prefs.y * 0.5f, 10);

added viewport stuff :

protected void onEnable() {
            ViewportPanel2D viewportPanel = new ViewportPanel2D(getStateManager(), new ElementId(Container.ELEMENT_ID), Styles.ROOT_STYLE);
            viewportPanel.setPreferredSize(new Vector3f(600,400 , 1));
            int width = getApplication().getCamera().getWidth();
            int height = getApplication().getCamera().getHeight();
            viewportPanel.setLocalTranslation((width - 600) / 2, (height + 400) / 2, 100);
            BorderLayout layout = new BorderLayout();
            viewportPanel.getControl(GuiControl.class).setLayout(layout);
            Slider slider_V = new Slider(new DefaultRangedValueModel(), Axis.Y);
            layout.addChild(BorderLayout.Position.East, slider_V);
            
            Slider slider_H = new Slider(new DefaultRangedValueModel(), Axis.X);
            layout.addChild(BorderLayout.Position.South, slider_H);
            
            Node root = ((SimpleApplication)getApplication()).getGuiNode();
            root.attachChild(viewportPanel);
            viewportPanel.attachScene(loginPanel);
            
        }
  • Do this yourself :
    Update location of loginPanel by listening to slider changes.
3 Likes

Thanks for the help

1 Like

I trying put the update my contaner when i scroll up our down put i can’t make it work
what i doing wrong

slider_V.getThumbButton().addCommands(Button.ButtonAction.Click.Up, new Command() {
            @Override
            public void execute(Object source) {
                logger.log(Level.INFO, "spinSlider Button UP"); 

            }
        });
        slider_V.getThumbButton().addCommands(Button.ButtonAction.Click.Down, new Command() {
            @Override
            public void execute(Object source) {
                logger.log(Level.INFO, "spinSlider Button Down");
            }
        });