java - JDialog 具有透明背景,模糊了下面的东西

标签 java swing background blur jdialog

我正在尝试制作一个透明的 JDialog,它会模糊其下面的内容(为了更好的可读性)。已经找到这个link ,但是对话框的内容是模糊的。我还发现了this ,但是所有东西(下面的东西和对话框的内容)都是模糊的并且闪烁。

下面是为了更好地理解的屏幕截图:

enter image description here

顶部是我已经拥有的,底部是我想要实现的。

最佳答案

经过一些测试后,获得您想要实现的目标似乎非常困难。我最终使用了 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) {
    }
}

关于java - JDialog 具有透明背景,模糊了下面的东西,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39511717/

相关文章:

java swing addactionlistener JButton

android - 非常奇怪,当插入任何二十欧元纸币的图片时,Android 应用程序就会崩溃

java - 如何使用 xpath 在嵌套 xml 中查找 Web 元素

java - vlcj3 支持的文件类型列表?

java - Swing JTabbedPane 在填充时抛出 IndexOutOfBoundsException

java - 如何阻止列表将 1 和 0 的混合转换为全 0?

java - 无法在调用拦截 Android 应用程序中阻止号码不以“+91”开头的联系人

java - Hibernate 查询 - ClassCastError

html - 无法让背景填充最小宽度

ios - NSOperationQueue 批处理 SLRequests