屏幕上鼠标位置周围区域的缩放框[关闭]
Posted
技术标签:
【中文标题】屏幕上鼠标位置周围区域的缩放框[关闭]【英文标题】:Zoom box for area around mouse location on screen [closed] 【发布时间】:2013-08-12 02:03:33 【问题描述】:有没有办法在 Java 中创建一个动态缩放框,其中包括 e. G。光标周围的 20x20pix 区域(但即使光标移动到应用程序的框架之外)并且会在一个小的 JPanel 中显示?
我是在颜色选择器程序的上下文中询问的。最后一个需要实现的功能就是 Zoom Box。
【问题讨论】:
【参考方案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);
【讨论】:
太棒了!非常感谢楼主!以上是关于屏幕上鼠标位置周围区域的缩放框[关闭]的主要内容,如果未能解决你的问题,请参考以下文章