|
Replies:
10
-
Last Post:
Nov 1, 2008 11:46 PM
by: alexfromsun
|
Threads:
[
Previous
|
Next
]
|
|
|
|
|
|
Multiple layers on one component
Posted:
Oct 24, 2008 1:11 AM
|
|
|
hello,
I want to write two LayerUIs, each one with a specific behavior, and then applied them on the same component. This solution : http://www.pbjar.org/blogs/jxlayer/JXLayer_one.html does not work in my case because it remove the generic and the second layer is not applied on the component but on the first layer.
I have wrote this class which seem to work, but you have to extend CompoundLayerUI.AbstractLayerUI instead of AbstractLayerUI for the "sub-layer". Also super.paintLayer(...) should not be called on the "sub-layer" (since it's already done in CompoundLayerUI).
The question is : is there a better way of doing this ?
package ilist.ui.generic;
import java.awt.Graphics2D;
import java.awt.event.FocusEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import javax.swing.JComponent;
import org.jdesktop.jxlayer.JXLayer;
import org.jdesktop.jxlayer.plaf.AbstractLayerUI;
public class CompoundLayerUI<V extends JComponent> extends AbstractLayerUI<V> {
private AbstractLayerUI<V> layer1;
private AbstractLayerUI<V> layer2;
public CompoundLayerUI(AbstractLayerUI<V> layer1, AbstractLayerUI<V> layer2) {
super();
this.layer1 = layer1;
this.layer2 = layer2;
}
@Override
protected void paintLayer(Graphics2D g, JXLayer<V> l) {
super.paintLayer(g, l);
this.layer1.paintLayer(g, l);
this.layer2.paintLayer(g, l);
}
@Override
protected void processFocusEvent(FocusEvent e, JXLayer<V> l) {
super.processFocusEvent(e, l);
this.layer1.eventDispatched(e, l);
this.layer2.eventDispatched(e, l);
}
@Override
protected void processKeyEvent(KeyEvent e, JXLayer<V> l) {
super.processKeyEvent(e, l);
this.layer1.eventDispatched(e, l);
this.layer2.eventDispatched(e, l);
}
@Override
protected void processMouseEvent(MouseEvent e, JXLayer<V> l) {
super.processMouseEvent(e, l);
this.layer1.eventDispatched(e, l);
this.layer2.eventDispatched(e, l);
}
@Override
protected void processMouseMotionEvent(MouseEvent e, JXLayer<V> l) {
super.processMouseMotionEvent(e, l);
this.layer1.eventDispatched(e, l);
this.layer2.eventDispatched(e, l);
}
@Override
protected void processMouseWheelEvent(MouseWheelEvent e, JXLayer<V> l) {
super.processMouseWheelEvent(e, l);
this.layer1.eventDispatched(e, l);
this.layer2.eventDispatched(e, l);
}
public static class AbstractLayerUI<T extends JComponent> extends org.jdesktop.jxlayer.plaf.AbstractLayerUI<T> {
// paintLayer is now public :
@Override
public void paintLayer(Graphics2D g, JXLayer<T> l) {
super.paintLayer(g, l);
}
}
}
How to use it :
JXLayer<JList> myLayer = new JXLayer<JList>(myList);
CompoundLayerUI<JList> compoundLayerUI = new CompoundLayerUI<JList>(layerUI1, layerUI2);
myLayer.setUI(compoundLayerUI);
JScrollPane scrollPane = new JScrollPane(myLayer);
|
|
|
|
|
|
|
Re: Multiple layers on one component
Posted:
Oct 24, 2008 2:38 AM
in response to: lebesnec
|
|
|
Hi Lebesnec,
I don't understand exactly what you mean by:
This solution : http://www.pbjar.org/blogs/jxlayer/JXLayer_one.html does not work in my case because it remove the generic and the second layer is not applied on the component but on the first layer.
Could you provide some code example that shows what goes wrong?
Your code looks somewhat familiar to me, because I also made some attempt to write a generic MultiLayerUI. I failed because for virtually all methods I had to decide to either do the processing in the MultiLayerUI or delegate to the child LayerUIs. For me, that was very problematic.
Just as a hint. It seems that you implement your own AbstractLayerUI, extending from the original AbstractLayerUI. Your naming is very confusing. Shouldn't you name your class differently? Something like PublicPaintAbstractLayerUI?
Piet
|
|
|
|
|
|
|
|
Re: Multiple layers on one component
Posted:
Oct 24, 2008 2:44 AM
in response to: pietblok
|
|
|
Update : this work even better :
package ilist.ui.generic;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.FocusEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import javax.swing.JComponent;
import org.jdesktop.jxlayer.JXLayer;
import org.jdesktop.jxlayer.plaf.AbstractLayerUI;
public class CompoundLayerUI<V extends JComponent> extends AbstractLayerUI<V> {
private AbstractLayerUI<V> layer1;
private AbstractLayerUI<V> layer2;
public CompoundLayerUI(AbstractLayerUI<V> layer1, AbstractLayerUI<V> layer2) {
super();
this.layer1 = layer1;
this.layer1.setCompoundLayer(this);
this.layer2 = layer2;
this.layer2.setCompoundLayer(this);
}
@Override
protected void paintLayer(Graphics2D g, JXLayer<V> l) {
super.paintLayer(g, l);
this.layer1.paintLayer(g, l);
this.layer2.paintLayer(g, l);
}
@Override
protected void processFocusEvent(FocusEvent e, JXLayer<V> l) {
super.processFocusEvent(e, l);
this.layer1.eventDispatched(e, l);
this.layer2.eventDispatched(e, l);
}
@Override
protected void processKeyEvent(KeyEvent e, JXLayer<V> l) {
super.processKeyEvent(e, l);
this.layer1.eventDispatched(e, l);
this.layer2.eventDispatched(e, l);
}
@Override
protected void processMouseEvent(MouseEvent e, JXLayer<V> l) {
super.processMouseEvent(e, l);
this.layer1.eventDispatched(e, l);
this.layer2.eventDispatched(e, l);
}
@Override
protected void processMouseMotionEvent(MouseEvent e, JXLayer<V> l) {
super.processMouseMotionEvent(e, l);
this.layer1.eventDispatched(e, l);
this.layer2.eventDispatched(e, l);
}
@Override
protected void processMouseWheelEvent(MouseWheelEvent e, JXLayer<V> l) {
super.processMouseWheelEvent(e, l);
this.layer1.eventDispatched(e, l);
this.layer2.eventDispatched(e, l);
}
@Override
public Dimension getPreferredScrollableViewportSize(JXLayer<V> l) {
return layer1.getPreferredScrollableViewportSize(l);
}
@Override
public int getScrollableBlockIncrement(JXLayer<V> l, Rectangle r, int orientation, int direction) {
return layer1.getScrollableBlockIncrement(l, r, orientation, direction);
}
@Override
public boolean getScrollableTracksViewportHeight(JXLayer<V> l) {
return layer1.getScrollableTracksViewportHeight(l);
}
@Override
public boolean getScrollableTracksViewportWidth(JXLayer<V> l) {
return layer1.getScrollableTracksViewportWidth(l);
}
@Override
public int getScrollableUnitIncrement(JXLayer<V> l, Rectangle r,int orientation, int direction) {
return layer1.getScrollableUnitIncrement(l, r, orientation, direction);
}
public static class AbstractLayerUI<T extends JComponent> extends org.jdesktop.jxlayer.plaf.AbstractLayerUI<T> {
private CompoundLayerUI compoundLayerUI;
// paintLayer is now public :
@Override
public void paintLayer(Graphics2D g, JXLayer<T> l) {
super.paintLayer(g, l);
}
protected void setCompoundLayer(CompoundLayerUI compoundLayerUI) {
this.compoundLayerUI = compoundLayerUI;
}
@Override
protected void setDirty(boolean dirty) {
super.setDirty(dirty);
this.compoundLayerUI.setDirty(dirty);
}
}
}
|
|
|
|
|
|
|
|
Re: Multiple layers on one component
Posted:
Oct 24, 2008 3:07 AM
in response to: pietblok
|
|
|
hello Piet,
in fact the problem is not that the solution at http://www.pbjar.org/blogs/jxlayer/JXLayer_one.html does not work, it is that I can't use it ...
For example let say I want to use 2 layers on a JList. If I used this solution the second layers will be on a JXlayer instead of a JList, and I won't be able to do :
public void paintLayer(Graphics2D g, JXLayer<JList> layer) {
layer.getView().getSelectedIndex(); // getSelectedIndex is a method of JList
....
}
Just as a hint. It seems that you implement your own AbstractLayerUI, extending from the original AbstractLayerUI. Your naming is very confusing. Shouldn't you name your class differently? Something like PublicPaintAbstractLayerUI?
I keep the same name because I wanted it to be as invisible as possible for the users of CompoundLayerUI, but may be this too confusing
|
|
|
|
|
|
|
|
Re: Multiple layers on one component
Posted:
Oct 24, 2008 3:18 AM
in response to: lebesnec
|
|
|
another small change :
I have changed :
// paintLayer is now public :
@Override
public void paintLayer(Graphics2D g, JXLayer<T> l) {
super.paintLayer(g, l);
}
into :
// paintLayer is now public :
@Override
public void paintLayer(Graphics2D g, JXLayer<T> l) {}
So it will work even if in the sub-layers you forget to remove the call to super.paintLayer(...)
|
|
|
|
|
|
|
|
Re: Multiple layers on one component
Posted:
Oct 24, 2008 3:59 AM
in response to: lebesnec
|
|
|
I see.
In that case, define the outer JXLayer as follows:
JXLayer<JXLayer<JList>> outerLayer;
then you get at the index as follows:
public void paintLayer(Graphics2D g, JXLayer<JXLayer<JList>> layer) {
layer.getView().getView().getSelectedIndex(); // getSelectedIndex is a method of JList
....
}
Piet
|
|
|
|
|
|
|
|
Re: Multiple layers on one component
Posted:
Oct 24, 2008 5:03 AM
in response to: pietblok
|
|
|
Or something like this (to keep it more transparent)
import java.awt.Graphics2D;
import javax.swing.JComponent;
import javax.swing.JList;
import org.jdesktop.jxlayer.JXLayer;
import org.jdesktop.jxlayer.plaf.AbstractLayerUI;
public class JListLayerUI extends AbstractLayerUI<JComponent> {
@Override
protected void paintLayer(Graphics2D g2, JXLayer<JComponent> layer) {
super.paintLayer(g2, layer);
JComponent view = layer.getView();
while (!(view instanceof JList)) {
if (view instanceof JXLayer) {
view = ((JXLayer<?>) view).getView();
} else if (view == null) {
break;
} else {
throw new RuntimeException("Unexpected view encountered");
}
}
if (view != null) {
JList list = (JList) view;
int selectedIndex = list.getSelectedIndex();
// etc.
}
}
}
Not tested
Piet
|
|
|
|
|
|
|
|
Re: Multiple layers on one component
Posted:
Oct 24, 2008 7:53 PM
in response to: pietblok
|
|
|
I suppose the api should be extended to add multiple layers , maybe having a LayeredUIContainer whose layout supports adding multiple layers
|
|
|
|
|
|
|
|
Re: Multiple layers on one component
Posted:
Oct 29, 2008 2:59 AM
in response to: psychostud
|
|
|
Hi,
That's what I initially thought also. For a second time I tried to wite a MultiLayerUI (probably it will have many flaws, but it serves as a demo).
I found the results very disapponting, but now I think I understand why this never will work.
Imagine two or three LayerUI's that all do some customized painting.
1) Paints curves following the mouse 2) Paints dots where the mouse is clicked 3) Some magnifying glass
When applying those LayerUI's upon wrapped JXLayer's, they work so to speak recursive:
A) LayerUI 3 will, by invoking super.paintLayer(..) have LayerUI 2 do its work B) Then LayerUI 2 will, by invoking super.paintLayer(..) have LayerUI 1 do its work C) Then LayerUI1 will, by invoking super.paintLayer(..) have the view component be painted D) LayerUI 1 paints its curves E) LayerUI 2 paints its dots F) LayerUI 3 paints it magnifying glass
Now we see on the screen the views painting and the paintings of the three LayerUI's.
Now try this with a MultiLayerUI (use the code below for the implementation)
You will see that all LayerUI's will erase the painting of their peers, leaving the painting of thelast one only.
You may vary this experiment by commenting out the invocation of super.paintLayer(..) in the MultiLayerUI and/or in LayerUI 1, 2 and 3.
You will see that acting of those LayerUI's as peers, instead of a wrapped hierarchy, is the problematic part.
Well, this was just my experiment. I am very curious if anyone can setup some implementation of some multi LayerUI where the LayerUI's work in harmony together.
import java.awt.AWTEvent;
import java.awt.Graphics;
import java.util.LinkedHashSet;
import javax.swing.JComponent;
import org.jdesktop.jxlayer.JXLayer;
import org.jdesktop.jxlayer.plaf.AbstractLayerUI;
import org.jdesktop.jxlayer.plaf.LayerUI;
import org.jdesktop.jxlayer.plaf.item.LayerItemChangeEvent;
import org.jdesktop.jxlayer.plaf.item.LayerItemListener;
public class MultiLayerUI<V extends JComponent> extends AbstractLayerUI<V> {
private LayerItemListener layerItemListener = new LayerItemListener() {
@SuppressWarnings("unchecked")
@Override
public void layerItemChanged(LayerItemChangeEvent event) {
/*
* Getting the originating LayerUI. But what to do with it?
*/
@SuppressWarnings("unused")
LayerUI<V> layerUI = (LayerUI<V>) event.getSource();
/*
* When a child LayerUI is changed, then this LayerUI is changed as
* well.
*/
MultiLayerUI.this.fireLayerItemChanged();
}
};
private LinkedHashSet<LayerUI<V>> uis = new LinkedHashSet<LayerUI<V>>();
public void addLayerUI(LayerUI<V> layerUI) {
layerUI.addLayerItemListener(layerItemListener);
uis.add(layerUI);
}
@Override
public void eventDispatched(AWTEvent e, JXLayer<V> layer) {
for (LayerUI<V> layerUI : this.getLayerUIs()) {
if (layerUI.isEnabled()) {
layerUI.eventDispatched(e, layer);
}
}
}
@SuppressWarnings("unchecked")
public LayerUI<V>[] getLayerUIs() {
return (LayerUI<V>[]) uis.toArray(new LayerUI<?>[uis.size()]);
}
@Override
public void installUI(JComponent c) {
super.installUI(c);
for (LayerUI<V> layerUI : this.getLayerUIs()) {
layerUI.installUI(c);
}
}
@Override
public void paint(Graphics g, JComponent component) {
super.paint(g, component);
for (LayerUI<V> layerUI : this.getLayerUIs()) {
if (layerUI.isEnabled()) {
layerUI.paint(g.create(), component);
}
}
}
public void removeAllLayerUIs() {
for (LayerUI<V> layerUI : getLayerUIs()) {
removeLayerUI(layerUI);
}
uis.clear();
}
public void removeLayerUI(LayerUI<V> layerUI) {
layerUI.removeLayerItemListener(layerItemListener);
uis.remove(layerUI);
}
@Override
public void uninstallUI(JComponent c) {
super.uninstallUI(c);
for (LayerUI<V> layerUI : this.getLayerUIs()) {
layerUI.uninstallUI(c);
}
}
}
Piet
|
|
|
|
|
|
|
|
Re: Multiple layers on one component
Posted:
Nov 1, 2008 11:46 PM
in response to: pietblok
|
|
|
(Writing from Bangkok, at the end of vacation)
Hello Piet
I like your evaluation about MultiLayerUI I also believe that it can never be implemented correctly
the ui ordering is another problem, (adding one more ui on top of the others or in between of them) it can also be solved by prioritizing the ui's but it makes the result API not easy to use and maintain
I remember the experiment with MultiplePainter implementation from SwingX team it made me decide to not follow this way (don't tell Richard about that :-))
Thanks alexp
|
|
|
|
|
|
|
|
Re: Multiple layers on one component
Posted:
Oct 27, 2008 1:30 AM
in response to: pietblok
|
|
|
yes, both methods seem correct !
|
|
|
|
|