更改Swing窗口的底层背景颜色

13

正如在这里讨论的那样,当在Vista(我正在使用的Windows 7也是如此)中调整Swing应用程序的大小时,您会在右下角看到黑色背景,同时Swing的重绘会追赶变化。

通过使用其他应用程序(Windows资源管理器(Native)、Firefox(C++?)和Eclipse(Java)),我注意到它们都有同样的问题 - 与上面链接中的人们所说的相反 - 但是它们通过具有灰色填充颜色来最小化问题,这比出现在Swing中的黑色要少得多视觉上炫目。

我想知道是否有某种方法可以改变这种情况,使Swing表现得像这些其他应用程序一样? 我尝试设置JFrame的背景颜色,但无济于事。

额外信息 Jonas发现(请参见他们下面的详细答案)这是JFrames的问题,而不是AWT Frames的问题 - 也许这会帮助某人解决这个问题。


你能给一个快速的代码片段吗? - bragboy
@Bragaadeesh:你可以运行我回答中的代码。 - Jonas
@Jonas:是的,我明白了,这有点奇怪,我一直在使用Swings工作,但没有注意到它。我想我有一两个替代方案,会尝试解决这个问题。顺便说一句,好问题,+1。 - bragboy
3个回答

3
我注意到了同样的问题。在IE中,这个颜色是灰色的,在Opera中是黑色的,在Eclipse中是灰色的。它在Swing中似乎更加明显,因为它在重绘时似乎要慢一些,而且颜色正如你所说的黑色。如果您使用左上角进行调整大小,则此问题更加明显。
我编写了一个示例并尝试理解这个黑色颜色的定义。JFrame有许多层级,因此我在每个层上设置了不同的背景。
import java.awt.Color;
import javax.swing.JFrame;

public class BFrame {

    public static void main(String[] args) {
        new JFrame() {{
            super.setBackground(Color.CYAN);
            this.getRootPane().setBackground(Color.BLUE);
            this.getLayeredPane().setBackground(Color.RED);
            this.getContentPane().setBackground(Color.YELLOW);
            this.setSize(400,340); 
            this.setVisible(true);
        }};
    }
}

但是这个例子没有帮助。也许颜色由一个超类设置为Frame
java.lang.Object
  java.awt.Component
      java.awt.Container
          java.awt.Window
              java.awt.Frame

我的理论是,由于Swing自己绘制,但使用本地窗口,所以在调整大小之前绘制本地背景,调整大小后绘制Swing的背景。但对于本地应用程序,在调整大小之前绘制背景。

更新:现在我尝试使用 Frame,并且没有出现相同的问题。背景似乎是在调整大小之前绘制的。
import java.awt.Color;
import java.awt.Frame;

public class B2Frame extends Frame {

    public static void main(String[] args) {
        new Frame() {{
            setBackground(Color.YELLOW);
            setSize(400,340);
            setVisible(true);
        }};
    }

}

感谢您提供详细的答案并尝试了所有的方法。我想知道为什么会有这样的差异,是否有任何方法可以修复它。我想知道是否有任何方法可以设置JFrame本身的颜色(而不是getContentPane(),似乎只有它能起作用)。我刚刚尝试获取JFrame的图形对象并设置其颜色,但也没有起作用。您是否有任何想法,可能是默认的灰色背景在哪里设置的?也许这与此有关。 - dimo414
@dimo414:如果您跳过本地标题栏和边框,就可以摆脱这个问题。请参阅我的问题和答案:https://dev59.com/KHE85IYBdhLWcg3wbS_1#2781132 - Jonas
没错,我可以这样做,但是对我来说,那似乎是一个非常绕弯子的解决方案,而且,如果你原谅我的话,比我要寻找的更加复杂。特别是考虑到您发现Frame没有这个问题,我仍然想知道是否有一种方法可以在Swing中实现相同的功能,而不必完全放弃Windows Aero。 - dimo414
我相当确定Frame也有同样的问题,只是它重新绘制得更快,所以不太明显。在我处理的解决方案中,对于较小的内容,Frame调整大小几乎是瞬间完成的,但一旦内容增加一点,调整大小时黑色背景就肯定会出现。我认为这实际上是一个平台问题,因为Java与Aero的交互设置颜色时存在问题。 - Charles Goodwin

2

框架负责绘制其背景,因此您需要确保让它完成其工作。

您可以通过设置以下内容来证明:

System.setProperty("sun.awt.noerasebackground", "true");

这将导致在调整大小时背景始终为黑色(所以不要这样做)。以下是我使用的方法:
1.(仅限AWT)使用createBufferStrategy(2)设置双缓冲 - 在addNotify()中进行包装,否则在创建框架时会发生异常。(在Swing中,默认情况下是双缓冲的,因此步骤1仅适用于AWT。)
2.在Frame.paint()实现中始终(非常重要)调用super()
3.使用setBackground()设置背景颜色,然后在扩展框架时背景应始终是相同的颜色。
示例代码:
    class InnerFrame extends Frame {
        public void addNotify() {
            super.addNotify();
            // Buffer
            createBufferStrategy(2);           
            strategy = getBufferStrategy();
        }

        public void paint(Graphics g) {
            super(g);
            //...
        }
        //...
     }

有趣,谢谢。下次我在处理我的Swing项目时会尝试研究一下这个。 - dimo414
我还发现将ComponentListener添加到Frame的主要子组件似乎可以很好地解决调整大小的问题(添加到原始答案中)。 - Charles Goodwin
根据过去几个月修复此问题的解决方案进行了更新。 - Charles Goodwin
我已经好几个月没看过这个问题了,然后大约20分钟前我看了一下,然后你发了一个编辑 o_O 谢谢!今晚我在Windows机器上试试。 - dimo414
抱歉耽搁了,我尝试实现你回答中的代码片段,但据我所知它似乎没有任何作用。调用super.paint(g)很重要,是的,但即使您根本没有覆盖paint(),这个问题也会出现。而且setBackground()也没有立即影响。尝试运行Jonas在他的答案中发布的类,无论是扩展paint()还是实现ComponentListener都不会对黑色子背景产生任何影响。 - dimo414

1

我也注意到了这个问题。对我来说,通过更改布局管理器(之前我使用的是自由格式布局)来解决此问题并且效果很好(系统颜色绘制)。

但最终我还是回到了自由格式布局。一些知名应用程序也面临这个问题(例如SKYPE),但实际上我并不介意...


你有“自由格式布局”链接吗? - Jonas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接