屏幕上鼠标位置周围区域的缩放框

时间:2013-08-10 04:10:34

标签: java swing jpanel awt zoom

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

我在询问Color Chooser程序的背景下。需要实现的最后一个功能就是Zoom Box。

2 个答案:

答案 0 :(得分:7)

我确信有很多不同的方法可以实现。

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

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

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

我没有玩变焦因子,所以可能还有一些怪癖,但你应该得到基本的想法......

虽然我已经提供了一个图像作为背景,但这应该适用于任何组件

enter image description here

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方法检测到鼠标位置没有改变时,它会更新缓冲区并显示缩放窗口。当鼠标位置改变时,它会再次隐藏窗口......但那就是我;)

enter image description here

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而不是浮动框上固定了一个面板)

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

enter image description here

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();
    }

  }

}

答案 1 :(得分:3)

Zoom On Mouse

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);
    }
}