Skip to main content

JXLayer and Scrollable components

10 replies [Last post]
pietblok
Offline
Joined: 2003-07-17
Points: 0

Hi Alex,

I experimented with JXLayer to create the effect of a disappearing cursor when the mouse is not touched for a few seconds. That worked great!

However, I encountered a problem: my component implements the Scrollable interface to have some custom behavior when used in a JScrollPane.

When I wrap my component in a JXLayer, that behavior is lost.

I cannot subclass JXLayer (you explained why). Is it possible to have JXLayer implement Scrollable and let it delegate the Scrollable methods to the wrapped component (if the wrapped component implements Scrollable)?

I am not sure what values should be returned if the wrapped component does not implement Scrollable. Maybe you could provide two versions of JXLayer, one implementing Scrollable, the other not?

As a temporary workaround I can of course wrap the JScrollPane, containing my component, in a JXLayer, but that has the effect of a disappearing cursor also on the slidebars (which I do not want).

Thanks,

Piet

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
alexfromsun
Offline
Joined: 2005-09-05
Points: 0

Hello Piet

JXLayer class was made Scrollable, as usual it delegates all its method to the LayerUI,
in its turn LayerUI calls their counterparts from the layer's view if it is also Scrollable

please download the newest layer.jar and let me know how it works for you

Thanks
alexp

pietblok
Offline
Joined: 2003-07-17
Points: 0

Hi Alex,

Thanks, it works great. The scrollable behavior is now as expected.

However, I detected a new problem, the mouse scroll wheel. (FYI: a wrapped JXLayer in a scrollable JPanel exhibits the same problem).

The mouse scroll wheel works only when the mouse is over one of the scrolling elements (scrollbars and scroll corners), not when the mouse is over my component (the JScrollPane is not in the JXLayer, my component is, so the view of the JScrollPane is the JXLayer).

What could be the cause of that?

I cannot test this with the previous version of JXLayer because I accidentally have overwritten that version with the new one.

Oh, and i changed the setting of the sursor. I now set it on layer.getGlassPane(). Works as a charm.

Thanks

Piet

alexfromsun
Offline
Joined: 2005-09-05
Points: 0

Hello Piet

I need some time to think how to solve this mouse scroll wheel problem,
stay tuned

thanks
alexp

alexfromsun
Offline
Joined: 2005-09-05
Points: 0

Hello Piet

I found a simple and effective fix for the "mouse scroll wheel problem",
check out the new jxlayer.jar and let me know how it works for you

By the way, you didn't answer to my question from the previous messages
(it's about writing a blog)

Thanks
alexp

pietblok
Offline
Joined: 2003-07-17
Points: 0

Hi Alex,

Yes, the scroll wheel in the new version works!
Thanks.

About the blog: I deliberately did not answer that question yet, because I wanted to think it over. I am not much of a blogger (I don't have a blog).

However, since I own a website I can try to create my first blog.

The small project I am currently working on is just a very simple image viewer with some added capabilities (resize to fit if component is smaller, resize to fit if component is larger, rotate, open directory or image file, open URL). It features a pseudo full screen mode (in contrast to exclusive full screen mode).

Preparing it for webstart is a bit complicated because it requires access to the user's local disk (to load images), so the jar must be signed.

So OK, I'll give it a try and send you a link when done.

Thank you so much for your support,

Piet

alexfromsun
Offline
Joined: 2005-09-05
Points: 0

Hello Piet

Making and signing webstart application is not as complicated, see Kirill's blog:
http://weblogs.java.net/blog/kirillcool/archive/2005/05/signing_jars_fo....

Good luck with your project
alexp

alexfromsun
Offline
Joined: 2005-09-05
Points: 0

Hello Piet

You know, I thought about making JXLayer scrollable,
but also wasn't sure about what values to return if wrapped component is not Scrollable

I'll think how to solve this problem, thanks for the code

Meanwhile, could you tell us a bit more about the effect you are working on?

Thanks
alexp

pietblok
Offline
Joined: 2003-07-17
Points: 0

Hi Alex,

Thanks for the prompt answer. Yes, that would be wonderful if JXLayer implements Scrollable.

Please see below the code that wraps a component so that the cursor will disappear. I use it for showing artwork or images where I do not want a cursor to spoil the effect, especially in full screen mode.

[code]
/**
* Prepare a JComponent for a disappearing cursor. The targetComponent will
* be wrapped in a new JComponent that will be returned.
*

* When the mouse is touched, the cursor will re-appear for some time.
*

*

* Requires the JXLayer package to be present.
*

*
* @param targetComponent
* the component for which no cursor must be shown
* @param cursorTimeout
* time in milliseconds that the cursor is shown after any
* mouse action (must be greater than 0)
* @return a new JComponent with a disappearing cursor
*/
public static JComponent prepareForDisappearingCursor(
JComponent targetComponent, final int cursorTimeout) {
final JXLayer layer = new JXLayer(
targetComponent);
layer.setUI(new AbstractLayerUI() {

private final Cursor nullCursor;

private Cursor oldCursor;

private final Timer timer;

{
nullCursor = Toolkit.getDefaultToolkit().createCustomCursor(
new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB),
new Point(0, 0), "nullCursor");
oldCursor = layer.getCursor();
layer.setCursor(nullCursor);
timer = new Timer(cursorTimeout, new ActionListener() {

@Override
public void actionPerformed(ActionEvent event) {
Cursor currentCursor = layer.getCursor();
if (nullCursor != currentCursor) {
oldCursor = currentCursor;
}
layer.setCursor(nullCursor);
}
});
timer.setRepeats(false);
}

private void resetCursor() {
if (nullCursor == layer.getCursor()) {
layer.setCursor(oldCursor);
}
timer.restart();
}

@Override
protected void processMouseEvent(MouseEvent e, JXLayer l) {
resetCursor();
}

@Override
protected void processMouseMotionEvent(MouseEvent e,
JXLayer l) {
resetCursor();
}

});
/*
* The workaround: instead of returning the JXLayer object, wrap it in a
* Scrollable JPanel
*/
return new ScrollableJXLayerWrapper(layer);

}
[/code]

Thanks
Piet

alexfromsun
Offline
Joined: 2005-09-05
Points: 0

Hello Piet

This usage of JXLayer is very interesting, how about writing a blog about that?
;-)

By the way, you can also set the mouse cursor to the layer.glassPane() instead of layer
in this case you'll have the same cursor even if a underlying component has another one

Thanks
alexp

pietblok
Offline
Joined: 2003-07-17
Points: 0

Hi Alex,

Meanwhile I found a better workaround with no side effects. I just wrap the JXLayer in a Scrollable JPanel as follows:

[code]
public class ScrollableJXLayerWrapper extends JPanel implements
Scrollable {

private static final long serialVersionUID = 1L;

private final JXLayer layer;

public ScrollableJXLayerWrapper(JXLayer layer) {
super(new BorderLayout());
this.layer = layer;
this.add(layer, BorderLayout.CENTER);
}

@Override
public Dimension getPreferredScrollableViewportSize() {
JComponent view = layer.getView();
if (view instanceof Scrollable) {
return ((Scrollable) view).getPreferredScrollableViewportSize();
} else {
return this.getPreferredSize();
}
}

@Override
public int getScrollableBlockIncrement(Rectangle visibleRect,
int orientation, int direction) {
JComponent view = layer.getView();
if (view instanceof Scrollable) {
return ((Scrollable) view).getScrollableBlockIncrement(
visibleRect, orientation, direction);
} else {
return 1;
}
}

@Override
public boolean getScrollableTracksViewportHeight() {
JComponent view = layer.getView();
if (view instanceof Scrollable) {
return ((Scrollable) view).getScrollableTracksViewportHeight();
} else {
return false;
}
}

@Override
public boolean getScrollableTracksViewportWidth() {
JComponent view = layer.getView();
if (view instanceof Scrollable) {
return ((Scrollable) view).getScrollableTracksViewportWidth();
} else {
return false;
}
}

@Override
public int getScrollableUnitIncrement(Rectangle visibleRect,
int orientation, int direction) {
JComponent view = layer.getView();
if (view instanceof Scrollable) {
return ((Scrollable) view).getScrollableBlockIncrement(
visibleRect, orientation, direction);
} else {
return 1;
}
}

}
[/code]

But you might of source implement Scrollable in JXLayer itself.

Thanks,

Piet