【问题标题】:Zoom box for area around mouse location on screen [closed]屏幕上鼠标位置周围区域的缩放框[关闭]
【发布时间】:2013-08-12 02:03:33
【问题描述】:

有没有办法在 Java 中创建一个动态缩放框,其中包括 e. G。光标周围的 20x20pix 区域(但即使光标移动到应用程序的框架之外)并且会在一个小的 JPanel 中显示?

我是在颜色选择器程序的上下文中询问的。最后一个需要实现的功能就是 Zoom Box。

【问题讨论】:

    标签: java swing jpanel awt zooming


    【解决方案1】:

    我确信有许多不同的方法可以实现这一目标。

    这基本上使用了一个单独的组件,它充当“缩放框”。你向它提供一个你想要“放大”的组件。它添加了一个鼠标侦听器,因此它可以监视鼠标运动事件以及进入和退出事件。

    这些用于确定“弹出”窗口应显示的时间、弹出窗口应显示的位置以及应“绘制”的区域。

    这使用“要缩放的组件”paint 方法将其区域绘制到后备缓冲区,然后将其缩放并绘制到“缩放框”...简单

    我没有玩过缩放系数,所以可能还有一些怪癖,但你应该明白基本的想法......

    虽然我展示了一张图片作为背景,但这应该适用于任何组件

    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.Point;
    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseEvent;
    import java.awt.geom.AffineTransform;
    import java.awt.image.BufferedImage;
    import java.io.File;
    import java.io.IOException;
    import javax.imageio.ImageIO;
    import javax.swing.JComponent;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JWindow;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    
    public class ZoomBoxWindow {
    
      public static void main(String[] args) {
        new ZoomBoxWindow();
      }
    
      public ZoomBoxWindow() {
        EventQueue.invokeLater(new Runnable() {
          @Override
          public void run() {
            try {
              UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
              ex.printStackTrace();
            }
    
            TestPane pane = new TestPane();
            ZoomPane zoomPane = new ZoomPane(pane);
    
            JFrame frame = new JFrame("Testing");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(pane);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
          }
        });
      }
    
      public static class ZoomPane extends JPanel {
    
        protected static final int ZOOM_AREA = 40;
    
        private JComponent parent;
        private JWindow popup;
    
        private BufferedImage buffer;
    
        private float zoomLevel = 2f;
    
        public ZoomPane(JComponent parent) {
          this.parent = parent;
          popup = new JWindow();
          popup.setLayout(new BorderLayout());
          popup.add(this);
          popup.pack();
          MouseAdapter ma = new MouseAdapter() {
            @Override
            public void mouseMoved(MouseEvent e) {
              Point p = e.getPoint();
              Point pos = e.getLocationOnScreen();
              updateBuffer(p);
              popup.setLocation(pos.x + 16, pos.y + 16);
              repaint();
            }
    
            @Override
            public void mouseEntered(MouseEvent e) {
              popup.setVisible(true);
            }
    
            @Override
            public void mouseExited(MouseEvent e) {
              popup.setVisible(false);
            }
    
          };
    
          parent.addMouseListener(ma);
          parent.addMouseMotionListener(ma);
        }
    
        protected void updateBuffer(Point p) {
          int width = Math.round(ZOOM_AREA);
          int height = Math.round(ZOOM_AREA);
          buffer = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
          Graphics2D g2d = buffer.createGraphics();
          AffineTransform at = new AffineTransform();
    
          int xPos = (ZOOM_AREA / 2) - p.x;
          int yPos = (ZOOM_AREA / 2) - p.y;
    
          if (xPos > 0) {
            xPos = 0;
          }
          if (yPos > 0) {
            yPos = 0;
          }
    
          if ((xPos * -1) + ZOOM_AREA > parent.getWidth()) {
            xPos = (parent.getWidth() - ZOOM_AREA) * -1;
          }
          if ((yPos * -1) + ZOOM_AREA > parent.getHeight()) {
            yPos = (parent.getHeight()- ZOOM_AREA) * -1;
          }
    
          at.translate(xPos, yPos);
          g2d.setTransform(at);
          parent.paint(g2d);
          g2d.dispose();
        }
    
        @Override
        public Dimension getPreferredSize() {
          return new Dimension(Math.round(ZOOM_AREA * zoomLevel), Math.round(ZOOM_AREA * zoomLevel));
        }
    
        @Override
        protected void paintComponent(Graphics g) {
          super.paintComponent(g);
          Graphics2D g2d = (Graphics2D) g.create();
          if (buffer != null) {
            AffineTransform at = g2d.getTransform();
            g2d.setTransform(AffineTransform.getScaleInstance(zoomLevel, zoomLevel));
            g2d.drawImage(buffer, 0, 0, this);
            g2d.setTransform(at);
          }
          g2d.setColor(Color.RED);
          g2d.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
          g2d.dispose();
        }
    
      }
    
      public class TestPane extends JPanel {
    
        private BufferedImage img;
    
        public TestPane() {
          try {
            img = ImageIO.read(new File("/path/to/your/image"));
          } catch (IOException ex) {
            ex.printStackTrace();
          }
        }
    
        @Override
        public Dimension getPreferredSize() {
          return img == null ? new Dimension(200, 200) : new Dimension(img.getWidth(), img.getHeight());
        }
    
        @Override
        protected void paintComponent(Graphics g) {
          super.paintComponent(g);
          if (img != null) {
            Graphics2D g2d = (Graphics2D) g.create();
            int x = (getWidth() - img.getWidth()) / 2;
            int y = (getHeight() - img.getHeight()) / 2;
            g2d.drawImage(img, x, y, this);
            g2d.dispose();
          }
        }
    
      }
    
    }
    

    更新为“屏幕”版本

    此版本将允许您在屏幕上的任何位置显示“缩放窗口”。

    这有一个小问题,您需要在捕获屏幕之前隐藏缩放窗口,然后重新显示它。

    我可能很想改变这个过程,以便当updateBuffer 方法检测到鼠标位置没有改变时,它会更新缓冲区并显示缩放窗口。当鼠标位置改变时,它会再次隐藏窗口......但那是我;)

    import java.awt.AWTException;
    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.MouseInfo;
    import java.awt.Point;
    import java.awt.PointerInfo;
    import java.awt.Rectangle;
    import java.awt.Robot;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.geom.AffineTransform;
    import java.awt.image.BufferedImage;
    import javax.swing.Action;
    import javax.swing.JPanel;
    import javax.swing.JWindow;
    import javax.swing.Timer;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    import static zoomboxwindow.ZoomBoxWindow.ZoomPane.ZOOM_AREA;
    
    public class GlobalZoomBox {
    
      public static void main(String[] args) {
        new GlobalZoomBox();
      }
    
      public GlobalZoomBox() {
        EventQueue.invokeLater(new Runnable() {
          @Override
          public void run() {
            try {
              UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
              ex.printStackTrace();
            }
            Zoomer zoomer = new Zoomer();
            zoomer.setZoomWinodwVisible(true);
          }
        });
      }
    
      public class Zoomer extends JPanel {
    
        protected static final int ZOOM_AREA = 40;
    
        private JWindow popup;
    
        private BufferedImage buffer;
        private Robot bot;
    
        private float zoomLevel = 2f;
        private Point lastPoint;
        private final Timer timer;
    
        public Zoomer() {
          popup = new JWindow();
          popup.setLayout(new BorderLayout());
          popup.add(this);
          popup.pack();
          try {
            bot = new Robot();
          } catch (AWTException ex) {
            ex.printStackTrace();
          }
          timer = new Timer(125, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
              updateBuffer();
            }
          });
          timer.setCoalesce(true);
          timer.setInitialDelay(0);
        }
    
        public void setZoomWinodwVisible(boolean value) {
    
          if (value && !popup.isVisible()) {
    
            timer.start();
            popup.setVisible(true);
    
          } else {
    
            timer.stop();
            popup.setVisible(false);
    
          }
    
        }
    
        @Override
        public Dimension getPreferredSize() {
          return new Dimension(Math.round(ZOOM_AREA * zoomLevel), Math.round(ZOOM_AREA * zoomLevel));
        }
    
        protected void updateBuffer() {
          if (bot != null) {
            PointerInfo info = MouseInfo.getPointerInfo();
            Point p = info.getLocation();
            if (lastPoint == null || !lastPoint.equals(p)) {
              int x = p.x - (ZOOM_AREA / 2);
              int y = p.y - (ZOOM_AREA / 2);
              popup.setLocation(p.x + 16, p.y + 16);
              popup.setVisible(false);
              buffer = bot.createScreenCapture(new Rectangle(x, y, ZOOM_AREA, ZOOM_AREA));
              popup.setVisible(true);
              lastPoint = p;
              repaint();
            }
          }
        }
    
        @Override
        protected void paintComponent(Graphics g) {
          super.paintComponent(g);
          Graphics2D g2d = (Graphics2D) g.create();
          if (buffer != null) {
            AffineTransform at = g2d.getTransform();
            g2d.setTransform(AffineTransform.getScaleInstance(zoomLevel, zoomLevel));
            g2d.drawImage(buffer, 0, 0, this);
            g2d.setTransform(at);
          }
          g2d.setColor(Color.RED);
          g2d.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
          g2d.dispose();
        }
    
      }
    
    }
    

    更新了“工具提示”样式的弹出窗口

    第二个示例的主要问题是您需要隐藏弹出窗口才能抓取屏幕截图。这样做是为了防止弹出窗口也开始被捕获。这使得每次移动鼠标时弹出窗口都会“闪烁”。

    您“可以”解决此问题,确保弹出窗口位于捕获范围之外,但随着您增加捕获区域,弹出窗口将远离光标。

    当然,这对于固定位置显示来说是一个很好的解决方案(即,您将面板固定在 JFrame 而不是浮动框上)

    这是一个额外的更新,它使用第二个计时器在用户停止移动鼠标后显示缩放框。

    import java.awt.AWTException;
    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.MouseInfo;
    import java.awt.Point;
    import java.awt.PointerInfo;
    import java.awt.Rectangle;
    import java.awt.Robot;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.geom.AffineTransform;
    import java.awt.image.BufferedImage;
    import javax.swing.Action;
    import javax.swing.JPanel;
    import javax.swing.JWindow;
    import javax.swing.Timer;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    import static zoomboxwindow.ZoomBoxWindow.ZoomPane.ZOOM_AREA;
    
    public class GlobalZoomBox {
    
      public static void main(String[] args) {
        new GlobalZoomBox();
      }
    
      public GlobalZoomBox() {
        EventQueue.invokeLater(new Runnable() {
          @Override
          public void run() {
            try {
              UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
              ex.printStackTrace();
            }
            Zoomer zoomer = new Zoomer();
            zoomer.setZoomWinodwVisible(true);
          }
        });
      }
    
      public class Zoomer extends JPanel {
    
        protected static final int ZOOM_AREA = 80;
    
        private JWindow popup;
    
        private BufferedImage buffer;
        private Robot bot;
    
        private float zoomLevel = 2f;
        private Point lastPoint;
        private final Timer timer;
        private final Timer popupTimer;
    
        public Zoomer() {
          popup = new JWindow();
          popup.setLayout(new BorderLayout());
          popup.add(this);
          popup.pack();
          try {
            bot = new Robot();
          } catch (AWTException ex) {
            ex.printStackTrace();
          }
          timer = new Timer(125, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
              updateBuffer();
            }
          });
          timer.setCoalesce(true);
          timer.setInitialDelay(0);
    
          popupTimer = new Timer(250, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
              if (lastPoint != null) {
                System.out.println("lastPoint = " + lastPoint);
                popup.setVisible(false);
                Point p = lastPoint;
                int x = p.x - (ZOOM_AREA / 2);
                int y = p.y - (ZOOM_AREA / 2);
                popup.setLocation(p.x + 16, p.y + 16);
                buffer = bot.createScreenCapture(new Rectangle(x, y, ZOOM_AREA, ZOOM_AREA));
                repaint();
                popup.setVisible(true);
              }
            }
          });
          popupTimer.setRepeats(false);
        }
    
        public void setZoomWinodwVisible(boolean value) {
    
          if (value && !popup.isVisible()) {
    
            timer.start();
            popup.setVisible(true);
    
          } else {
    
            timer.stop();
            popup.setVisible(false);
    
          }
    
        }
    
        @Override
        public Dimension getPreferredSize() {
          return new Dimension(Math.round(ZOOM_AREA * zoomLevel), Math.round(ZOOM_AREA * zoomLevel));
        }
    
        protected void updateBuffer() {
          if (bot != null) {
            PointerInfo info = MouseInfo.getPointerInfo();
            Point p = info.getLocation();
            if (lastPoint == null || !lastPoint.equals(p)) {
              lastPoint = p;
              popupTimer.stop();
              popup.setVisible(false);
            } else {
              if (!popup.isVisible()) {
                popupTimer.start();
              }
            }
          }
        }
    
        @Override
        protected void paintComponent(Graphics g) {
          super.paintComponent(g);
          Graphics2D g2d = (Graphics2D) g.create();
          if (buffer != null) {
            AffineTransform at = g2d.getTransform();
            g2d.setTransform(AffineTransform.getScaleInstance(zoomLevel, zoomLevel));
            g2d.drawImage(buffer, 0, 0, this);
            g2d.setTransform(at);
          }
          g2d.setColor(Color.RED);
          g2d.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
          g2d.dispose();
        }
    
      }
    
    }
    

    【讨论】:

    • 非常酷的想法,光标后面有一个小框,但是......可惜它只出现在父组件边框中。是否可以从父组件扩展或使独立的框/工具提示存在?
    • 正如我所说,应该可以将任何组件传递给它,例如,你将它传递给框架的内容窗格,它应该也能够看到所有子组件。或者您是否正在寻找可用于屏幕任何部分的解决方案?
    • 我正在寻找可以在整个屏幕上使用的解决方案。
    • 我会看到我的鞭子;)
    • 谢谢。我会试着弄清楚:)
    【解决方案2】:

    import java.awt.*;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.image.BufferedImage;
    import javax.swing.*;
    
    class ZoomOnMouse {
    
        public static void main(String[] args) throws AWTException {
            final Robot robot = new Robot();
            Runnable r = new Runnable() {
    
                @Override
                public void run() {
                    final int size = 256;
                    final BufferedImage bi = new BufferedImage(
                            size, size, BufferedImage.TYPE_INT_RGB);
                    final JLabel gui = new JLabel(new ImageIcon(bi));
                    ActionListener zoomListener = new ActionListener() {
    
                        @Override
                        public void actionPerformed(ActionEvent e) {
                            PointerInfo pi = MouseInfo.getPointerInfo();
                            Point p = pi.getLocation();
                            BufferedImage temp = robot.createScreenCapture(
                                    new Rectangle(p.x-(size/4), p.y-(size/4), 
                                    (size/2), (size/2)));
                            Graphics g = bi.getGraphics();
                            g.drawImage(temp, 0, 0, size, size, null);
                            g.dispose();
                            gui.repaint();
                        }
                    };
                    Timer t = new Timer(40, zoomListener);
                    t.start();
    
                    JOptionPane.showMessageDialog(null, gui);
    
                    t.stop();
                }
            };
            // Swing GUIs should be created and updated on the EDT
            // http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
            SwingUtilities.invokeLater(r);
        }
    }
    

    【讨论】:

    • 太棒了!非常感谢楼主!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-13
    • 2020-05-28
    • 2014-08-18
    • 2013-05-16
    • 1970-01-01
    • 2021-06-25
    • 1970-01-01
    相关资源
    最近更新 更多