绘制边界矩形以选择要记录的区域

界

如何在屏幕上绘制半透明矩形? 这不能是JFrame因为JFrames在右上角有通常的关闭,最小化,最大化选项。
如果它确实是一个挥杆能力,它是如何在空气中绘制的? 无需将其插入JFrame中? 请告诉我它是什么以及如何实现它……

想到的直接想法是使用java.awt.Robot捕获屏幕截图,将其绘制到无框窗口。 从那里你可以简单地在上面画一个矩形

更新了示例

……花了一些时间……

在此处输入图像描述

 public class SelectionRectangle { public static void main(String[] args) { new SelectionRectangle(); } public SelectionRectangle() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { } JFrame frame = new JFrame("Test"); frame.setUndecorated(true); frame.setExtendedState(JFrame.MAXIMIZED_BOTH); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new BorderLayout()); frame.add(new BackgroundPane()); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } public class BackgroundPane extends JPanel { private BufferedImage background; private Point mouseAnchor; private Point dragPoint; private SelectionPane selectionPane; public BackgroundPane() { selectionPane = new SelectionPane(); try { Robot bot = new Robot(); background = bot.createScreenCapture(getScreenViewableBounds()); } catch (AWTException ex) { Logger.getLogger(SelectionRectangle.class.getName()).log(Level.SEVERE, null, ex); } selectionPane = new SelectionPane(); setLayout(null); add(selectionPane); MouseAdapter adapter = new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { mouseAnchor = e.getPoint(); dragPoint = null; selectionPane.setLocation(mouseAnchor); selectionPane.setSize(0, 0); } @Override public void mouseDragged(MouseEvent e) { dragPoint = e.getPoint(); int width = dragPoint.x - mouseAnchor.x; int height = dragPoint.y - mouseAnchor.y; int x = mouseAnchor.x; int y = mouseAnchor.y; if (width < 0) { x = dragPoint.x; width *= -1; } if (height < 0) { y = dragPoint.y; height *= -1; } selectionPane.setBounds(x, y, width, height); selectionPane.revalidate(); repaint(); } }; addMouseListener(adapter); addMouseMotionListener(adapter); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g.create(); g2d.drawImage(background, 0, 0, this); g2d.dispose(); } } public class SelectionPane extends JPanel { private JButton button; private JLabel label; public SelectionPane() { button = new JButton("Close"); setOpaque(false); label = new JLabel("Rectangle"); label.setOpaque(true); label.setBorder(new EmptyBorder(4, 4, 4, 4)); label.setBackground(Color.GRAY); label.setForeground(Color.WHITE); setLayout(new GridBagLayout()); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 0; add(label, gbc); gbc.gridy++; add(button, gbc); button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { SwingUtilities.getWindowAncestor(SelectionPane.this).dispose(); } }); addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { label.setText("Rectangle " + getX() + "x" + getY() + "x" + getWidth() + "x" + getHeight()); } }); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g.create(); g2d.setColor(new Color(128, 128, 128, 64)); g2d.fillRect(0, 0, getWidth(), getHeight()); float dash1[] = {10.0f}; BasicStroke dashed = new BasicStroke(3.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f, dash1, 0.0f); g2d.setColor(Color.BLACK); g2d.setStroke(dashed); g2d.drawRect(0, 0, getWidth() - 3, getHeight() - 3); g2d.dispose(); } } public static Rectangle getScreenViewableBounds() { GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice gd = ge.getDefaultScreenDevice(); return getScreenViewableBounds(gd); } public static Rectangle getScreenViewableBounds(GraphicsDevice gd) { Rectangle bounds = new Rectangle(0, 0, 0, 0); if (gd != null) { GraphicsConfiguration gc = gd.getDefaultConfiguration(); bounds = gc.getBounds(); Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(gc); bounds.x += insets.left; bounds.y += insets.top; bounds.width -= (insets.left + insets.right); bounds.height -= (insets.top + insets.bottom); } return bounds; } } 

使用SnipIt更新示例

有些人建议在屏幕顶部放置一个透明窗口,这实际上是行不通的,因为透明窗口实际上并没有响应鼠标点击,除非他们有一些东西可以在它们上面绘制,这将允许鼠标事件发生被困

有人建议您使用Window作为选择机制,这是一个有效的答案,但是,我会(个人)发现这是一个不合适的解决方案,因为您希望用户只需单击并拖动选择矩形(恕我直言) )。

另一种方法是使用像SnipIt这样的东西。

在此处输入图像描述

 public class SnipIt { public static void main(String[] args) { new SnipIt(); } public SnipIt() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { } JFrame frame = new JFrame(); frame.setUndecorated(true); // This works differently under Java 6 frame.setBackground(new Color(0, 0, 0, 0)); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new BorderLayout()); frame.add(new SnipItPane()); frame.setBounds(getVirtualBounds()); frame.setVisible(true); } }); } public class SnipItPane extends JPanel { private Point mouseAnchor; private Point dragPoint; private SelectionPane selectionPane; public SnipItPane() { setOpaque(false); setLayout(null); selectionPane = new SelectionPane(); add(selectionPane); MouseAdapter adapter = new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { mouseAnchor = e.getPoint(); dragPoint = null; selectionPane.setLocation(mouseAnchor); selectionPane.setSize(0, 0); } @Override public void mouseDragged(MouseEvent e) { dragPoint = e.getPoint(); int width = dragPoint.x - mouseAnchor.x; int height = dragPoint.y - mouseAnchor.y; int x = mouseAnchor.x; int y = mouseAnchor.y; if (width < 0) { x = dragPoint.x; width *= -1; } if (height < 0) { y = dragPoint.y; height *= -1; } selectionPane.setBounds(x, y, width, height); selectionPane.revalidate(); repaint(); } }; addMouseListener(adapter); addMouseMotionListener(adapter); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g.create(); Rectangle bounds = new Rectangle(0, 0, getWidth(), getHeight()); Area area = new Area(bounds); area.subtract(new Area(selectionPane.getBounds())); g2d.setColor(new Color(192, 192, 192, 64)); g2d.fill(area); } } public class SelectionPane extends JPanel { private JButton button; private JLabel label; public SelectionPane() { button = new JButton("Close"); setOpaque(false); label = new JLabel("Rectangle"); label.setOpaque(true); label.setBorder(new EmptyBorder(4, 4, 4, 4)); label.setBackground(Color.GRAY); label.setForeground(Color.WHITE); setLayout(new GridBagLayout()); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 0; add(label, gbc); gbc.gridy++; add(button, gbc); button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { SwingUtilities.getWindowAncestor(SelectionPane.this).dispose(); } }); addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { label.setText("Rectangle " + getX() + "x" + getY() + "x" + getWidth() + "x" + getHeight()); } }); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g.create(); // I've chosen NOT to fill this selection rectangle, so that // it now appears as if you're "cutting" away the selection // g2d.setColor(new Color(128, 128, 128, 64)); // g2d.fillRect(0, 0, getWidth(), getHeight()); float dash1[] = {10.0f}; BasicStroke dashed = new BasicStroke(3.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f, dash1, 0.0f); g2d.setColor(Color.BLACK); g2d.setStroke(dashed); g2d.drawRect(0, 0, getWidth() - 3, getHeight() - 3); g2d.dispose(); } } public static Rectangle getVirtualBounds() { Rectangle bounds = new Rectangle(0, 0, 0, 0); GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice lstGDs[] = ge.getScreenDevices(); for (GraphicsDevice gd : lstGDs) { bounds.add(gd.getDefaultConfiguration().getBounds()); } return bounds; } } 

更新Multi Monitor支持来自@MadProgrammer的示例答案。

没有ExtendedState(JFrame.MAXIMIZED_BOTH)pack()

在此处输入图像描述

 public SelectionRectangle() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { } JFrame frame = new JFrame("Test"); frame.setUndecorated(true); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new BorderLayout()); frame.add(new BackgroundPane()); frame.setResizable( false ); frame.setBounds( getScreenViewableBounds() ); frame.setVisible(true); } }); } 

 public static Rectangle getScreenViewableBounds() { GraphicsDevice[] devices = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices(); int minx = Integer.MAX_VALUE; int miny = Integer.MAX_VALUE; int maxx = Integer.MIN_VALUE; int maxy = Integer.MIN_VALUE; for( GraphicsDevice device : devices ) { for( GraphicsConfiguration config : device.getConfigurations() ) { Rectangle bounds = config.getBounds(); minx = Math.min( minx, bounds.x ); miny = Math.min( miny, bounds.y ); maxx = Math.max( maxx, bounds.x + bounds.width ); maxy = Math.max( maxy, bounds.y + bounds.height ); } } return new Rectangle( new Point(minx, miny), new Dimension(maxx - minx, maxy - miny) ); } 

您可以使用透明的未装饰框架来创建基本边框。

 public class ScreenRectangle extends JFrame { public ScreenRectangle() { this.setUndecorated(true); this.setBackground(new Color(0, 0, 0, 0.25F)); // opacity ranges 0.0-1.0 and is the fourth paramater this.add(new DrawPanel()); } private class DrawPanel extends JPanel { @Override public void paintComponent(Graphics g) { super.paintComponent(g); g.drawRect(0, 0, this.getWidth(), this.getHeight()); // any other drawing } } } 

框架也可能需要设置为setOpaque ,或者可能需要处理面板尺寸,但这是它的一般概念。