1

我尝试从 PNG 图片构建我的个人 JFrame。但是 Mac OSX 10.8 和 Windows 7 之间存在不同的行为。(我必须使用 JDK 6)

这是我的代码:

[...]

public Fenetre()
{

    this.setLocationRelativeTo(null);
    this.setUndecorated(true);
    this.setBackground(new Color(0,0,0,0));

    try {
        image = ImageIO.read(this.getClass().getResource("/Images/frame.png"));     
    } catch (IOException e) {
        e.printStackTrace();
    }

    this.setSize(image.getWidth(),image.getHeight());                
    this.setLayout(null);


    panel = new JPanel();
    JButton quit = new JButton("Quitter");
    panel.add(quit);
    Dimension size = panel.getPreferredSize();
    panel.setBounds(67, 45, size.width, size.height);

    this.add(panel);

    this.addMouseListener(this);
    this.addMouseMotionListener(this);
    this.setVisible(true);      

}

public void paint(Graphics g) {

    Graphics2D g2 =(Graphics2D) g;
    g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC)); // SRC_ATOP > Windows
    g2.drawImage(image, 0, 0, this);
    panel.update(panel.getGraphics());

}

[...]

Mac OSX 10.8 (AlphaComposite = SRC) 上的结果:

http://imageshack.us/photo/my-images/15/maczr.png/

然后,在 Windows 7 (AlphaComposite = SRC_ATOP) 上,在启动和移动它时,我可以看到:

http://imageshack.us/photo/my-images/16/windowsqu.jpg/

怎么做?

4

2 回答 2

5

您的代码不完整,但在我看来,您正在覆盖 JFrame 的 paint() 方法。你永远不应该这样做(除非你知道你在做什么并且你调用了 super.paint(..))!

如果要在框架中显示图像,则可以:

a) 将带有图像的 JLabel 添加到框架
b) 或通过覆盖 paintComponent() 方法在 JPanel 上进行自定义绘画,然后将面板添加到框架。

于 2013-02-04T00:15:30.490 回答
4

你不尊重油漆链

public void paint(Graphics g) {
    // You must call super.paint somewhere here...

    Graphics2D g2 =(Graphics2D) g;
    g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC)); // SRC_ATOP > Windows
    g2.drawImage(image, 0, 0, this);
    panel.update(panel.getGraphics());

}

你不应该打电话给Component#update.

    panel.update(panel.getGraphics());

这是由重绘管理器代表您调用的,它调用paint.

paint调用paintComponentpaintBorder并且paintChildren未能遵守绘制链意味着没有调用这些方法,它们非常重要

正如 camickr 所指出的,您永远不需要覆盖paint顶级容器的方法,例如JFrame.

相反,创建一个能够为您执行绘画的自定义组件并将其设置为框架内容窗格......

this.setLocationRelativeTo(null);
this.setUndecorated(true);
this.setBackground(new Color(0,0,0,0));

setContentPane(new FancyPaintPane());

pack();

FancyPaintPane

public class FancyPaintPane extends JPanel {

    private BufferedImage image;

    public FancyPaintPane() {
        try {
            image = ImageIO.read(this.getClass().getResource("/Images/frame.png"));
        } catch (IOException e) {
            e.printStackTrace();
        }

        setOpaque(false);
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(image.getWidth(), image.getHeight());
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g); //To change body of generated methods, choose Tools | Templates.
        Graphics2D g2 = (Graphics2D) g.create();
        g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC)); // SRC_ATOP > Windows
        g2.drawImage(image, 0, 0, this);
        g2.dispose();
    }
}

您也不应该在Graphics不恢复上下文的情况下修改上下文。这些是同一顶级容器内所有组件的共享资源。更好的方法是创建一个副本,您可以在完成后对其进行操作和处置...

您还试图在不先将组件标记为透明的情况下显示具有透明元素的组件。这会产生令人讨厌的油漆伪影。你应该称之为JComponent#setOpaque传递一个false值。

我也强烈建议您不要使用null布局。他们有一个讨厌的习惯,回来咬你。

用简单的例子更新

在此处输入图像描述

public class CirclePaneTest {

    public static void main(String[] args) {
        new CirclePaneTest();
    }

    public CirclePaneTest() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (Exception ex) {
                }

                CirclePane circlePane = new CirclePane();
                circlePane.setLayout(new BorderLayout());
                circlePane.addMouseListener(new MouseAdapter() {
                    @Override
                    public void mouseClicked(MouseEvent e) {
                        if (e.getClickCount() == 2) {
                            System.exit(0);
                        }
                    }
                });

                JLabel label = new JLabel("Look Ma, I'm a circle");
                label.setHorizontalAlignment(JLabel.CENTER);
                label.setVerticalAlignment(JLabel.CENTER);

                JFrame frame = new JFrame("Test");
                frame.setUndecorated(true);
                frame.setBackground(new Color(0, 0, 0, 0));
                frame.setContentPane(circlePane);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(label);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class CirclePane extends JPanel {

        public CirclePane() {
            setOpaque(false);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        protected int getRadius() {
            return Math.min(getWidth(), getHeight()) - 1;
        }

        @Override
        public Insets getInsets() {

            int radius = getRadius();
            int xOffset = (getWidth() - radius) / 2;
            int yOffset = (getHeight() - radius) / 2;
            Insets insets = new Insets(
                    radius / 6,
                    radius / 6,
                    radius / 6,
                    radius / 6);

            return insets;
        }

        @Override
        protected void paintComponent(Graphics g) {

            super.paintComponent(g);

            int radius = getRadius();
            int xOffset = (getWidth() - radius) / 2;
            int yOffset = (getHeight() - radius) / 2;

            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setColor(getBackground());
            g2d.fillOval(xOffset, yOffset, radius, radius);
            g2d.setColor(Color.GRAY);
            g2d.drawOval(xOffset, yOffset, radius, radius);
            g2d.dispose();

        }
    }
}

更新了 Java 7 的代码

应使用以下代码将框架设置为在 Java 6 下透明。

JFrame frame = new JFrame("Test");
frame.setAlwaysOnTop(true);
frame.setUndecorated(true);
try {
    Class<?> awtUtilsClass = Class.forName("com.sun.awt.AWTUtilities");
    if (awtUtilsClass != null) {

        Method method = awtUtilsClass.getMethod("setWindowOpaque", Window.class, boolean.class);
        method.invoke(null, frame, false);
    }

} catch (Exception exp) {
}
//frame.setBackground(new Color(0, 0, 0, 0));
frame.setContentPane(circlePane);
于 2013-02-04T00:28:15.507 回答