Synchronised scroll

99 views
Skip to first unread message

thinkofme...@gmail.com

unread,
Sep 2, 2013, 12:06:25 PM9/2/13
to codenameone...@googlegroups.com
Hi,

I have 2 components one at WEST side and the other at CENTER. They are both scrollable and have the same height. What I would like to do is to scroll vertically both when just one is currently scrolled.

What I've done works well when I scroll keeping the "finger" (currently mouse on the simulator) on one component, but stops working when I spin it. I don't understand why during tensile or spin animation setScrollX/Y are not called. Can you help me?

Thank you in advance

Claudio


Here is my code:

public abstract class AbstractComponent extends Component {

    private boolean scrollableX;
    private boolean scrollableY;
    private List<AbstractComponent> scrollYListeners = new ArrayList<AbstractComponent>(1);
    private boolean scrollingY = false;

    @SuppressWarnings( "OverridableMethodCallInConstructor" )
    public AbstractComponent ( boolean scrollableX, boolean scrollableY ) {

        this.scrollableX = scrollableX;
        this.scrollableY = scrollableY;

        setAlwaysTensile(true);
        setEnabled(true);
        setFocusable(false);
        setScrollVisible(true);
        setSmoothScrolling(true);
        setTensileDragEnabled(true);

    }

    public void addScrollYListener ( AbstractComponent listener ) {
        scrollYListeners.add(listener);
    }

    @Override
    public boolean isScrollableX () {
        return scrollableX;
    }

    @Override
    public boolean isScrollableY () {
        return scrollableY;
    }

    @Override
    public void paint ( Graphics g ) {
...
    }

    @Override
    protected void setScrollY ( int scrollY ) {

        if ( !scrollingY ) {

            scrollingY = true;

            super.setScrollY(scrollY);

            for ( AbstractComponent c : scrollYListeners ) {
                c.updateScrollY(scrollY);
            }

            scrollingY = false;

        }

    }

    void updateScrollY ( int scrollY ) {
        setScrollY(scrollY);
    }

}

public class InstrumentNamesComponent extends AbstractComponent {

    public InstrumentNamesComponent () {
        super(false, true);
        init();
    }

    private void init () {

        setName("InstrumentNamesComponent");
        setCompactInstrumentNames(false);

        Dimension d = new Dimension(200, 10000);

        setPreferredSize(d);
        setScrollSize(d);

    }

}

public class SplitsComponent extends AbstractComponent {

    public SplitsComponent () {
        super(true, true);
        init();
    }

    private void init () {

        setName("SplitsComponent");
        setCompactInstrumentNames(false);

        Dimension d = new Dimension(10000, 10000);

        setPreferredSize(d);
        setScrollSize(d);

    }

}

public class StateMachine extends StateMachineBase {

    private InstrumentNamesComponent instrumentNamesComponent;
    private SplitsComponent splitsComponent;

...

    protected void beforeMain ( Form form ) {

        findCenterContainer(form).addComponent(BorderLayout.WEST, instrumentNamesComponent);
        findCenterContainer(form).addComponent(BorderLayout.CENTER, splitsComponent);
...
        instrumentNamesComponent.addScrollYListener(splitsComponent);
        splitsComponent.addScrollYListener(instrumentNamesComponent);

    }

    protected void initVars ( Resources resources ) {

        instrumentNamesComponent = new InstrumentNamesComponent();
        splitsComponent = new SplitsComponent();

    }

}

Shai Almog

unread,
Sep 2, 2013, 12:36:02 PM9/2/13
to codenameone...@googlegroups.com, thinkofme...@gmail.com
Hi,
you are invoking setPreferredSize which is almost always wrong.
I don't quite understand the use case for this but you can always override setScrollY() and invoke the setScrollY() of the other component (with proper locking to avoid recursion obviously).

thinkofme...@gmail.com

unread,
Sep 6, 2013, 12:08:06 PM9/6/13
to codenameone...@googlegroups.com, thinkofme...@gmail.com
Hi,

I'm already using and overridden setScrollY() with the proper locking. The problem is that it is correctly called when I keep my finger on the device, but not called when an animation completes the move (textile or sweeping animation).

I try to better explain the point with some pictures:

1. I have two vertically large panels. They know each other and have overridden setScrollY() methods to keep their vertical position in sync.

 

Figure 1: The 2 panels starts at Y = 0.


2. Scrolling with the finger kept pressed on one of the two panels works well: both are kept in sync. If I scroll down more, tensile behaviour will allow to scroll both beyond the panels boundaries.

Figure 2: Scrolling & keeping the finger on the panel will scroll the other panel (setScrollY is called on the scrolling one).


3. When I release the finger, the tensile animation works on the dragged panel moving it at the right place but (it seems) without calling the setScrollY method, thus leaving the other panel not synchronised.

Figure 3: Releasing the finger will start tensile animation on the scrolled panel, the other one is not in synch because setScrollY is not called on the animated panel. The same behaviour occurs when sweep-scrolling.


This is a very big issue for me, and I need to understand where I'm wrong.

Thank you for any help.

Claudio

Shai Almog

unread,
Sep 6, 2013, 1:30:34 PM9/6/13
to codenameone...@googlegroups.com, thinkofme...@gmail.com
Hi,
this is internal behavior that I am a bit timid of changing.
It seems the animation code modifies the scroll variable directly, I looked into changing this but it seems that the method has some logic that might be "problematic for this case".

Can you clarify your use case a bit? Why are you trying to do this in this particular way?
Why not have two containers in one scrollable container? It would produce the exact same effect as far as I can tell.

BTW nice visuals, did you draw these or did you use some specialty tool for that?

thinkofme...@gmail.com

unread,
Sep 7, 2013, 3:43:05 AM9/7/13
to codenameone...@googlegroups.com, thinkofme...@gmail.com
Hi,

as can you see in the following image, I have a large canvas the can be scrolled vertically and horizontally, and two side canvases one vertical and the other horizontal that can be scrolled only on one direction.

Scrolling any to these must scroll in synch also the related one(s).


If you can suggest an alternative, it will be wellcome.

The images I've posted here were created using OmniGraffle Professional on Mac. There are user-contributed stencils for tablets, phones, and so on.

Claudio

Shai Almog

unread,
Sep 7, 2013, 1:16:46 PM9/7/13
to codenameone...@googlegroups.com, thinkofme...@gmail.com
Interesting.
Would this be solved by placing both containers on a Y scrollable parent and making the right container scrollable on the X axis?

We normally say that nested scrollable is prohibited but in this case I think this should work because of the different axis.

thinkofme...@gmail.com

unread,
Sep 7, 2013, 2:13:16 PM9/7/13
to codenameone...@googlegroups.com, thinkofme...@gmail.com
What about the bottom-right component that must scroll horizontally in sync with the upper-right? It will have the same problem.

Do you think possible to add a call to the setScrollX/Y at least at the end of the animation (tensile and swipe)? It is probably not the "correct" solution, but at least will re-align components at the and of the animation.

Claudio

Shai Almog

unread,
Sep 8, 2013, 1:44:38 AM9/8/13
to codenameone...@googlegroups.com, thinkofme...@gmail.com
You do make things complicated ;-)

I'll try to add a setScrollX/Y when the animation is finished. This code is pretty hairy so I'm not sure it will work well.
There will be an update before Monday noon so we will find out if this solve your issue soon.

thinkofme...@gmail.com

unread,
Sep 9, 2013, 12:21:31 PM9/9/13
to codenameone...@googlegroups.com, thinkofme...@gmail.com
Hi Shai,

today Codename One plugin updated to ver. 1.0.52. I don't know if this is the version you referred yesterday... however it doesn't solve the problem.

Following the link of the project I'm using to test this problem. You can scroll areas with a red cross drawn inside. I hope it can help you.


Claudio

Shai Almog

unread,
Sep 10, 2013, 4:30:55 AM9/10/13
to codenameone...@googlegroups.com, thinkofme...@gmail.com
Hi Claudio,
did you go into project settings and press refresh project libraries?
Just updating the plugin isn't enough.
If so please file an issue and I'll try to get to it but this is a busy month.

thinkofme...@gmail.com

unread,
Sep 11, 2013, 4:00:51 AM9/11/13
to codenameone...@googlegroups.com, thinkofme...@gmail.com
Hi Shai,

I was unaware of the project libraries refresh requirement.
I did it and it worked.

So for the moment this let me continue my work.
If you agree, I can file a (low priority) issue for having setScrollX/Y called while the animation progress and not just at the end.
Let me know.

For now, thank you for the help.

Claudio

Shai Almog

unread,
Sep 11, 2013, 2:41:12 PM9/11/13
to codenameone...@googlegroups.com, thinkofme...@gmail.com
Great.
I'm not sure we can solve it during the animation progress since the values given there are sometimes illegal so that won't work (tensile drag etc.).
But you can file an RFE for proper scroll event callbacks which is something we should have in place rather than this kludge.

thinkofme...@gmail.com

unread,
Sep 12, 2013, 3:25:21 AM9/12/13
to codenameone...@googlegroups.com, thinkofme...@gmail.com
Done.
Reply all
Reply to author
Forward
0 new messages