3

次のコードがあります。基本的に、背景画像を持つフレームがあります。また、フレーム内に 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));

         }

    }

}

更新: 問題が見つからない場合は、次の別の方法を教えてください。背景画像と背景画像の上に 3 つのパネルがあるフレームが必要です。3 つのパネルが正しく表示されるようにするには、背景画像上でピクセル パーフェクトな位置とサイズが必要です。それはほとんどそれです。3 つのパネルを再描画しますが、背景画像は同じままです。

4

2 に答える 2

2

私は非常に異なる方法で問題に取り組むことにしました。これが私がやった方法です。私は自分のコードで完全にゼロから始めました。JFrameインスタンスとCanvasインスタンスを作成しました(キャンバスはサブクラス化されていました)。キャンバスでは、drawImage()を使用して背景画像を適用しました。次に、背景画像でアニメーション化する3つの領域のそれぞれについて、3つのJPanelを作成する代わりに、キャンバス内でfillRect()を使用して、画像の適切な領域を塗りつぶしました。それでおしまい。素晴らしくてシンプル。毎秒repaint()は、3つの領域でflickrを実行します。これが、次の課題です。ダブルバッファリングを使用する必要があると思いますが、以前は使用したことがないので、次に調べます。ともかく、3つのJPanelの代わりに1つのキャンバスを使用すると、非常に簡単であることがわかりました。それができた理由は、背景画像が他のすべてを視覚的に提供していたためです。私がしなければならなかったのはdrawImage()とfillRect()だけでした。すべての貢献に感謝します。

更新:これでこのタスクは完了しました。上記について私が変更したことが1つありました。Canvasでダブルバッファリングを試みているときに、いくつかの問題が発生しました。通常の「コンポーネントには有効なピアが必要」という例外があります。それを調べているうちに、SwingでCanvasを使用すべきではないこと、そしてそれを使用する方法はAWTとSwingを混合することであることがわかりました。そこで、JComponentと交換しました(JPanelが提供するものは何も必要なかったため)。そして、Swingはデフォルトでダブルバッファリングされているので、私の作業は完了しました。ちらつきや簡略化されたコードはありません。

于 2012-11-29T12:50:57.927 に答える
2

問題は、適切なを使用していないことですLayoutManager

JLabelLayoutManagerデフォルトでは何も付属していません。したがって、を追加する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 に答える