我在Swing中使用透明背景时遇到问题。由于挥杆不会重新改变变化的区域,因此产生了大量的人工制品。
据我所知,有两种开箱即用的方式可以使用透明背景:
问题:背景的透明部分永远不会刷新 - >人工制品。
问题:根本没有绘制背景。
我不想做的事:
我在Win7 x64上运行
Aaaand在这里是我的SSCCEEE:
更新1:init与invokeLater(仍然无法工作)
public class OpacityBug {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new OpacityBug();
}
});
}
static final Color transparentBlue = new Color(0f, 1f, 0f, 0.5f);
JFrame frame;
JPanel content;
JTextField txt1;
JTextField txt2;
public OpacityBug() {
initFrame();
initContent();
}
void initFrame() {
frame = new JFrame();
frame.setSize(300, 80);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
}
void initContent() {
content = new JPanel();
content.setDoubleBuffered(true);
content.setBackground(Color.red);
frame.getContentPane().add(content);
txt1 = new JTextField() {
@Override
public void setBorder(Border border) {
super.setBorder(null); //nope border
}
};
txt1.setText("Hi! I am Buggy!");
txt1.setOpaque(true);
txt1.setBackground(transparentBlue);
content.add(txt1);
txt2 = new JTextField() {
@Override
public void setBorder(Border border) {
super.setBorder(null); //nope border
}
};
txt2.setText("And I have no BG!");
txt2.setOpaque(false);
txt2.setBackground(transparentBlue);
content.add(txt2);
content.revalidate();
content.repaint();
}
}
更新2
正如你们中的一些人注意到的那样,Swing看起来挥杆无法画出透明的背景。但是,为什么我还没有清楚地知道为什么,我搜索了负责绘制组件背景的代码片段,并在ComponentUI.java中找到了以下代码:
public void update(Graphics g, JComponent c) {
if (c.isOpaque()) {
g.setColor(c.getBackground());
g.fillRect(0, 0, c.getWidth(),c.getHeight());
}
paint(g, c);
}
如您所见,它假设如果组件不是不透明的,则不需要重新绘制背景。我说这是一个非常模糊的假设。
我建议以下实施:
public void update(Graphics g, JComponent c) {
if(c.isOpaque() || (!c.isOpaque() && c.isBackgroundSet())) {
g.setColor(c.getBackground());
g.fillRect(0, 0, c.getWidth(), c.getHeight());
}
paint(g, c);
}
我只是检查组件是否不透明时是否设置了背景。这个简单的添加将允许我们在秋千中使用透明背景。至少我不知道为什么不应该这样做。
通过使用透明背景,您可以打破Swings绘画规则。基本上,当组件不透明时,您承诺绘制组件的背景。但由于背景是透明的,因此无需绘画。
查看Backgrounds With Transparency以获取更多信息和一些简单的解决方案。
您应该尊重Swing的线程策略并在GUI线程上初始化GUI:
SwingUtilities.invokeLater(() -> new OpacityBug());
我无法分辨这是否只是纠正你身边的行为,但它已经完成了我的(OS X)。
我不能强调这一点,我看到很多人没有这样做,而确保Swing的正确行为至关重要;所有GUI实例必须在EDT上运行(事件调度线程)
请阅读以下文章并调整您的代码并报告效果。
https://docs.oracle.com/javase/tutorial/uiswing/concurrency/dispatch.html
你应该在有问题的组件上使用setOpaque(false)
,并对所有父母做同样的事情!
例如,如果你在JList
'scrollPane'中有一个JScrollPane
'jList',整个东西都在JPanel
'jPanel'里面,你应该使用:
jList.setOpaque(false);
scrollPane.setOpaque(false);
scrollPane.getViewport().setOpaque(false);
jPanel.setOpaque(false);
是的,如果你有一个JScrollPane
,你应该将它的视口的不透明度设置为false。
这将防止具有透明背景的组件上的绘制问题。