映射鼠标事件坐标
Mapping mouse event coordinates
我已经实现了一个 JLayer<JPanel>
组件,它绘制了一个缩放的 Graphics
自身,因此他所有的下降组件也将被缩放。
此 JLayer 作为 ContentPane 应用于 JFrame 组件。
主要问题是所有缩放实际上只适用于图形,组件的实际大小和位置保持不变。这意味着所有的鼠标事件都发生在用户看到的错误位置。
我对它进行了调整,在框架的顶部定义了一个 GlassPane
JComponent
,它有自己的 MouseInputAdapter
,它将 MouseEvent
重新发送到使用 SwingUtilities.getDeepestComponentAt()
的底层组件。这是通过创建一个新的 MouseEvent
并根据缩放值映射鼠标坐标来实现的。 (修改How to use RootPanes教程获得)
这种方法显然不能令人满意,因为很多事件根本无法触发(例如 MOUSE_ENTERED
所有下降组件触发的事件)。
另一方面,使用 LayerUI.paint()
覆盖意味着我必须拥有重新映射所有鼠标坐标的东西。
有没有办法在不破坏内部 MouseEvent
处理的情况下映射鼠标坐标?
或
有没有另一种方法可以放大组件的位图,同时修改实际位置和大小?我试过这个但是调用内部组件的 setSize()
似乎以某种方式第二次调用 LayerUi.paint()
所以我得到的只是一些与实际小部件位置断开连接的更大的图形
这是我到目前为止所做的,感谢 MadProgrammer 和 PBar 扩展,在 java 8.
中使用 JLayer
TransformUI
本身包括 PBar 的 org.pbjar.jxlayer.plaf.ext.MouseEventUI
和 org.pbjar.jxlayer.plaf.ext.TransformUI
:
package jzoom.transform;
import java.awt.AWTEvent;
import java.awt.Component;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;
import java.util.HashSet;
import java.util.Set;
import javax.swing.JComponent;
import javax.swing.JLayer;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.plaf.LayerUI;
/**
*
* This UI apply an {@link AffineTransform} to all the visible objects, and apply the inversion
* of the same transform to all the mouse event's coordinates
*
* @author Andrea.Maracci based on the pbjar JXLayer extension
*
*/
public class TransformUI extends LayerUI<JComponent> {
private static final long serialVersionUID = 1L;
private Component lastEnteredTarget, lastPressedTarget;
private final Set<JComponent> originalDoubleBuffered = new HashSet<JComponent>();
private AffineTransform transform = new AffineTransform();
private JLayer<JComponent> installedLayer;
private boolean dispatchingMode = false;
/**
* Process the mouse events and map the mouse coordinates inverting the internal affine transformation.
*
* @param
* event the event to be dispatched
* layer the layer this LayerUI is set to
*
*/
@Override
public void eventDispatched(AWTEvent event, final JLayer<? extends JComponent> layer) {
if (event instanceof MouseEvent) {
MouseEvent mouseEvent = (MouseEvent) event;
/*
* The if discriminate between generated and original event.
* Removing it cause a stack overflow caused by the event being redispatched to this class.
*/
if (!dispatchingMode) {
// Process an original mouse event
dispatchingMode = true;
try {
redispatchMouseEvent(mouseEvent, layer);
} finally {
dispatchingMode = false;
}
} else {
/*
* Process generated mouse events
* Added a check, because on mouse entered or exited, the cursor
* may be set to specific dragging cursors.
*/
if (MouseEvent.MOUSE_ENTERED == mouseEvent.getID() || MouseEvent.MOUSE_EXITED == mouseEvent.getID()) {
layer.getGlassPane().setCursor(null);
} else {
Component component = mouseEvent.getComponent();
layer.getGlassPane().setCursor(component.getCursor());
}
}
} else {
super.eventDispatched(event, layer);
}
layer.repaint();
}
/**
* Set the affine transformation applied to the graphics
* @param transform the transformation
*/
public void setTransform(AffineTransform transform) {
if (transform != null) {
this.transform = transform;
}
}
/**
* Return the affine transformation applied to the graphics
* @return the transformation
*/
public AffineTransform getTransform() {
return transform;
}
/**
* Paint the specified component {@code c} applying the transformation on it's graphic
*
* @param
* g - the Graphics context in which to paint
* c - the component being painted
*/
@Override
public void paint(Graphics g, JComponent c) {
if (g instanceof Graphics2D) {
Graphics2D g2 = (Graphics2D) g.create();
JLayer<? extends JComponent> l = (JLayer<? extends JComponent>) c;
g2.transform(transform);
paintLayer(g2, l);
g2.dispose();
}
}
/**
* Paint the view decorated by the JLayer {@code layer} and the JLayer itself
*
* @param g2
* @param layer the layer this LayerUI is set to
*/
private final void paintLayer(Graphics2D g2, JLayer<? extends JComponent> layer) {
JComponent view = layer.getView();
if (view != null) {
if (view.getX() < 0 || view.getY() < 0) {
setToNoDoubleBuffering(view);
g2.translate(view.getX(), view.getY());
view.paint(g2);
for (JComponent jComp : originalDoubleBuffered) {
jComp.setDoubleBuffered(true);
}
originalDoubleBuffered.clear();
return;
}
}
layer.paint(g2);
}
/**
* Disable the double buffering for the {@code component} and for all of it's children
*
* @param component
*/
private void setToNoDoubleBuffering(Component component) {
if (component instanceof JComponent) {
JComponent jComp = (JComponent) component;
if (jComp.isDoubleBuffered()) {
originalDoubleBuffered.add(jComp);
jComp.setDoubleBuffered(false);
}
}
if (component instanceof Container) {
Container container = (Container) component;
for (int index = 0; index < container.getComponentCount(); index++) {
setToNoDoubleBuffering(container.getComponent(index));
}
}
}
/**
* {@inheritDoc}
*/
@Override
public void uninstallUI(JComponent component) {
if (!(component instanceof JLayer<?>)) {
throw new IllegalArgumentException(
this.getClass().getName() + " invalid class, must be a JLayer component");
}
JLayer<JComponent> jlayer = (JLayer<JComponent>) component;
jlayer.setLayerEventMask(0);
super.uninstallUI(component);
}
/**
* {@inheritDoc}
*/
@Override
public void installUI(JComponent component) throws IllegalStateException {
super.installUI(component);
if (installedLayer != null) {
throw new IllegalStateException(this.getClass().getName() + " cannot be shared between multiple layers");
}
if (!(component instanceof JLayer<?>)) {
throw new IllegalArgumentException(
this.getClass().getName() + " invalid class, must be a JLayer component");
}
// component.getClass().getDeclaringClass();
installedLayer = (JLayer<JComponent>) component;
installedLayer.setLayerEventMask(AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK
| AWTEvent.MOUSE_WHEEL_EVENT_MASK | AWTEvent.KEY_EVENT_MASK | AWTEvent.FOCUS_EVENT_MASK);
}
/**
* Process the mouse events and map the mouse coordinates inverting the internal affine transformation.
* It consume the original event, calculates the mapped mouse coordinates and find the real target of the mouse event.
* It than create a new event with the correct informations in it and redispatch it to the target event
*
* @param originalEvent the event to be dispatched
* @param layer the layer this LayerUI is set to
*/
private void redispatchMouseEvent(MouseEvent originalEvent, JLayer<? extends JComponent> layer) {
if (layer.getView() != null) {
if (originalEvent.getComponent() != layer.getGlassPane()) {
originalEvent.consume();
}
MouseEvent newEvent = null;
Point realPoint = calculateTargetPoint(layer, originalEvent);
Component realTarget = getTarget(layer, realPoint);
// Component realTarget =
// SwingUtilities.getDeepestComponentAt(layer.getView(),
// realPoint.x, realPoint.y);
if (realTarget != null) {
//System.out.println(realTarget.getClass().getName());
realTarget = getListeningComponent(originalEvent, realTarget);
}
switch (originalEvent.getID()) {
case MouseEvent.MOUSE_PRESSED:
newEvent = transformMouseEvent(layer, originalEvent, realTarget, realPoint);
if (newEvent != null) {
lastPressedTarget = newEvent.getComponent();
}
break;
case MouseEvent.MOUSE_RELEASED:
newEvent = transformMouseEvent(layer, originalEvent, lastPressedTarget, realPoint);
lastPressedTarget = null;
break;
case MouseEvent.MOUSE_CLICKED:
newEvent = transformMouseEvent(layer, originalEvent, realTarget, realPoint);
lastPressedTarget = null;
break;
case MouseEvent.MOUSE_MOVED:
newEvent = transformMouseEvent(layer, originalEvent, realTarget, realPoint);
generateEnterExitEvents(layer, originalEvent, realTarget, realPoint);
break;
case MouseEvent.MOUSE_ENTERED:
generateEnterExitEvents(layer, originalEvent, realTarget, realPoint);
break;
case MouseEvent.MOUSE_EXITED:
generateEnterExitEvents(layer, originalEvent, realTarget, realPoint);
break;
case MouseEvent.MOUSE_DRAGGED:
newEvent = transformMouseEvent(layer, originalEvent, lastPressedTarget, realPoint);
generateEnterExitEvents(layer, originalEvent, realTarget, realPoint);
break;
case (MouseEvent.MOUSE_WHEEL):
// redispatchMouseWheelEvent((MouseWheelEvent) originalEvent,
// realTarget, realPoint);
newEvent = transformMouseWheelEvent(layer, (MouseWheelEvent) originalEvent, realTarget, realPoint);
break;/**/
}
dispatchMouseEvent(newEvent);
}
}
/**
* Apply the inverse transformation to {@code point}
*
* @param layer the layer this LayerUI is set to
* @param point the starting point
* @return the transformed point
*/
private Point transformPoint(JLayer<? extends JComponent> layer, Point point) {
if (transform != null) {
try {
transform.inverseTransform(point, point);
} catch (NoninvertibleTransformException e) {
e.printStackTrace();
}
}
return point;
}
/**
* Find the deepest component in the AWT hierarchy
*
* @param layer the layer to which this UI is installed
* @param targetPoint the point in layer's coordinates
* @return the component in the specified point
*/
private Component getTarget(JLayer<? extends JComponent> layer, Point targetPoint) {
Component view = layer.getView();
if (view == null) {
return null;
} else {
Point viewPoint = SwingUtilities.convertPoint(layer, targetPoint, view);
return SwingUtilities.getDeepestComponentAt(view, viewPoint.x, viewPoint.y);
}
}
/**
* Convert the {@code mouseEvent}'s coordinates to the {@code layer}'s space
* @param layer the layer this LayerUI is set to
* @param mouseEvent the original mouse event
* @return the {@code mouseEvent}'s point transformed to the {@code layer}'s coordinate space
*/
private Point calculateTargetPoint(JLayer<? extends JComponent> layer,
MouseEvent mouseEvent) {
Point point = mouseEvent.getPoint();
//SwingUtilities.convertPointToScreen(point, mouseEvent.getComponent());
//SwingUtilities.convertPointFromScreen(point, layer);
point = SwingUtilities.convertPoint(mouseEvent.getComponent(), point, layer);
return transformPoint(layer, point);
}
private MouseEvent transformMouseEvent(JLayer<? extends JComponent> layer, MouseEvent mouseEvent, Component target, Point realPoint) {
return transformMouseEvent( layer, mouseEvent, target, realPoint, mouseEvent.getID());
}
/**
* Create the new event to being dispatched
*/
private MouseEvent transformMouseEvent(JLayer<? extends JComponent> layer, MouseEvent mouseEvent, Component target, Point targetPoint, int id) {
if (target == null) {
return null;
} else {
Point newPoint = SwingUtilities.convertPoint(layer, targetPoint, target);
return new MouseEvent(target, //
id, //
mouseEvent.getWhen(), //
mouseEvent.getModifiers(), //
newPoint.x, //
newPoint.y, //
mouseEvent.getClickCount(), //
mouseEvent.isPopupTrigger(), //
mouseEvent.getButton());
}
}
/**
* Create the new mouse wheel event to being dispached
*/
private MouseWheelEvent transformMouseWheelEvent( JLayer<? extends JComponent> layer, MouseWheelEvent mouseWheelEvent, Component target,
Point targetPoint) {
if (target == null) {
return null;
} else {
Point newPoint = SwingUtilities.convertPoint(layer, targetPoint, target);
return new MouseWheelEvent(target, //
mouseWheelEvent.getID(), //
mouseWheelEvent.getWhen(), //
mouseWheelEvent.getModifiers(), //
newPoint.x, //
newPoint.y, //
mouseWheelEvent.getClickCount(), //
mouseWheelEvent.isPopupTrigger(), //
mouseWheelEvent.getScrollType(), //
mouseWheelEvent.getScrollAmount(), //
mouseWheelEvent.getWheelRotation() //
);
}
}
/**
* dispatch the {@code mouseEvent}
* @param mouseEvent the event to be dispatched
*/
private void dispatchMouseEvent(MouseEvent mouseEvent) {
if (mouseEvent != null) {
Component target = mouseEvent.getComponent();
target.dispatchEvent(mouseEvent);
}
}
/**
* Get the listening component associated to the {@code component}'s {@code event}
*/
private Component getListeningComponent(MouseEvent event, Component component) {
switch (event.getID()) {
case (MouseEvent.MOUSE_CLICKED):
case (MouseEvent.MOUSE_ENTERED):
case (MouseEvent.MOUSE_EXITED):
case (MouseEvent.MOUSE_PRESSED):
case (MouseEvent.MOUSE_RELEASED):
return getMouseListeningComponent(component);
case (MouseEvent.MOUSE_DRAGGED):
case (MouseEvent.MOUSE_MOVED):
return getMouseMotionListeningComponent(component);
case (MouseEvent.MOUSE_WHEEL):
return getMouseWheelListeningComponent(component);
}
return null;
}
/**
* Cycles through the {@code component}'s parents to find the {@link Component} with associated {@link MouseListener}
*/
private Component getMouseListeningComponent(Component component) {
if (component.getMouseListeners().length > 0) {
return component;
} else {
Container parent = component.getParent();
if (parent != null) {
return getMouseListeningComponent(parent);
} else {
return null;
}
}
}
/**
* Cycles through the {@code component}'s parents to find the {@link Component} with associated {@link MouseMotionListener}
*/
private Component getMouseMotionListeningComponent(Component component) {
/*
* Mouse motion events may result in MOUSE_ENTERED and MOUSE_EXITED.
*
* Therefore, components with MouseListeners registered should be
* returned as well.
*/
if (component.getMouseMotionListeners().length > 0 || component.getMouseListeners().length > 0) {
return component;
} else {
Container parent = component.getParent();
if (parent != null) {
return getMouseMotionListeningComponent(parent);
} else {
return null;
}
}
}
/**
* Cycles through the {@code component}'s parents to find the {@link Component} with associated {@link MouseWheelListener}
*/
private Component getMouseWheelListeningComponent(Component component) {
if (component.getMouseWheelListeners().length > 0) {
return component;
} else {
Container parent = component.getParent();
if (parent != null) {
return getMouseWheelListeningComponent(parent);
} else {
return null;
}
}
}
/**
* Generate a {@code MOUSE_ENTERED} and {@code MOUSE_EXITED} event when the target component is changed
*/
private void generateEnterExitEvents( JLayer<? extends JComponent> layer,MouseEvent originalEvent, Component newTarget, Point realPoint) {
if (lastEnteredTarget != newTarget) {
dispatchMouseEvent(
transformMouseEvent(layer, originalEvent, lastEnteredTarget, realPoint, MouseEvent.MOUSE_EXITED));
lastEnteredTarget = newTarget;
//System.out.println("Last " + lastEnteredTarget.getClass().getName());
dispatchMouseEvent(
transformMouseEvent(layer, originalEvent, lastEnteredTarget, realPoint, MouseEvent.MOUSE_ENTERED));
}
}
}
ZoomPanel
是一个 JPanel
,其中包含一个 JLayer
和一个 TransformUI
。 JLayer
包含一个 JPanel
和一个 SpringLayout
,其中使用比例因子更新约束以正确布局组件(JXLayer
有它自己的 LayoutManager
但在 JLayer
中你不能设置它)
package jzoom.transform;
import ...
public class ZoomPanel extends JPanel {
private static final long serialVersionUID = 1L;
private AffineTransform transform;
private TransformUI layerUI;
private JLayer<JComponent> layer;
private SpringLayout layout;
private JPanel springPanel;
private Container view = null;
public ZoomPanel() {
this(null);
}
public ZoomPanel(Container view) {
setLayout(new BorderLayout());
this.view = view;
transform = new AffineTransform();
layout = new SpringLayout();
springPanel = new JPanel(layout);
if (view != null) {
updateConstraints();
springPanel.add(view);
}
layerUI = new TransformUI();
layerUI.setTransform(transform);
layer = new JLayer<JComponent>(springPanel, layerUI);
super.add(layer);
}
private void updateConstraints() {
Spring width = layout.getConstraint(SpringLayout.WIDTH, springPanel);
Spring height = layout.getConstraint(SpringLayout.HEIGHT, springPanel);
SpringLayout.Constraints constraints = layout.getConstraints(view);
constraints.setX(Spring.constant(0));
constraints.setY(Spring.constant(0));
constraints.setWidth(Spring.scale(width, (float) (1 / transform.getScaleX())));
constraints.setHeight(Spring.scale(height, (float) (1 / transform.getScaleX())));
}
public void setView(Container view) {
if (this.view != null) {
throw new IllegalStateException(
this.getClass().getName() + " cannot be shared between multiple containers");
}
if (view != null) {
this.view = view;
updateConstraints();
springPanel.add(view);
} else {
throw new IllegalArgumentException("Can't set a null view");
}
}
public double getScale() {
return transform.getScaleX();
}
public void zoomIn() {
setScale(transform.getScaleX() + 0.1);
}
public void zoomOut() {
setScale(transform.getScaleX() - 0.1);
}
public void setScale(double scale) {
if (!(scale < 1)) {
transform.setToIdentity();
transform.scale(scale, scale);
updateConstraints();
springPanel.updateUI();
}
}
protected Component addToView(Component comp, Object constraints, int index) {
if (view != null) {
view.add(comp, constraints, index);
return comp;
}
if (comp instanceof Container) {
setView((Container) comp);
return view;
}
throw new IllegalStateException("You need to add or set a Container view before adding Components");
}
@Override
public Component add(Component comp) {
// TODO Auto-generated method stub
return addToView(comp, null, this.getComponentCount());
}
@Override
public Component add(Component comp, int index) {
// TODO Auto-generated method stub
return addToView(comp, null, index);
}
@Override
public void add(Component comp, Object constraints) {
// TODO Auto-generated method stub
addToView(comp, constraints, this.getComponentCount());
}
@Override
public void add(Component comp, Object constraints, int index) {
// TODO Auto-generated method stub
addToView(comp, constraints, index);
}
private void inspectView(Container view) {
PrintStream ps = null;
try {
ps = new PrintStream("C:\Users\andrea.maracci\Documents\sicraReflectionTemp.txt");
inspectView(view, 0, ps);
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (ps != null) {
ps.close();
}
}
}
private static void inspectView(Component component, Integer level, PrintStream ps) {
for (Integer i = 0; i < level; i++) {
ps.print("\t");
}
ps.print(level + ")");
ps.println("Inspecting " + component.getClass().getName());
int accessibleCount = 0;
if (component.getAccessibleContext() != null) {
accessibleCount = component.getAccessibleContext().getAccessibleChildrenCount();
if (accessibleCount > 0) {
ps.println("*********************************************ACCESSIBLE CONTEXT*********************************************");
for (int i = 0; i < accessibleCount; i++) {
ps.println(i + ") " + component.getAccessibleContext().getAccessibleChild(i).getClass().getName());
}
ps.println("************************************************************************************************************");
}
}
if (component instanceof JComponent) {
JComponent jComponent = ((JComponent)component);
if (jComponent.getComponentCount() > 0) {
Component[] children = jComponent.getComponents();
for (Component child : children) {
inspectView(child, ++level, ps);
}
}
}
--level;
}
}
这是一个可怕的测试程序
package jzoom.test;
import ...
public class TestFinal {
public static void main(String[] args) {
new TestFinal();
}
public TestFinal() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedLookAndFeelException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setMinimumSize(new Dimension(400,500));
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JLayer<JComponent> layer;
private TransformUI layerUI;
private JPanel content;
private AffineTransform transform = new AffineTransform();
private ZoomPanel zoomPanel;
public TestPane() {
content = new JPanel(new GridBagLayout());
// content = new JPanel(new XYLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridy = 0;
gbc.weighty = 0;
gbc.weightx = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
JLabel label = new JLabel("Hello");
JTextField field = new JTextField("World", 20);
content.add(label, gbc);
gbc.weightx = 1;
content.add(field, gbc);
// content.add(label, new XYConstraints(50, 20, 50, 22));
// content.add(field, new XYConstraints(100, 20, 200, 22));
gbc.gridy++;
gbc.gridwidth = 2;
final JSlider slider = new JSlider(100, 200);
slider.setValue(100);
slider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
int value = slider.getValue();
double scale = value / 100d;
zoomPanel.setScale(scale);
}
});
content.add(slider, gbc);
// content.add(slider, new XYConstraints(75, 50, 200, 50));
gbc.gridy++;
gbc.gridwidth = 2;
gbc.weighty = 1;
gbc.fill = GridBagConstraints.BOTH;
JTextArea textArea = new JTextArea();
textArea.setEditable(true);
textArea.setText(
"pollofritto\npalma\npalmipedone\ncaccoletta\namammata\na\nasd\nasdgfag\nasdafa\nasdfasf\nadsfasdf\nadfadsf\nadsfdasf\nasdfdas\npollofritto\npalma\npalmipedone\ncaccoletta\namammata\na\nasd\nasdgfag\nasdafa\nasdfasf\nadsfasdf\nadfadsf\nadsfdasf\nasdfdas");
// textArea.setPreferredSize(new Dimensions());
JScrollPane scrollPane = new JScrollPane(textArea);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.setPreferredSize(new Dimension(200, 75));
content.add(scrollPane, gbc);
gbc.gridy++;
gbc.gridwidth = 2;
gbc.weighty = 0;
gbc.weightx = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
String[] petStrings = { "Bird", "Cat", "Dog", "Rabbit", "Pig" };
JComboBox petList = new JComboBox(petStrings);
content.add(petList, gbc);
JButton zoomIn = new JButton("Zoom In");
// zoomIn.addMouseListener(new ZoomMouseListener());
zoomIn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// System.out.println("FIRST");
// layerUI.zoomIn();
//double zoom = transform.getScaleX();
//transform.setToIdentity();
//transform.scale(zoom + 0.1, zoom + 0.1);
zoomPanel.zoomIn();
// jLayer.repaint();
}
});
JButton zoomOut = new JButton("Zoom Out");
zoomOut.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
zoomPanel.zoomOut();
//double zoom = transform.getScaleX();
//transform.setToIdentity();
//transform.scale(zoom - 0.1, zoom - 0.1);
// jLayer.repaint();
}
});
gbc.gridy++;
gbc.gridx = 0;
gbc.gridwidth = 0;
gbc.anchor = GridBagConstraints.LINE_END;
// content.add(zoomOut, new XYConstraints(50, 120, 100, 25));
// content.add(zoomIn, new XYConstraints(170, 120, 100, 25));
JPanel button = new JPanel();
button.setLayout(new BoxLayout(button, BoxLayout.LINE_AXIS));
button.add(zoomOut);
button.add(zoomIn);
gbc.fill = GridBagConstraints.NONE;
content.add(button, gbc);
setLayout(new BorderLayout());
setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
zoomPanel = new ZoomPanel();
zoomPanel.setView(content);
add(zoomPanel);
}
}
}
我已经实现了一个 JLayer<JPanel>
组件,它绘制了一个缩放的 Graphics
自身,因此他所有的下降组件也将被缩放。
此 JLayer 作为 ContentPane 应用于 JFrame 组件。
主要问题是所有缩放实际上只适用于图形,组件的实际大小和位置保持不变。这意味着所有的鼠标事件都发生在用户看到的错误位置。
我对它进行了调整,在框架的顶部定义了一个 GlassPane
JComponent
,它有自己的 MouseInputAdapter
,它将 MouseEvent
重新发送到使用 SwingUtilities.getDeepestComponentAt()
的底层组件。这是通过创建一个新的 MouseEvent
并根据缩放值映射鼠标坐标来实现的。 (修改How to use RootPanes教程获得)
这种方法显然不能令人满意,因为很多事件根本无法触发(例如 MOUSE_ENTERED
所有下降组件触发的事件)。
另一方面,使用 LayerUI.paint()
覆盖意味着我必须拥有重新映射所有鼠标坐标的东西。
有没有办法在不破坏内部
MouseEvent
处理的情况下映射鼠标坐标?或
有没有另一种方法可以放大组件的位图,同时修改实际位置和大小?我试过这个但是调用内部组件的
setSize()
似乎以某种方式第二次调用LayerUi.paint()
所以我得到的只是一些与实际小部件位置断开连接的更大的图形
这是我到目前为止所做的,感谢 MadProgrammer 和 PBar 扩展,在 java 8.
中使用 JLayerTransformUI
本身包括 PBar 的 org.pbjar.jxlayer.plaf.ext.MouseEventUI
和 org.pbjar.jxlayer.plaf.ext.TransformUI
:
package jzoom.transform;
import java.awt.AWTEvent;
import java.awt.Component;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;
import java.util.HashSet;
import java.util.Set;
import javax.swing.JComponent;
import javax.swing.JLayer;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.plaf.LayerUI;
/**
*
* This UI apply an {@link AffineTransform} to all the visible objects, and apply the inversion
* of the same transform to all the mouse event's coordinates
*
* @author Andrea.Maracci based on the pbjar JXLayer extension
*
*/
public class TransformUI extends LayerUI<JComponent> {
private static final long serialVersionUID = 1L;
private Component lastEnteredTarget, lastPressedTarget;
private final Set<JComponent> originalDoubleBuffered = new HashSet<JComponent>();
private AffineTransform transform = new AffineTransform();
private JLayer<JComponent> installedLayer;
private boolean dispatchingMode = false;
/**
* Process the mouse events and map the mouse coordinates inverting the internal affine transformation.
*
* @param
* event the event to be dispatched
* layer the layer this LayerUI is set to
*
*/
@Override
public void eventDispatched(AWTEvent event, final JLayer<? extends JComponent> layer) {
if (event instanceof MouseEvent) {
MouseEvent mouseEvent = (MouseEvent) event;
/*
* The if discriminate between generated and original event.
* Removing it cause a stack overflow caused by the event being redispatched to this class.
*/
if (!dispatchingMode) {
// Process an original mouse event
dispatchingMode = true;
try {
redispatchMouseEvent(mouseEvent, layer);
} finally {
dispatchingMode = false;
}
} else {
/*
* Process generated mouse events
* Added a check, because on mouse entered or exited, the cursor
* may be set to specific dragging cursors.
*/
if (MouseEvent.MOUSE_ENTERED == mouseEvent.getID() || MouseEvent.MOUSE_EXITED == mouseEvent.getID()) {
layer.getGlassPane().setCursor(null);
} else {
Component component = mouseEvent.getComponent();
layer.getGlassPane().setCursor(component.getCursor());
}
}
} else {
super.eventDispatched(event, layer);
}
layer.repaint();
}
/**
* Set the affine transformation applied to the graphics
* @param transform the transformation
*/
public void setTransform(AffineTransform transform) {
if (transform != null) {
this.transform = transform;
}
}
/**
* Return the affine transformation applied to the graphics
* @return the transformation
*/
public AffineTransform getTransform() {
return transform;
}
/**
* Paint the specified component {@code c} applying the transformation on it's graphic
*
* @param
* g - the Graphics context in which to paint
* c - the component being painted
*/
@Override
public void paint(Graphics g, JComponent c) {
if (g instanceof Graphics2D) {
Graphics2D g2 = (Graphics2D) g.create();
JLayer<? extends JComponent> l = (JLayer<? extends JComponent>) c;
g2.transform(transform);
paintLayer(g2, l);
g2.dispose();
}
}
/**
* Paint the view decorated by the JLayer {@code layer} and the JLayer itself
*
* @param g2
* @param layer the layer this LayerUI is set to
*/
private final void paintLayer(Graphics2D g2, JLayer<? extends JComponent> layer) {
JComponent view = layer.getView();
if (view != null) {
if (view.getX() < 0 || view.getY() < 0) {
setToNoDoubleBuffering(view);
g2.translate(view.getX(), view.getY());
view.paint(g2);
for (JComponent jComp : originalDoubleBuffered) {
jComp.setDoubleBuffered(true);
}
originalDoubleBuffered.clear();
return;
}
}
layer.paint(g2);
}
/**
* Disable the double buffering for the {@code component} and for all of it's children
*
* @param component
*/
private void setToNoDoubleBuffering(Component component) {
if (component instanceof JComponent) {
JComponent jComp = (JComponent) component;
if (jComp.isDoubleBuffered()) {
originalDoubleBuffered.add(jComp);
jComp.setDoubleBuffered(false);
}
}
if (component instanceof Container) {
Container container = (Container) component;
for (int index = 0; index < container.getComponentCount(); index++) {
setToNoDoubleBuffering(container.getComponent(index));
}
}
}
/**
* {@inheritDoc}
*/
@Override
public void uninstallUI(JComponent component) {
if (!(component instanceof JLayer<?>)) {
throw new IllegalArgumentException(
this.getClass().getName() + " invalid class, must be a JLayer component");
}
JLayer<JComponent> jlayer = (JLayer<JComponent>) component;
jlayer.setLayerEventMask(0);
super.uninstallUI(component);
}
/**
* {@inheritDoc}
*/
@Override
public void installUI(JComponent component) throws IllegalStateException {
super.installUI(component);
if (installedLayer != null) {
throw new IllegalStateException(this.getClass().getName() + " cannot be shared between multiple layers");
}
if (!(component instanceof JLayer<?>)) {
throw new IllegalArgumentException(
this.getClass().getName() + " invalid class, must be a JLayer component");
}
// component.getClass().getDeclaringClass();
installedLayer = (JLayer<JComponent>) component;
installedLayer.setLayerEventMask(AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK
| AWTEvent.MOUSE_WHEEL_EVENT_MASK | AWTEvent.KEY_EVENT_MASK | AWTEvent.FOCUS_EVENT_MASK);
}
/**
* Process the mouse events and map the mouse coordinates inverting the internal affine transformation.
* It consume the original event, calculates the mapped mouse coordinates and find the real target of the mouse event.
* It than create a new event with the correct informations in it and redispatch it to the target event
*
* @param originalEvent the event to be dispatched
* @param layer the layer this LayerUI is set to
*/
private void redispatchMouseEvent(MouseEvent originalEvent, JLayer<? extends JComponent> layer) {
if (layer.getView() != null) {
if (originalEvent.getComponent() != layer.getGlassPane()) {
originalEvent.consume();
}
MouseEvent newEvent = null;
Point realPoint = calculateTargetPoint(layer, originalEvent);
Component realTarget = getTarget(layer, realPoint);
// Component realTarget =
// SwingUtilities.getDeepestComponentAt(layer.getView(),
// realPoint.x, realPoint.y);
if (realTarget != null) {
//System.out.println(realTarget.getClass().getName());
realTarget = getListeningComponent(originalEvent, realTarget);
}
switch (originalEvent.getID()) {
case MouseEvent.MOUSE_PRESSED:
newEvent = transformMouseEvent(layer, originalEvent, realTarget, realPoint);
if (newEvent != null) {
lastPressedTarget = newEvent.getComponent();
}
break;
case MouseEvent.MOUSE_RELEASED:
newEvent = transformMouseEvent(layer, originalEvent, lastPressedTarget, realPoint);
lastPressedTarget = null;
break;
case MouseEvent.MOUSE_CLICKED:
newEvent = transformMouseEvent(layer, originalEvent, realTarget, realPoint);
lastPressedTarget = null;
break;
case MouseEvent.MOUSE_MOVED:
newEvent = transformMouseEvent(layer, originalEvent, realTarget, realPoint);
generateEnterExitEvents(layer, originalEvent, realTarget, realPoint);
break;
case MouseEvent.MOUSE_ENTERED:
generateEnterExitEvents(layer, originalEvent, realTarget, realPoint);
break;
case MouseEvent.MOUSE_EXITED:
generateEnterExitEvents(layer, originalEvent, realTarget, realPoint);
break;
case MouseEvent.MOUSE_DRAGGED:
newEvent = transformMouseEvent(layer, originalEvent, lastPressedTarget, realPoint);
generateEnterExitEvents(layer, originalEvent, realTarget, realPoint);
break;
case (MouseEvent.MOUSE_WHEEL):
// redispatchMouseWheelEvent((MouseWheelEvent) originalEvent,
// realTarget, realPoint);
newEvent = transformMouseWheelEvent(layer, (MouseWheelEvent) originalEvent, realTarget, realPoint);
break;/**/
}
dispatchMouseEvent(newEvent);
}
}
/**
* Apply the inverse transformation to {@code point}
*
* @param layer the layer this LayerUI is set to
* @param point the starting point
* @return the transformed point
*/
private Point transformPoint(JLayer<? extends JComponent> layer, Point point) {
if (transform != null) {
try {
transform.inverseTransform(point, point);
} catch (NoninvertibleTransformException e) {
e.printStackTrace();
}
}
return point;
}
/**
* Find the deepest component in the AWT hierarchy
*
* @param layer the layer to which this UI is installed
* @param targetPoint the point in layer's coordinates
* @return the component in the specified point
*/
private Component getTarget(JLayer<? extends JComponent> layer, Point targetPoint) {
Component view = layer.getView();
if (view == null) {
return null;
} else {
Point viewPoint = SwingUtilities.convertPoint(layer, targetPoint, view);
return SwingUtilities.getDeepestComponentAt(view, viewPoint.x, viewPoint.y);
}
}
/**
* Convert the {@code mouseEvent}'s coordinates to the {@code layer}'s space
* @param layer the layer this LayerUI is set to
* @param mouseEvent the original mouse event
* @return the {@code mouseEvent}'s point transformed to the {@code layer}'s coordinate space
*/
private Point calculateTargetPoint(JLayer<? extends JComponent> layer,
MouseEvent mouseEvent) {
Point point = mouseEvent.getPoint();
//SwingUtilities.convertPointToScreen(point, mouseEvent.getComponent());
//SwingUtilities.convertPointFromScreen(point, layer);
point = SwingUtilities.convertPoint(mouseEvent.getComponent(), point, layer);
return transformPoint(layer, point);
}
private MouseEvent transformMouseEvent(JLayer<? extends JComponent> layer, MouseEvent mouseEvent, Component target, Point realPoint) {
return transformMouseEvent( layer, mouseEvent, target, realPoint, mouseEvent.getID());
}
/**
* Create the new event to being dispatched
*/
private MouseEvent transformMouseEvent(JLayer<? extends JComponent> layer, MouseEvent mouseEvent, Component target, Point targetPoint, int id) {
if (target == null) {
return null;
} else {
Point newPoint = SwingUtilities.convertPoint(layer, targetPoint, target);
return new MouseEvent(target, //
id, //
mouseEvent.getWhen(), //
mouseEvent.getModifiers(), //
newPoint.x, //
newPoint.y, //
mouseEvent.getClickCount(), //
mouseEvent.isPopupTrigger(), //
mouseEvent.getButton());
}
}
/**
* Create the new mouse wheel event to being dispached
*/
private MouseWheelEvent transformMouseWheelEvent( JLayer<? extends JComponent> layer, MouseWheelEvent mouseWheelEvent, Component target,
Point targetPoint) {
if (target == null) {
return null;
} else {
Point newPoint = SwingUtilities.convertPoint(layer, targetPoint, target);
return new MouseWheelEvent(target, //
mouseWheelEvent.getID(), //
mouseWheelEvent.getWhen(), //
mouseWheelEvent.getModifiers(), //
newPoint.x, //
newPoint.y, //
mouseWheelEvent.getClickCount(), //
mouseWheelEvent.isPopupTrigger(), //
mouseWheelEvent.getScrollType(), //
mouseWheelEvent.getScrollAmount(), //
mouseWheelEvent.getWheelRotation() //
);
}
}
/**
* dispatch the {@code mouseEvent}
* @param mouseEvent the event to be dispatched
*/
private void dispatchMouseEvent(MouseEvent mouseEvent) {
if (mouseEvent != null) {
Component target = mouseEvent.getComponent();
target.dispatchEvent(mouseEvent);
}
}
/**
* Get the listening component associated to the {@code component}'s {@code event}
*/
private Component getListeningComponent(MouseEvent event, Component component) {
switch (event.getID()) {
case (MouseEvent.MOUSE_CLICKED):
case (MouseEvent.MOUSE_ENTERED):
case (MouseEvent.MOUSE_EXITED):
case (MouseEvent.MOUSE_PRESSED):
case (MouseEvent.MOUSE_RELEASED):
return getMouseListeningComponent(component);
case (MouseEvent.MOUSE_DRAGGED):
case (MouseEvent.MOUSE_MOVED):
return getMouseMotionListeningComponent(component);
case (MouseEvent.MOUSE_WHEEL):
return getMouseWheelListeningComponent(component);
}
return null;
}
/**
* Cycles through the {@code component}'s parents to find the {@link Component} with associated {@link MouseListener}
*/
private Component getMouseListeningComponent(Component component) {
if (component.getMouseListeners().length > 0) {
return component;
} else {
Container parent = component.getParent();
if (parent != null) {
return getMouseListeningComponent(parent);
} else {
return null;
}
}
}
/**
* Cycles through the {@code component}'s parents to find the {@link Component} with associated {@link MouseMotionListener}
*/
private Component getMouseMotionListeningComponent(Component component) {
/*
* Mouse motion events may result in MOUSE_ENTERED and MOUSE_EXITED.
*
* Therefore, components with MouseListeners registered should be
* returned as well.
*/
if (component.getMouseMotionListeners().length > 0 || component.getMouseListeners().length > 0) {
return component;
} else {
Container parent = component.getParent();
if (parent != null) {
return getMouseMotionListeningComponent(parent);
} else {
return null;
}
}
}
/**
* Cycles through the {@code component}'s parents to find the {@link Component} with associated {@link MouseWheelListener}
*/
private Component getMouseWheelListeningComponent(Component component) {
if (component.getMouseWheelListeners().length > 0) {
return component;
} else {
Container parent = component.getParent();
if (parent != null) {
return getMouseWheelListeningComponent(parent);
} else {
return null;
}
}
}
/**
* Generate a {@code MOUSE_ENTERED} and {@code MOUSE_EXITED} event when the target component is changed
*/
private void generateEnterExitEvents( JLayer<? extends JComponent> layer,MouseEvent originalEvent, Component newTarget, Point realPoint) {
if (lastEnteredTarget != newTarget) {
dispatchMouseEvent(
transformMouseEvent(layer, originalEvent, lastEnteredTarget, realPoint, MouseEvent.MOUSE_EXITED));
lastEnteredTarget = newTarget;
//System.out.println("Last " + lastEnteredTarget.getClass().getName());
dispatchMouseEvent(
transformMouseEvent(layer, originalEvent, lastEnteredTarget, realPoint, MouseEvent.MOUSE_ENTERED));
}
}
}
ZoomPanel
是一个 JPanel
,其中包含一个 JLayer
和一个 TransformUI
。 JLayer
包含一个 JPanel
和一个 SpringLayout
,其中使用比例因子更新约束以正确布局组件(JXLayer
有它自己的 LayoutManager
但在 JLayer
中你不能设置它)
package jzoom.transform;
import ...
public class ZoomPanel extends JPanel {
private static final long serialVersionUID = 1L;
private AffineTransform transform;
private TransformUI layerUI;
private JLayer<JComponent> layer;
private SpringLayout layout;
private JPanel springPanel;
private Container view = null;
public ZoomPanel() {
this(null);
}
public ZoomPanel(Container view) {
setLayout(new BorderLayout());
this.view = view;
transform = new AffineTransform();
layout = new SpringLayout();
springPanel = new JPanel(layout);
if (view != null) {
updateConstraints();
springPanel.add(view);
}
layerUI = new TransformUI();
layerUI.setTransform(transform);
layer = new JLayer<JComponent>(springPanel, layerUI);
super.add(layer);
}
private void updateConstraints() {
Spring width = layout.getConstraint(SpringLayout.WIDTH, springPanel);
Spring height = layout.getConstraint(SpringLayout.HEIGHT, springPanel);
SpringLayout.Constraints constraints = layout.getConstraints(view);
constraints.setX(Spring.constant(0));
constraints.setY(Spring.constant(0));
constraints.setWidth(Spring.scale(width, (float) (1 / transform.getScaleX())));
constraints.setHeight(Spring.scale(height, (float) (1 / transform.getScaleX())));
}
public void setView(Container view) {
if (this.view != null) {
throw new IllegalStateException(
this.getClass().getName() + " cannot be shared between multiple containers");
}
if (view != null) {
this.view = view;
updateConstraints();
springPanel.add(view);
} else {
throw new IllegalArgumentException("Can't set a null view");
}
}
public double getScale() {
return transform.getScaleX();
}
public void zoomIn() {
setScale(transform.getScaleX() + 0.1);
}
public void zoomOut() {
setScale(transform.getScaleX() - 0.1);
}
public void setScale(double scale) {
if (!(scale < 1)) {
transform.setToIdentity();
transform.scale(scale, scale);
updateConstraints();
springPanel.updateUI();
}
}
protected Component addToView(Component comp, Object constraints, int index) {
if (view != null) {
view.add(comp, constraints, index);
return comp;
}
if (comp instanceof Container) {
setView((Container) comp);
return view;
}
throw new IllegalStateException("You need to add or set a Container view before adding Components");
}
@Override
public Component add(Component comp) {
// TODO Auto-generated method stub
return addToView(comp, null, this.getComponentCount());
}
@Override
public Component add(Component comp, int index) {
// TODO Auto-generated method stub
return addToView(comp, null, index);
}
@Override
public void add(Component comp, Object constraints) {
// TODO Auto-generated method stub
addToView(comp, constraints, this.getComponentCount());
}
@Override
public void add(Component comp, Object constraints, int index) {
// TODO Auto-generated method stub
addToView(comp, constraints, index);
}
private void inspectView(Container view) {
PrintStream ps = null;
try {
ps = new PrintStream("C:\Users\andrea.maracci\Documents\sicraReflectionTemp.txt");
inspectView(view, 0, ps);
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (ps != null) {
ps.close();
}
}
}
private static void inspectView(Component component, Integer level, PrintStream ps) {
for (Integer i = 0; i < level; i++) {
ps.print("\t");
}
ps.print(level + ")");
ps.println("Inspecting " + component.getClass().getName());
int accessibleCount = 0;
if (component.getAccessibleContext() != null) {
accessibleCount = component.getAccessibleContext().getAccessibleChildrenCount();
if (accessibleCount > 0) {
ps.println("*********************************************ACCESSIBLE CONTEXT*********************************************");
for (int i = 0; i < accessibleCount; i++) {
ps.println(i + ") " + component.getAccessibleContext().getAccessibleChild(i).getClass().getName());
}
ps.println("************************************************************************************************************");
}
}
if (component instanceof JComponent) {
JComponent jComponent = ((JComponent)component);
if (jComponent.getComponentCount() > 0) {
Component[] children = jComponent.getComponents();
for (Component child : children) {
inspectView(child, ++level, ps);
}
}
}
--level;
}
}
这是一个可怕的测试程序
package jzoom.test;
import ...
public class TestFinal {
public static void main(String[] args) {
new TestFinal();
}
public TestFinal() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedLookAndFeelException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setMinimumSize(new Dimension(400,500));
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JLayer<JComponent> layer;
private TransformUI layerUI;
private JPanel content;
private AffineTransform transform = new AffineTransform();
private ZoomPanel zoomPanel;
public TestPane() {
content = new JPanel(new GridBagLayout());
// content = new JPanel(new XYLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridy = 0;
gbc.weighty = 0;
gbc.weightx = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
JLabel label = new JLabel("Hello");
JTextField field = new JTextField("World", 20);
content.add(label, gbc);
gbc.weightx = 1;
content.add(field, gbc);
// content.add(label, new XYConstraints(50, 20, 50, 22));
// content.add(field, new XYConstraints(100, 20, 200, 22));
gbc.gridy++;
gbc.gridwidth = 2;
final JSlider slider = new JSlider(100, 200);
slider.setValue(100);
slider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
int value = slider.getValue();
double scale = value / 100d;
zoomPanel.setScale(scale);
}
});
content.add(slider, gbc);
// content.add(slider, new XYConstraints(75, 50, 200, 50));
gbc.gridy++;
gbc.gridwidth = 2;
gbc.weighty = 1;
gbc.fill = GridBagConstraints.BOTH;
JTextArea textArea = new JTextArea();
textArea.setEditable(true);
textArea.setText(
"pollofritto\npalma\npalmipedone\ncaccoletta\namammata\na\nasd\nasdgfag\nasdafa\nasdfasf\nadsfasdf\nadfadsf\nadsfdasf\nasdfdas\npollofritto\npalma\npalmipedone\ncaccoletta\namammata\na\nasd\nasdgfag\nasdafa\nasdfasf\nadsfasdf\nadfadsf\nadsfdasf\nasdfdas");
// textArea.setPreferredSize(new Dimensions());
JScrollPane scrollPane = new JScrollPane(textArea);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.setPreferredSize(new Dimension(200, 75));
content.add(scrollPane, gbc);
gbc.gridy++;
gbc.gridwidth = 2;
gbc.weighty = 0;
gbc.weightx = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
String[] petStrings = { "Bird", "Cat", "Dog", "Rabbit", "Pig" };
JComboBox petList = new JComboBox(petStrings);
content.add(petList, gbc);
JButton zoomIn = new JButton("Zoom In");
// zoomIn.addMouseListener(new ZoomMouseListener());
zoomIn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// System.out.println("FIRST");
// layerUI.zoomIn();
//double zoom = transform.getScaleX();
//transform.setToIdentity();
//transform.scale(zoom + 0.1, zoom + 0.1);
zoomPanel.zoomIn();
// jLayer.repaint();
}
});
JButton zoomOut = new JButton("Zoom Out");
zoomOut.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
zoomPanel.zoomOut();
//double zoom = transform.getScaleX();
//transform.setToIdentity();
//transform.scale(zoom - 0.1, zoom - 0.1);
// jLayer.repaint();
}
});
gbc.gridy++;
gbc.gridx = 0;
gbc.gridwidth = 0;
gbc.anchor = GridBagConstraints.LINE_END;
// content.add(zoomOut, new XYConstraints(50, 120, 100, 25));
// content.add(zoomIn, new XYConstraints(170, 120, 100, 25));
JPanel button = new JPanel();
button.setLayout(new BoxLayout(button, BoxLayout.LINE_AXIS));
button.add(zoomOut);
button.add(zoomIn);
gbc.fill = GridBagConstraints.NONE;
content.add(button, gbc);
setLayout(new BorderLayout());
setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
zoomPanel = new ZoomPanel();
zoomPanel.setView(content);
add(zoomPanel);
}
}
}