2016-09-15 4 views
2

透明なJDialogを作成しようとしています。すでにlinkが見つかりましたが、ダイアログの内容がぼやけています。また、私はthisを見つけましたが、そこにはすべて(ダイアログの下のものと内容)がぼやけてちらつきがあります。ここで透明な背景を持つJDialogは、下にあるものをぼかす

は、より良い理解のためのスクリーンショットです:

enter image description here

トップは、私はすでに私が達成したいものを持っていると下のものです。

+0

あなたは画像を埋め込むことが許可されていない場合でも、あなたはi.stack.imgur.com上の画像を投稿する必要があります。他の外部サイトへのリンクは古くなる傾向があります。 – VGR

答えて

1

いくつかのテストの後、達成したいものを得ることはかなり難しいようです。私は、ぼやけた背景のための1つのレイヤーと実際のコンテンツのための1つのレイヤーを含むJLayeredPaneを使用して終了しました。

私は結果には全く満足していませんが、今はもっと良い解決策を見つけられませんでした。 問題は、Javaが実際のアプリケーションの背後にあるものをキャプチャする適切な方法を提供しないため、スクリーンショットを撮る前にコンテンツを隠す必要があることです。それはあなたが言及したちらつきを引き起こす問題でもあります。 これを避けるには、アプリケーションのサイズを変更または移動した場合にのみバックグラウンドを書き直します。これに一度実際に使用された場合、さらに多くの努力を払う必要があります。アプリが最小化された場合。しかし、この例をサイズ変更することはできません。最小化されているので、今はそれほど重要ではありません。 しかし、このアプローチの欠点は、背景が静的でないかどうかを完全に無視していることです。たとえば、ビデオの前でアプリケーションを使用する場合、現在のバージョンはビデオの現在のフレームに基づいて背景を変更しません。これは、私の例でタイマーのコメントを外すと可能になる可能性があります。setVisible(...)しかし、次にちらつきが戻ってきます。

JavaFxの使用について考えてみることをお勧めします。 CSSはすでにぼかし機能を提供しているので、Fxでもうまく機能する可能性があります。しかし、私はまだそれを試していないので、私はそれが働いていることを保証することはできません。

短いストーリー、ここにその例があります。ぼかし機能は上のリンクから使用されます。

import java.awt.AWTException; 
import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Graphics; 
import java.awt.Rectangle; 
import java.awt.Robot; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.ComponentEvent; 
import java.awt.event.ComponentListener; 
import java.awt.image.BufferedImage; 
import java.awt.image.BufferedImageOp; 
import java.awt.image.ConvolveOp; 
import java.awt.image.Kernel; 

import javax.swing.JComponent; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JLayeredPane; 
import javax.swing.JPanel; 
import javax.swing.SwingConstants; 

@SuppressWarnings("serial") 
public class BlurryFrame extends JFrame implements ActionListener, ComponentListener { 

    public static void main(String... sss) { 

     JLabel label1 = new JLabel("TestLabel 1"); 
     label1.setSize(500, 100); 
     label1.setForeground(Color.RED); 

     JLabel label2 = new JLabel("TestLabel 2"); 
     label2.setHorizontalAlignment(SwingConstants.CENTER); 
     label2.setForeground(Color.BLUE); 

     JPanel testPanel = new JPanel(); 
     testPanel.setOpaque(false); 
     testPanel.setLayout(new BorderLayout()); 
     testPanel.add(label1, BorderLayout.CENTER); 
     testPanel.add(label2, BorderLayout.SOUTH); 

     BlurryFrame frame = new BlurryFrame(800, 600, testPanel); 
     frame.setBackground(new Color(0, 0, 0, 100)); 
     frame.setVisible(true); 
    } 

    private final BackgroundPanel backgroundPane; 
    private final JLayeredPane container; 
    private final JPanel containerPane; 
    private final Robot robot; 

    // This rectangle is going to be your screenshots bounds to keep the image only as big as necessary 
    private final Rectangle captureRect; 

    // This is going to be the blurred screenshot 
    private BufferedImage background; 

    public BlurryFrame() { 
     this(1280, 800); 
    } 

    public BlurryFrame(int width, int height) { 
     this(width, height, null); 
    } 

    public BlurryFrame(int width, int height, JComponent component) { 

     this.captureRect = new Rectangle(); 
     try { 
      this.robot = new Robot(); 
     } catch (AWTException e) { 
      throw new RuntimeException(e); 
     } 

     this.backgroundPane = new BackgroundPanel(); 
     this.backgroundPane.setOpaque(false); 
     this.backgroundPane.setLayout(new BorderLayout()); 
     this.backgroundPane.setBounds(0, 0, width, height); 
     this.backgroundPane.addComponentListener(this); 

     this.containerPane = new JPanel(); 
     this.containerPane.setOpaque(false); 
     this.containerPane.setLayout(new BorderLayout()); 
     this.containerPane.add(component, BorderLayout.CENTER); 
     this.containerPane.setBounds(0, 0, width, height); 

     this.setUndecorated(true); 
     this.setSize(width, height); 
     this.setLocationRelativeTo(null); 

     this.container = new JLayeredPane(); 
     this.container.setOpaque(false); 
     this.container.setLayout(new BorderLayout()); 
     this.container.add(this.backgroundPane, 1); 
     this.container.add(this.containerPane, 0); 

     this.getContentPane().add(this.container, BorderLayout.CENTER); 
    } 

    public void add(JComponent component) { 
     this.containerPane.add(component, BorderLayout.CENTER); 
     this.containerPane.repaint(); 
    } 

    // This method does not really do much but ultimately triggers the screenshot by ending up in #componentHidden(...) 
    private void capture() { 
     this.containerPane.setVisible(false); 
     this.backgroundPane.setVisible(false); 
     this.repaint(); 
    } 

    @Override 
    public void setVisible(boolean visible) { 

     super.setVisible(visible); 
     this.capture(); 

     // XXX uncomment this if you want to see the flickering 
     // Timer timer = new Timer(60, this); 
     // timer.start(); 
    } 

    @Override 
    public void setSize(int width, int height) { 

     super.setSize(width, height); 

     this.captureRect.setSize(width, height); 
     this.backgroundPane.setBounds(0, 0, width, height); 
     this.containerPane.setBounds(0, 0, width, height); 

     if (this.isVisible()) 
      this.capture(); 
    } 

    @Override 
    public void setSize(Dimension dimension) { 

     super.setSize(dimension); 

     this.captureRect.setSize(dimension); 
     this.backgroundPane.setBounds(0, 0, dimension.width, dimension.height); 
     this.containerPane.setBounds(0, 0, dimension.width, dimension.height); 

     if (this.isVisible()) 
      this.capture(); 
    } 

    @Override 
    public void setPreferredSize(Dimension dimension) { 

     super.setPreferredSize(dimension); 

     this.captureRect.setSize(dimension); 
     this.backgroundPane.setBounds(0, 0, dimension.width, dimension.height); 
     this.containerPane.setBounds(0, 0, dimension.width, dimension.height); 

     if (this.isVisible()) 
      this.capture(); 
    } 

    @Override 
    public void actionPerformed(ActionEvent e) { 
     this.capture(); 
    } 

    int i = 0; 

    // This is where the magic happens. The capturing needs to be done here in order to assure the applications content has really been hidden 
    @Override 
    public void componentHidden(ComponentEvent e) { 

     int x = this.getLocationOnScreen().x; 
     int y = this.getLocationOnScreen().y; 

     this.captureRect.setLocation(x, y); 

     this.background = this.robot.createScreenCapture(this.captureRect); 

     //XXX uncomment this if you want to see what gets captured 
     //  if (this.i < 1) { 
     //   try { 
     //    ImageIO.write(this.background, "png", new File(System.getProperty("user.home") + "\\test.png")); 
     //   } catch (IOException ex) { 
     //    ex.printStackTrace(); 
     //   } 
     //   this.i++; 
     //  } 

     this.containerPane.setVisible(true); 
     this.backgroundPane.setVisible(true); 
     this.repaint(); 
    } 

    @Override 
    public void componentMoved(ComponentEvent e) { 
     this.capture(); 
    } 

    @Override 
    public void componentResized(ComponentEvent e) { 
     this.capture(); 
    } 

    private class BackgroundPanel extends JPanel { 

     private final float[] matrix = { 
       0.111f, 0.111f, 0.111f, 
       0.111f, 0.111f, 0.111f, 
       0.111f, 0.111f, 0.111f, 
     }; 

     @Override 
     public void paintComponent(Graphics g) { 

      super.paintComponent(g); 

      if (BlurryFrame.this.background != null) { 

       BufferedImageOp op = new ConvolveOp(new Kernel(3, 3, this.matrix)); 
       BufferedImage blurryBack = op.filter(BlurryFrame.this.background, null); 

       g.drawImage(blurryBack, 0, 0, null); 
      } 
     } 
    } 

    @Override 
    public void componentShown(ComponentEvent e) { 
    } 
} 
1

私はBenGe89sとマークしましたが、私の問題を解決しました。

しかし、フレームを移動可能にするために拡張機能を共有したいと考えました。私はこのComponentMoverを使用して少し修正したので、ドラッグが開始されて停止すると、フレームのgetが通知されます。フレームが動かされている間、背景はちらつきを避けるために透明になります。 BlurryFrame修正

package de.win; 

import java.awt.Component; 
import java.awt.Cursor; 
import java.awt.Dimension; 
import java.awt.Insets; 
import java.awt.Point; 
import java.awt.Rectangle; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 

import javax.swing.JComponent; 
import javax.swing.SwingUtilities; 

public class ComponentMover extends MouseAdapter { 
// private boolean moveWindow; 

@SuppressWarnings("rawtypes") 
private Class destinationClass; 
private DragNotifier dragNotifier; 
private Component destinationComponent; 
private Component destination; 
private Component source; 

private boolean changeCursor = true; 

private Point pressed; 
private Point location; 

private Cursor originalCursor; 
private boolean autoscrolls; 

private Insets dragInsets = new Insets(0, 0, 0, 0); 
private Dimension snapSize = new Dimension(1, 1); 

/** 
* * Constructor for moving individual components. The components must be regisetered using the registerComponent() method. 
*/ 
public ComponentMover() { 
} 

/** 
* * Constructor to specify a Class of Component that will be moved when drag events are generated on a registered child component. The events will be passed to the first ancestor of this specified class. 
* 
* @param destinationClass 
*   the Class of the ancestor component 
* @param component 
*   the Components to be registered for forwarding drag events to the ancestor Component. 
*/ 
public ComponentMover(@SuppressWarnings("rawtypes") Class destinationClass, DragNotifier dragNotifier, Component... components) { 
    this.destinationClass = destinationClass; 
    this.dragNotifier = dragNotifier; 
    registerComponent(components); 
} 

/** 
* * Constructor to specify a parent component that will be moved when drag events are generated on a registered child component. 
* 
* @param destinationComponent 
*   the component drage events should be forwareded to 
* @param components 
*   the Components to be registered for forwarding drag events to the parent component to be moved 
*/ 
public ComponentMover(Component destinationComponent, DragNotifier dragNotifier, Component... components) { 
    this.destinationComponent = destinationComponent; 
    this.dragNotifier = dragNotifier; 
    registerComponent(components); 
} 

/** 
* * Get the change cursor property 
* 
* @return the change cursor property 
*/ 
public boolean isChangeCursor() { 
    return changeCursor; 
} 

/** 
* * Set the change cursor property 
* 
* @param changeCursor 
*   when true the cursor will be changed to the Cursor.MOVE_CURSOR while the mouse is pressed 
*/ 
public void setChangeCursor(boolean changeCursor) { 
    this.changeCursor = changeCursor; 
} 

/** 
* * Get the drag insets 
* 
* @return the drag insets 
*/ 
public Insets getDragInsets() { 
    return dragInsets; 
} 

/** 
* * Set the drag insets. The insets specify an area where mouseDragged events should be ignored and therefore the component will not be moved. This will prevent these events from being confused with a MouseMotionListener that supports component resizing. 
* 
* @param dragInsets 
*/ 
public void setDragInsets(Insets dragInsets) { 
    this.dragInsets = dragInsets; 
} 

/** 
* * Remove listeners from the specified component 
* 
* @param component 
*   the component the listeners are removed from 
*/ 
public void deregisterComponent(Component... components) { 
    for (Component component : components) 
     component.removeMouseListener(this); 
} 

/** 
* * Add the required listeners to the specified component 
* 
* @param component 
*   the component the listeners are added to 
*/ 
public void registerComponent(Component... components) { 
    for (Component component : components) 
     component.addMouseListener(this); 
} 

/** 
* * Get the snap size 
* 
* @return the snap size 
*/ 
public Dimension getSnapSize() { 
    return snapSize; 
} 

/** 
* * Set the snap size. Forces the component to be snapped to the closest grid position. Snapping will occur when the mouse is dragged half way. 
*/ 
public void setSnapSize(Dimension snapSize) { 
    this.snapSize = snapSize; 
} 

/** 
* * Setup the variables used to control the moving of the component: 
* 
* source - the source component of the mouse event destination - the component that will ultimately be moved pressed - the Point where the mouse was pressed in the destination component coordinates. 
*/ 
@Override 
public void mousePressed(MouseEvent e) { 
    dragNotifier.dragStart(); 

    source = e.getComponent(); 
    int width = source.getSize().width - dragInsets.left - dragInsets.right; 
    int height = source.getSize().height - dragInsets.top - dragInsets.bottom; 
    Rectangle r = new Rectangle(dragInsets.left, dragInsets.top, width, height); 

    if (r.contains(e.getPoint())) 
     setupForDragging(e); 
} 

private void setupForDragging(MouseEvent e) { 
    source.addMouseMotionListener(this); 

    // Determine the component that will ultimately be moved 

    if (destinationComponent != null) { 
     destination = destinationComponent; 
    } else if (destinationClass == null) { 
     destination = source; 
    } else // forward events to destination component 
    { 
     destination = SwingUtilities.getAncestorOfClass(destinationClass, source); 
    } 

    pressed = e.getLocationOnScreen(); 
    location = destination.getLocation(); 

    if (changeCursor) { 
     originalCursor = source.getCursor(); 
     source.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); 
    } 

    // Making sure autoscrolls is false will allow for smoother dragging of individual components 

    if (destination instanceof JComponent) { 
     JComponent jc = (JComponent) destination; 
     autoscrolls = jc.getAutoscrolls(); 
     jc.setAutoscrolls(false); 
    } 
} 

/** 
* * Move the component to its new location. The dragged Point must be in the destination coordinates. 
*/ 
@Override 
public void mouseDragged(MouseEvent e) { 
    Point dragged = e.getLocationOnScreen(); 
    int dragX = getDragDistance(dragged.x, pressed.x, snapSize.width); 
    int dragY = getDragDistance(dragged.y, pressed.y, snapSize.height); 
    destination.setLocation(location.x + dragX, location.y + dragY); 
} 

/* 
* * Determine how far the mouse has moved from where dragging started (Assume drag direction is down and right for positive drag distance) 
*/ 
private int getDragDistance(int larger, int smaller, int snapSize) { 
    int halfway = snapSize/2; 
    int drag = larger - smaller; 
    drag += (drag < 0) ? -halfway : halfway; 
    drag = (drag/snapSize) * snapSize; 

    return drag; 
} 

/** 
* * Restore the original state of the Component 
*/ 
@Override 
public void mouseReleased(MouseEvent e) { 
    source.removeMouseMotionListener(this); 

    if (changeCursor) 
     source.setCursor(originalCursor); 

    if (destination instanceof JComponent) { 
     ((JComponent) destination).setAutoscrolls(autoscrolls); 
    } 

    if (dragNotifier != null) { 
     dragNotifier.dragComplete(); 
    } 

} 

interface DragNotifier { 
    public void dragComplete(); 

    public void dragStart(); 
} 

} 

package de.win; 

import java.awt.AWTException; 
import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Graphics; 
import java.awt.Rectangle; 
import java.awt.Robot; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.ComponentEvent; 
import java.awt.event.ComponentListener; 
import java.awt.image.BufferedImage; 
import java.awt.image.BufferedImageOp; 
import java.awt.image.ConvolveOp; 
import java.awt.image.Kernel; 

import javax.swing.JComponent; 
import javax.swing.JDialog; 
import javax.swing.JLabel; 
import javax.swing.JLayeredPane; 
import javax.swing.JPanel; 
import javax.swing.SwingConstants; 

import de.win.ComponentMover.DragNotifier; 

@SuppressWarnings("serial") 
public class BlurryFrame extends JDialog implements ActionListener,  ComponentListener, DragNotifier { 

public static void main(String... sss) { 

    JLabel label1 = new JLabel("TestLabel 1"); 
    label1.setSize(500, 100); 
    label1.setForeground(Color.RED); 

    JLabel label2 = new JLabel("TestLabel 2"); 
    label2.setHorizontalAlignment(SwingConstants.CENTER); 
    label2.setForeground(Color.BLUE); 

    JPanel testPanel = new JPanel(); 
    testPanel.setOpaque(false); 
    testPanel.setLayout(new BorderLayout()); 
    testPanel.add(label1, BorderLayout.CENTER); 
    testPanel.add(label2, BorderLayout.SOUTH); 

    BlurryFrame frame = new BlurryFrame(800, 600, testPanel); 
    frame.setBackground(new Color(0, 0, 0, 100)); 
    frame.setVisible(true); 
    new ComponentMover(frame, frame, testPanel); 
} 

private final BackgroundPanel backgroundPane; 
private final JLayeredPane container; 
private final JPanel containerPane; 
private final Robot robot; 

// This rectangle is going to be your screenshots bounds to keep the image only as big as necessary 
private final Rectangle captureRect; 

// This is going to be the blurred screenshot 
private BufferedImage background; 

public BlurryFrame() { 
    this(1280, 800); 
} 

public BlurryFrame(int width, int height) { 
    this(width, height, null); 
} 

public BlurryFrame(int width, int height, JComponent component) { 

    this.captureRect = new Rectangle(); 
    try { 
     this.robot = new Robot(); 
    } catch (AWTException e) { 
     throw new RuntimeException(e); 
    } 

    this.backgroundPane = new BackgroundPanel(); 
    this.backgroundPane.setOpaque(false); 
    this.backgroundPane.setLayout(new BorderLayout()); 
    this.backgroundPane.setBounds(0, 0, width, height); 
    this.backgroundPane.addComponentListener(this); 

    this.containerPane = new JPanel(); 
    this.containerPane.setOpaque(false); 
    this.containerPane.setLayout(new BorderLayout()); 
    this.containerPane.add(component, BorderLayout.CENTER); 
    this.containerPane.setBounds(0, 0, width, height); 

    this.setUndecorated(true); 
    this.setSize(width, height); 
    this.setLocationRelativeTo(null); 

    this.container = new JLayeredPane(); 
    this.container.setOpaque(false); 
    this.container.setLayout(new BorderLayout()); 
    this.container.add(this.backgroundPane, 1); 
    this.container.add(this.containerPane, 0); 

    this.getContentPane().add(this.container, BorderLayout.CENTER); 
} 

public void add(JComponent component) { 
    this.containerPane.add(component, BorderLayout.CENTER); 
    this.containerPane.repaint(); 
} 

// This method does not really do much but ultimately triggers the screenshot by ending up in #componentHidden(...) 
private void capture() { 
    this.containerPane.setVisible(false); 
    this.backgroundPane.setVisible(false); 
    this.repaint(); 
} 

@Override 
public void setVisible(boolean visible) { 

    super.setVisible(visible); 
    this.capture(); 

    // XXX uncomment this if you want to see the flickering 
    // Timer timer = new Timer(60, this); 
    // timer.start(); 
} 

@Override 
public void setSize(int width, int height) { 

    super.setSize(width, height); 

    this.captureRect.setSize(width, height); 
    this.backgroundPane.setBounds(0, 0, width, height); 
    this.containerPane.setBounds(0, 0, width, height); 

    if (this.isVisible()) 
     this.capture(); 
} 

@Override 
public void setSize(Dimension dimension) { 

    super.setSize(dimension); 

    this.captureRect.setSize(dimension); 
    this.backgroundPane.setBounds(0, 0, dimension.width, dimension.height); 
    this.containerPane.setBounds(0, 0, dimension.width, dimension.height); 

    if (this.isVisible()) 
     this.capture(); 
} 

@Override 
public void setPreferredSize(Dimension dimension) { 

    super.setPreferredSize(dimension); 

    this.captureRect.setSize(dimension); 
    this.backgroundPane.setBounds(0, 0, dimension.width, dimension.height); 
    this.containerPane.setBounds(0, 0, dimension.width, dimension.height); 

    if (this.isVisible()) 
     this.capture(); 
} 

@Override 
public void actionPerformed(ActionEvent e) { 
    this.capture(); 
} 

int i = 0; 

// This is where the magic happens. The capturing needs to be done here in order to assure the applications content has really been hidden 
@Override 
public void componentHidden(ComponentEvent e) { 

    int x = this.getLocationOnScreen().x; 
    int y = this.getLocationOnScreen().y; 

    this.captureRect.setLocation(x, y); 

    this.background = this.robot.createScreenCapture(this.captureRect); 

    // XXX uncomment this if you want to see what gets captured 
    // if (this.i < 1) { 
    // try { 
    // ImageIO.write(this.background, "png", new File(System.getProperty("user.home") + "\\test.png")); 
    // } catch (IOException ex) { 
    // ex.printStackTrace(); 
    // } 
    // this.i++; 
    // } 

    this.containerPane.setVisible(true); 
    this.backgroundPane.setVisible(true); 
    this.repaint(); 
} 

@Override 
public void componentMoved(ComponentEvent e) { 
    this.capture(); 
} 

@Override 
public void componentResized(ComponentEvent e) { 
    this.capture(); 
} 

private class BackgroundPanel extends JPanel { 

    private final float[] matrix = { 0.111f, 0.111f, 0.111f, 0.111f, 0.111f, 0.111f, 0.111f, 0.111f, 0.111f, }; 

    @Override 
    public void paintComponent(Graphics g) { 
     if (BlurryFrame.this.background != null) { 

      BufferedImageOp op = new ConvolveOp(new Kernel(3, 3, this.matrix)); 
      BufferedImage blurryBack = op.filter(BlurryFrame.this.background, null); 

      g.drawImage(blurryBack, 0, 0, null); 
     } 
    } 
} 

@Override 
public void componentShown(ComponentEvent e) { 
} 

@Override 
public void dragComplete() { 
    this.capture(); 
} 

@Override 
public void dragStart() { 
    this.background = null; 
    this.backgroundPane.repaint(); 
} 

}

関連する問題