(使用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之前的内容有一种苍白的印象:
在保持每像素半透明的同时,我该怎么做才能解决这个问题?
答案 0 :(得分:2)
"苍白的印象"你看到的是Mac OS X窗口阴影。 WindowServer将阴影计算为窗口内容的alpha通道的模糊。
但是,每当窗口内容发生变化时,WindowServer都不会重新计算阴影(因为这会非常昂贵),但仅在请求时才会重新计算。所以你需要的是一种确保你的Swing窗口在内部发出请求的方法。
不幸的是,我没有10.10左右来测试,所以我不知道这是否有效,但有一种情况下,重新计算阴影显然是必要的:当窗口调整大小时(因为甚至非透明窗口然后获得阴影)。在这种情况下, 使用pack()
调整窗口大小,因此必须在此处出现某种时间/事件排序问题。
我的建议是,在内容更新后,稍微调整窗口。伪代码:
pack()
。JFrame
的大小更改为比一维中的打包大小大一个像素。启动计时器,以便在0 ms后执行,执行:
pack()
,或者只是将尺寸更改为小一个像素。直截了当的丑陋修改代码:
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();