Масштабирование JLayeredPane через JLayer и LayerUI

Было предложено на этот вопрос переполнения стека о том, что лучший способ реализовать масштабирование в приложениях Swing — использовать декораторы JLayer, поставляемые с Java 7.

Я следил за руководством по Oracle и думаю лучший способ сделать это — создать собственный ZoomUI, расширяющий LayerUI. До сих пор я думал, что этот класс будет иметь переменную-член zoom, которая применяется перед рисованием фактического компонента.

Затем позже я могу использовать этот же класс, чтобы перехватывать события мыши и отправлять их в их немасштабированные координаты.

У меня возникли небольшие проблемы с первым шагом, и я не могу понять, почему вызов g2.scale(zoom, zoom) не влияет на мой SSCCE ниже.

import javax.swing.*;
import javax.swing.plaf.LayerUI;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;

public class Demo {


    public static void main(String args[]) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

                final JLayeredPane panel = new JLayeredPane();
                final ZoomUI layerUI = new ZoomUI();
                final JLayer<JComponent> jLayer = new JLayer<JComponent>(panel, layerUI);

                Button zoomIn = new Button("Zoom In");
                zoomIn.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                       layerUI.zoom += 0.1;
                       jLayer.repaint();
                    }
                });
                zoomIn.setBounds(0,0,100,50);
                panel.add(zoomIn);

                Button zoomOut = new Button("Zoom Out");
                zoomOut.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        layerUI.zoom -= 0.1;
                        jLayer.repaint();
                    }
                });
                zoomOut.setBounds(100,0,100,50);
                panel.add(zoomOut);

                frame.setPreferredSize(new Dimension(400,200));
                frame.add(jLayer);
                frame.pack();
                frame.setVisible(true);
            }
        });
    }

    private static class ZoomUI extends LayerUI<JComponent> {
        public int zoom = 1.5; // Changing this value seems to have no effect
        @Override
        public void paint(Graphics g, JComponent c) {
            Graphics2D g2 = (Graphics2D) g.create();
            g2.scale(zoom, zoom);
            super.paint(g2, c);
            g2.dispose();
        }

        @Override
        public void installUI(JComponent c) {
            super.installUI(c);
            JLayer jlayer = (JLayer)c;
            jlayer.setLayerEventMask(
                    AWTEvent.MOUSE_EVENT_MASK | AWTEvent.ACTION_EVENT_MASK |
                            AWTEvent.MOUSE_MOTION_EVENT_MASK
            );
        }

        @Override
        public void uninstallUI(JComponent c) {
            JLayer jlayer = (JLayer)c;
            jlayer.setLayerEventMask(0);
            super.uninstallUI(c);
        }
    }
}

В этом примере я ожидаю, что кнопки увеличения/уменьшения масштаба будут увеличиваться в размерах при нажатии и при увеличении будут правильно реагировать на события мыши. Это не нужно щелкать там, где они раньше находились, чтобы вызвать событие.

К сожалению, я не могу даже увеличить их до щелчка, изменив строку с комментариями, поэтому я был бы очень признателен за помощь!


person Sarah Tattersall    schedule 29.01.2014    source источник


Ответы (1)


Ваша непосредственная проблема заключается в том, что вы смешиваете компоненты тяжелого веса / AWT с компонентами легкого веса / Swing ...

Button является собственным компонентом, что означает, что его рисование находится вне контроля Swing и, следовательно, не зависит от него.

Вместо этого используйте JButton.

public class TestJLayerZoom {

    public static void main(String args[]) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

                final JPanel panel = new JPanel();
                final ZoomUI layerUI = new ZoomUI();
                final JLayer<JComponent> jLayer = new JLayer<JComponent>(panel, layerUI);

                JButton zoomIn = new JButton("Zoom In");
                zoomIn.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        layerUI.zoom += 0.1;
                        jLayer.repaint();
                    }
                });
                panel.add(zoomIn);

                JButton zoomOut = new JButton("Zoom Out");
                zoomOut.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        layerUI.zoom -= 0.1;
                        jLayer.repaint();
                    }
                });
                panel.add(zoomOut);

                frame.setPreferredSize(new Dimension(400, 200));
                frame.add(jLayer);
                frame.pack();
                frame.setVisible(true);
            }
        });
    }

    private static class ZoomUI extends LayerUI<JComponent> {

        public double zoom = 2; // Changing this value seems to have no effect

        @Override
        public void paint(Graphics g, JComponent c) {
            Graphics2D g2 = (Graphics2D) g.create();
            g2.scale(zoom, zoom);
            super.paint(g2, c);
            g2.dispose();
        }

        @Override
        public void installUI(JComponent c) {
            super.installUI(c);
            JLayer jlayer = (JLayer) c;
            jlayer.setLayerEventMask(
                    AWTEvent.MOUSE_EVENT_MASK | AWTEvent.ACTION_EVENT_MASK
                    | AWTEvent.MOUSE_MOTION_EVENT_MASK
            );
        }

        @Override
        public void uninstallUI(JComponent c) {
            JLayer jlayer = (JLayer) c;
            jlayer.setLayerEventMask(0);
            super.uninstallUI(c);
        }
    }
}

Ваша следующая проблема будет заключаться в том, чтобы понять, как переводить события мыши;)

person MadProgrammer    schedule 29.01.2014