2012-12-19 33 views
7

bound绘制边框选择什么区域记录

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

+1

本教程可能会帮助你,[如何使半透明窗口(http://docs.oracle.com/ javase/tutorial/uiswing/misc/trans_shaped_windows.html) –

回答

9

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

与例如

更新...花了一些时间......

enter image description here

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例

有人建议usi在屏幕顶部放置一个透明窗口,这实际上是行不通的,因为透明窗口实际上不会响应鼠标点击,除非它们有东西要涂在它们上面,这样鼠标事件才能被捕获。

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

另一种方法是使用类似SnipIt的东西。

enter image description here

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; 

    } 
} 
+0

是的,'robot'可以用来** **屏幕。然后'ImageIO'可以用来将它写到磁盘上,但是这个问题;那个神秘的矩形是什么? –

+0

使用标准Graphics2D简单地将图像涂在图像上 – MadProgrammer

+0

我相信问题是指屏幕本身的“捕获区域边界”,而不是所得到的捕获图像(或者'Robot'实际上是否被用于超出JVM窗口绘制?) – Vulcan

3

你可以以创建一个基本的边框使用透明,无修饰框架。

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,或面板尺寸,可能需要处理,但是这是它的总体思路。

+0

请致电'super.paintComponent';) – MadProgrammer

+0

@MadProgrammer哎呀!修正了这一点,谢谢。 (虽然在这种情况下实际上很重要,因为在JPanel上没有其他东西可以绘制,也许我会在稍后测试。) – Vulcan

+0

@Vulcan并且没有额外的代码需要创建可更改的大小吗? 'JFrame'会自己处理它? –

7

更新对@MadProgrammer的示例应答的多监视器支持。

没有ExtendedState(JFrame.MAXIMIZED_BOTH)pack()

enter image description here

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

这是一个有趣的方法。我会在getScreenViewableBounds中使用一个Area,基本上将每个设备边界/矩形添加到一起,这只是我虽然 – MadProgrammer