3

我有以下代码。基本上我有一个有背景图像的框架。我在框架内还有三个面板:面板 1、2 和 3。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));

         }

    }

}

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

4

2 回答 2

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用于“绘制组件”,而不是更改其属性。

于 2012-11-28T16:20:15.363 回答
2

我决定以一种非常不同的方式来解决这个问题。我就是这样做的。我用我的代码完全从头开始。我创建了一个 JFrame 实例和一个 Canvas 实例(画布是子类)。在画布中,我使用 drawImage() 来应用背景图像。然后,对于我想在背景图像上设置动画的三个区域中的每一个,我没有创建三个 JPanel,而是简单地在画布中使用 fillRect() 来填充图像上的正确区域。就是这样。很好很简单。repaint() 每秒都会在三个区域上闪烁,这是下一个挑战。我猜我必须使用双缓冲,但这不是我以前用过的东西,所以我接下来会研究一下。反正,使用单个画布代替三个 JPanel 证明要简单得多,我能够这样做的原因是因为背景图像提供了视觉上的所有其他内容。我所要做的就是drawImage() 和fillRect()。感谢所有的贡献。

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

于 2012-11-29T12:50:57.927 回答