为什么paintComponent永远不会被调用?

时间:2012-11-28 16:11:46

标签: java linux swing paintcomponent

我有以下代码。基本上我有一个有背景图像的框架。框架内还有三个面板:面板1,2和3。因为我没有将它们分类,所以工作正常。但是,面板1一旦我将其子类化,即将逻辑放在JPanel的paintComponent方法中就停止工作,因为永远不会调用该方法,并且永远不会打印foo。我无法弄清楚原因。非常感谢你的帮助。我尝试了其他类似线程的一些建议,但他们没有帮助。

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class Test {

    public static void main(String[] args) throws IOException {

        JFrame.setDefaultLookAndFeelDecorated(true);
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();

        int fooPanelX = 5;
        int fooPanelY = 160;
        int fooPanelWidth = 470;
        int fooPanelHeight = 305;

        int bar0PanelX = 5;
        int bar0PanelY = 550;
        int bar0PanelWidth = 230;
        int bar0PanelHeight = 210;

        int bar1PanelX = bar0PanelX * 2 + bar0PanelWidth + bar0PanelX;
        int bar1PanelY = bar0PanelY;
        int bar1PanelWidth = bar0PanelWidth;
        int bar1PanelHeight = bar0PanelHeight;

        JPanel panel1 = new Panel1(fooPanelX, fooPanelY, fooPanelWidth, fooPanelHeight);

        JPanel panel2 = new JPanel();
        panel2.setBackground(Color.WHITE);
        panel2.setLocation(bar0PanelX, bar0PanelY);
        panel2.setSize(bar0PanelWidth, bar0PanelHeight);
        panel2.setOpaque(false);
        panel2.setBorder(BorderFactory.createLineBorder(Color.WHITE));
        panel2.setBounds(bar0PanelX, bar0PanelY, bar0PanelWidth, bar0PanelHeight);

        JPanel panel3 = new JPanel();
        panel3.setBackground(Color.WHITE);
        panel3.setLocation(bar1PanelX, bar1PanelX);
        panel3.setSize(bar1PanelWidth, bar1PanelHeight);
        panel3.setOpaque(false);
        panel3.setBorder(BorderFactory.createLineBorder(Color.WHITE));
        panel3.setBounds(bar1PanelX, bar1PanelY, bar1PanelWidth, bar1PanelHeight);

        JLabel imagePanel = new JLabel(new ImageIcon(ImageIO.read(new File("image.png"))));

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.addKeyListener(new KeyAdapter() {

            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode() == 27) {
                    System.exit(0);
                }
            }

        });

        frame.setContentPane(imagePanel);
        frame.getContentPane().add(panel1);
        frame.getContentPane().add(panel2);
        frame.getContentPane().add(panel3);
        frame.setLocation((int) (screenSize.getWidth() * 0.75),
                (int) (screenSize.getHeight() * 0.25));
        frame.pack();
        frame.setVisible(true);

    }

    @SuppressWarnings("serial")
    static class Panel1 extends JPanel {

        int x, y, w, h;

        public Panel1(int x, int y, int w, int h) {
            this.x = x;
            this.y = y;
            this.w = w;
            this.h = h;
        }

        @Override
        public void paintComponent(Graphics graphics) {

            System.out.println("foo");
            super.paintComponents(graphics);

            setBackground(Color.WHITE);
            setLocation(x, y);
            setSize(w, h);
            setOpaque(true);
            setBorder(BorderFactory.createLineBorder(Color.WHITE));

         }

    }

}

更新:如果您无法找到问题,那么请您提供另一种方法来执行以下操作。我需要一个带背景图像的框架和背景图像顶部的三个面板。这三个面板必须在背景图像上具有像素完美的位置和尺寸才能看起来正确。这就是它。我将重新绘制三个面板,但背景图像将保持不变。

2 个答案:

答案 0 :(得分:2)

嗯,问题是你没有使用合适的LayoutManager

默认情况下,

JLabel不附带任何LayoutManager。因此,当您添加Panel1时,它的大小为0x0并位于(0,0)中,因为没有LayoutManager会更改它,它将保留该大小和位置。对于空边界,您的组件永远不会被绘制,因此永远不会调用paintComponent方法。

现在,你永远不应该在paintComponent

中这样做
        setBackground(Color.WHITE);
        setLocation(x, y);
        setSize(w, h);
        setOpaque(true);
        setBorder(BorderFactory.createLineBorder(Color.WHITE));

在构造函数或其他方法中执行此操作。 paintComponent用于“绘制组件”,而不是更改其属性。

答案 1 :(得分:2)

我决定以一种非常不同的方式解决问题。这就是我做到的。我用我的代码完全从头开始。我创建了一个JFrame实例和一个Canvas实例(画布是子类)。在画布中我使用drawImage()来应用背景图像。然后,对于我想在背景图像上设置动画的三个区域中的每一个,而不是创建三个JPanel,我只是在画布中使用fillRect()来填充图像上的右侧区域。而已。很好,很简单。每一秒的重绘()会对三个区域进行闪烁,这就是下一个挑战。我猜我必须使用双缓冲,但这不是我以前用过的东西,所以接下来我会调查一下。无论如何,使用单个画布代替三个JPanels证明了更简单,我之所以能够做到这一点的原因是因为背景图像提供了其他所有视觉效果。我所要做的就是drawImage()和fillRect()。感谢您的所有贡献。

更新:我现在已完成此任务。关于上述事情我改变了一件事。在尝试使用Canvas加倍缓冲时,我遇到了一些问题:通常的“组件必须具有有效的对等”异常。在研究的过程中,我了解到不应该在Swing中使用Canvas,并且使用它的做法是混合AWT和Swing。所以我把它换成JComponent(因为我不需要JPanel提供的任何东西)。由于Swing默认是双缓冲的,我的工作已经完成。没有闪烁和简化的代码。