Skip to main content

JXLayer, PBTransform and Context Menus

7 replies [Last post]
smseland
Offline
Joined: 2009-10-05
Points: 0

Hi,
I really appreciate the combination of JXLayer and PBTransform. It saved me at least a week of work, but still one problem remains. I'm not quite sure if it is solvable at all, but perhaps anyone had come across it and has a solution.
The application panel, which is zoomed using Piet's TransformUI, supports context menus. Everything is fine when the event passes down to the component, which pop's up the menu then. But then this component resolves the absolute screen position using its internal dimension, so that the menu pops up far away from the mouse cursor, mostly even out of the window. Did I overlook something or is it simply impossible to have context menus?

Greetings,
Sebastian

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
jackta101
Offline
Joined: 2009-09-01
Points: 0

I'm also struggling with a similar problem with a combination of JXLayer and PBTransform, the JPopupMenu does not appear at the end of the mouse cursor when the panel is zoomed.

I do not know (and have tried a great number of different things to do so) how to get the menu to display correctly. The co-ordinates coming from the event are correct, and appear to have been transformed, but the popup menu needs to be displayed within a component space, and I have tried the source component, the JXLayer, the JXLayer view and none of them place the popup menu correctly.

[code]
package Zoom;

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;

import org.jdesktop.jxlayer.JXLayer;
import org.pbjar.jxlayer.demo.QualityHints;
import org.pbjar.jxlayer.demo.TransformUtils;
import org.pbjar.jxlayer.plaf.ext.TransformUI;
import org.pbjar.jxlayer.plaf.ext.transform.DefaultTransformModel;

public class Application {

public static void main(String[] args){
new Application();
}

JXLayer layer;
double zoomVar = 0.5;

public Application(){
final JFrame window = new JFrame("Zoom Test");
window.setSize(new Dimension(400,400));
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JPanel content = new JPanel();

layer = TransformUtils.createTransformJXLayer(createContent(), 1,
new QualityHints());
content.add(layer);

JPanel control = new JPanel();
JButton zoomIn = new JButton("Zoom In");
zoomIn.addActionListener(new ActionListener(){

@Override
public void actionPerformed(ActionEvent arg0) {
TransformUI ui = (TransformUI) layer.getUI();
DefaultTransformModel old = (DefaultTransformModel) ui.getModel();
old.setScale(old.getScale()+zoomVar);
layer.validate();
window.validate();
}

});
control.add(zoomIn);

JButton zoomOut = new JButton("Zoom Out");
zoomOut.addActionListener(new ActionListener(){

@Override
public void actionPerformed(ActionEvent arg0) {
TransformUI ui = (TransformUI) layer.getUI();
DefaultTransformModel old = (DefaultTransformModel) ui.getModel();
old.setScale(old.getScale()-zoomVar);
layer.validate();
window.validate();
}

});
control.add(zoomOut);

content.add(control);
window.add(content);
window.setVisible(true);
}

private JComponent createContent(){
final JPanel testPanel = new JPanel();
testPanel.add(new JButton("Test Button"));
testPanel.add(new JButton("Test Button 2"));

final JPopupMenu rMenu = new JPopupMenu();
rMenu.add(new JMenuItem("Test"));

testPanel.addMouseListener(new MouseAdapter(){
public void mouseReleased(MouseEvent event){
if (event.isPopupTrigger()){
rMenu.show(event.getComponent(), event.getX(), event.getY());
}
}
});

return testPanel;
}
}
[/code]

Any suggestions would be great? I have been trying for hours to try and get something to work and I've tried absolutely everything I can think of.

Jack

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

Hi Jack,

You may change your mouseReleased method as follows:

[code]
public void mouseReleased(MouseEvent event) {
if (event.isPopupTrigger()) {
Point point = event.getPoint();
point = SwingUtilities.convertPoint(event.getComponent(),
point, layer);
TransformUI ui = (TransformUI) layer.getUI();
DefaultTransformModel model = (DefaultTransformModel) ui
.getModel();
java.awt.geom.AffineTransform at = model.getTransform(layer);
at.transform(point, point);
rMenu.show(layer, point.x, point.y);
}
[/code]

First, recalculate the event point to a point in the JXLayer itself. Now you can transform it, using the AffineTransform from the model, and finally specify the JXLayer as the anchor component.

Thanks,

Piet

gorbachev
Offline
Joined: 2010-12-16
Points: 0

I've got a related issue.
I'm implementing JXLayer with TransformUI on an application that uses a lot of third party UI components (closed source, obfuscated class files).
Context menus opened by the third party UI components are showing up on wrong locations, and the above solution obviously isn't going to cut it.
Anyone else run into this issue, and if so, were you able to solve it?

snoopygee
Offline
Joined: 2010-01-13
Points: 0

Hi Piet (and all),
Using the example above I have tried to extend the concept by also transforming the popup size to be the same as the zoomed buttons. I've found by wrapping each of the components added to the JPopupMenu with a JXLayer and applying the same scaling from the parent panel the combo box items also rescale, as:
<code>
package org.pbjar.jxlayer.test;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;
import org.jdesktop.jxlayer.JXLayer;
import org.pbjar.jxlayer.JXLayerFactory;
import org.pbjar.jxlayer.JXLayerManager;
import org.pbjar.jxlayer.demo.QualityHints;
import org.pbjar.jxlayer.demo.TransformUtils;
import org.pbjar.jxlayer.plaf.ext.TransformUI;
import org.pbjar.jxlayer.plaf.ext.transform.DefaultTransformModel;
public class Application {
public static void main(String[] args) {
new Application();
}
private JPopupMenu rMenu = new JPopupMenu();
JXLayer layer;
double zoomVar = 0.5;
public Application() {
final JFrame window = new JFrame("Zoom Test"); //$NON-NLS-1$
window.setSize(new Dimension(400, 400));
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel content = new JPanel();
layer = TransformUtils.createTransformJXLayer(createContent(), 1, new QualityHints());
content.add(layer);
JPanel control = new JPanel();
JButton zoomIn = new JButton("Zoom In"); //$NON-NLS-1$
zoomIn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
TransformUI ui = (TransformUI) layer.getUI();
DefaultTransformModel old = (DefaultTransformModel) ui.getModel();
old.setScale(old.getScale() + zoomVar);
layer.validate();
window.validate();
}
});
control.add(zoomIn);
JButton zoomOut = new JButton("Zoom Out"); //$NON-NLS-1$
zoomOut.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
TransformUI ui = (TransformUI) layer.getUI();
DefaultTransformModel old = (DefaultTransformModel) ui.getModel();
old.setScale(old.getScale() - zoomVar);
layer.validate();
window.validate();
}
});
control.add(zoomOut);
content.add(control);
window.add(content);
window.setVisible(true);
}
private JComponent createContent() {
final JPanel testPanel = new JPanel();
testPanel.setBackground( Color.RED );
testPanel.add(new JButton("Test Button")); //$NON-NLS-1$
testPanel.add(new JButton("Test Button 2")); //$NON-NLS-1$

testPanel.addMouseListener(new MouseAdapter() {

public void mousePressed(MouseEvent e) {
rMenu.removeAll();
JXLayer<?> thePopupLayer = createTransformChild( layer, new JMenuItem("Test Combo item") ); //$NON-NLS-1$
rMenu.add( thePopupLayer );
}

public void mouseReleased(MouseEvent event) {
if (event.isPopupTrigger()) {
Point point = event.getPoint();
point = SwingUtilities.convertPoint(event.getComponent(), point, layer);
AffineTransform at = JXLayerManager.getJXLayerAffineTransform( layer );
at.transform(point, point);
rMenu.show(layer, point.x, point.y);
}
}
});
return testPanel;
}

private JXLayer createTransformChild( JXLayer parentJXLayer, JComponent component ){
DefaultTransformModel parentModel = (DefaultTransformModel)((TransformUI) parentJXLayer.getUI()).getModel();
AffineTransform parentTransform = parentModel.getTransform(parentJXLayer);
return createTransformChild( parentTransform, component );
}

private JXLayer createTransformChild( AffineTransform parentTransform, JComponent component ){
DefaultTransformModel newModel = new DefaultTransformModel();
newModel.setScale((parentTransform.getScaleX() + parentTransform.getScaleY()) / 2.0);
return TransformUtils.createTransformJXLayer(component,newModel, new QualityHints());
}
}
</code>
I have a strange side effect using this technique however as when I now try to select the items within the popup, for some reason the popup seems to loose focus and disappear.
Can you suggest a solution to this problem. Perhaps an alternative technique?
Thanks
Snoopygee

snoopygee
Offline
Joined: 2010-01-13
Points: 0

Hi All,
Following on from this post, I have now spent some time to work out why the menu items are not selectable once scaled by a JXLayer. I have found it has nothing to do with the JXLayer, the problem lies with the standard Swing classes. Therefore to summarise I now have a solution for scaling Menu's and there subitems using the technique above and the solution detailed below.
I created a small application which demonstrates the problem and it's solution here: http://www.java.net/external?url=http://www.java-forums.org/awt-swing/36...
I have simplified this solution (within the above link) by not including a JXLayer but the complete solution would be the same, within the MyMenuItemUI.getPath() method to take account of the JXLayer wrapping the JMenuItems and return the correct path to these Menu Items.
Thanks.

werterzui
Offline
Joined: 2010-09-12
Points: 0

Just had a similar problem, this solution works great, thank you very much.

snoopygee
Offline
Joined: 2010-01-13
Points: 0

Hi All,
Anyone have any idea's regarding my posting above?
Thanks