程序化调整大小后,半透明JFrame渲染效果不佳

时间:2014-10-03 14:02:22

标签: java swing jframe

(使用Java 1.7.0_45在Mac OS X 10.10上会出现此问题。在使用Java 1.7.0_55的Windows 7上,我没有这个问题。)

我有一个半透明的"总是在顶部" JFrame包含JLabel中的一些信息。当信息改变时,我再次通知JFrame pack(),以使JFrame保持尽可能小。当JFrame重新布局并在调整大小后绘制JFrame时,会出现渲染故障。

这是一个SSCCE:

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class ScratchSpace {


    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {

                final JLabel label = new JLabel("Test message that is long");
                label.setOpaque(false);
                label.setForeground(Color.WHITE);

                JLabel iconLabel = new JLabel("Label 2");

                JPanel contentPane = new JPanel();
                contentPane.setOpaque(false);
                contentPane.add(label);

                contentPane.add(iconLabel);

                final JFrame hudFrame = new JFrame();
                hudFrame.setAlwaysOnTop(true);
                hudFrame.setType(Window.Type.UTILITY);
                hudFrame.setUndecorated(true);
                hudFrame.setBackground(new Color(0, 0, 0, 50));

                hudFrame.setContentPane(contentPane);
                hudFrame.pack();
                hudFrame.setLocationRelativeTo(null);
                hudFrame.setVisible(true);

                Timer timer = new Timer(2000, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        label.setText("Shorter test message");
                        hudFrame.pack();
                    }
                });
                timer.setRepeats(false);
                timer.start();
            }
        });
    }
}

这是输出的放大屏幕截图,您可以在其中看到JFrame未正确重新渲染。 JFrame之前的内容有一种苍白的印象:

enter image description here

在保持每像素半透明的同时,我该怎么做才能解决这个问题?

1 个答案:

答案 0 :(得分:2)

有关进展情况的信息

"苍白的印象"你看到的是Mac OS X窗口阴影。 WindowServer将阴影计算为窗口内容的alpha通道的模糊。

但是,每当窗口内容发生变化时,WindowServer都不会重新计算阴影(因为这会非常昂贵),但仅在请求时才会重新计算。所以你需要的是一种确保你的Swing窗口在内部发出请求的方法。

可能的解决方法

不幸的是,我没有10.10左右来测试,所以我不知道这是否有效,但有一种情况下,重新计算阴影显然是必要的:当窗口调整大小时(因为甚至非透明窗口然后获得阴影)。在这种情况下, 使用pack()调整窗口大小,因此必须在此处出现某种时间/事件排序问题。

我的建议是,在内容更新后,稍微调整窗口。伪代码:

  1. 按照您目前的要求更新内容和pack()
  2. JFrame的大小更改为比一维中的打包大小大一个像素。
  3. 启动计时器,以便在0 ms后执行,执行:

      再次
    1. pack(),或者只是将尺寸更改为小一个像素。
  4. 直截了当的丑陋修改代码:

                Timer timer = new Timer(2000, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        label.setText("Shorter test message");
                        hudFrame.pack();
                        Dimension d = hudFrame.getSize();
                        d.width += 1;
                        hudFrame.setSize(d);
                        Timer timer = new Timer(0, new ActionListener() {
                            @Override
                            public void actionPerformed(ActionEvent e) {
                                hudFrame.pack();
                            }
                        });
                        timer.setRepeats(false);
                        timer.start();
                    }
                });
                timer.setRepeats(false);
                timer.start();