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

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

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

解决方法:

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

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

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

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

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

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

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

  }

}
上一篇:java – 如何通过点制作直线曲线


下一篇:在java中,JFrame是重量级组件还是轻量级组件?