3

私はここで新しいです。お役に立てれば幸いです。

問題: JFrame でアニメーションを表示する際の問題。Javaのグラフィックがどのように機能するかを十分に理解していない/見逃しているようです。

全体的な考え: ゲーム/映画/クリップを作りたいとしましょう。このためには、この (ない) 単純なアニメーションが機能する必要があります。

この質問の例: クラス Screen を取得しました。このクラスには、JFrame の画面宣言があり、その構成 (サイズ、閉じる操作など) を設定してから、フレームに表示されるクラス Box のオブジェクトを作成します。クラスのこの画像/図を確認してください(正しい方法で書いたことを願っています):ClassesDiagram

現在、クラス Box は JPanel を拡張しています。JPanel からメソッド Paint() を継承してオーバーライドし、ボックスをペイントします。

Screen クラスでは、2 つのボックスを作成した後、それらを JFrame に .add() します。次にループ while(true) を開始し、200 ミリ秒ごとにスレッドをスリープさせてボックスの位置を更新します。(この場合、単純な x++ または y++ は、ボックス 1 またはボックス 2 に依存します)。

主な問題 1):プログラムが実行され、JFrame が表示されますが、JFrame では、最後に追加されたオブジェクト/コンポーネント ボックスのみが表示されます。もう一方は表示されません。なんで?

「 JFrame に複数のコンポーネントを追加する方法」というトピックを見つけました。、そして最も投票された投稿が与えたヒントを試してみました.jjnguy 15年11月. 奇妙な理由で、最初のヒントでも2番目のヒントでもうまくいきませんでした。

主な問題 2):私の知る限り、レイアウト マネージャーが必要です。フレームの特定の X、Y で paint() したいだけなのに、なぜそれが必要なのですか?

他の投稿を見つけました(もう一度見つけることはできません)+レイアウトに関するOracleのガイドラインは、 setLayout(null); の使用を検討する必要があることを示唆しています。そうしようとしましたが、再び問題が発生しました。

主な問題 3): JFrame が表示され、ボックスが 1 つしか表示されず (緑色のボックスは表示されません。何をしても表示されません。理由はわかりません)、移動すると、反対側から消去されます。ここ:箱の動き

ヘルプ、ヒント、説明をよろしくお願いします。投稿が明確で、整理され、見栄えが良いことを願っています。


public class Screen {

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

private JFrame window;

public Screen() {
    window = new JFrame("Multiply components panel");
    //window.setLayout(null);
    window.setSize(200, 200);

    window.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

    Box b1 = new Box(10,10, "box1");
    //b1.setBounds(10, 10, 50, 50);

    Box b2 = new Box(100,100, "box2");
    //b2.setBounds(100, 100, 50, 50);


    window.add(b1);
    //window.add(b2);


    window.setVisible(true);

    while (true){

        b1.update();
        b2.update();

        try {
            Thread.sleep(200);
        } catch (Exception e) {
            // TODO: handle exception
        }
    }

}
}

public class Box extends JPanel{

int x, y, w, h;
private String name;

public Box(int x, int y, String name) {
    this.x = x;
    this.y = y;
    this.w = 100;
    this.h = 100;
    this.name=name;
}


public void paint(Graphics g){
    System.out.println(this.name.equalsIgnoreCase("box1"));
    if(this.name.equalsIgnoreCase("box1")){
        g.setColor(Color.BLACK);
        g.fillRect(x, y, w, h);
    }else{
        g.setColor(Color.GREEN);
        g.fillRect(x, y, w, h);
    }


}


public void update() {
    if(this.name.equalsIgnoreCase("box1"))
        x++;
    else
        y++;
    //this.setBounds(x, y, w, h);
    System.out.println("Current "+name+": X: "+x+", Y: "+y+", W: "+w+", H: "+h);
    repaint();
}

}
4

2 に答える 2

3

主な問題 1): プログラムが実行され、JFrame が表示されますが、JFrame では、最後に追加されたオブジェクト/コンポーネント ボックスのみが表示されます。もう一方は表示されません。なんで?

そうし window.add(b1); window.add(b2);ます。デフォルトでJFrameBorderLayout、最後に追加したボックスを置き換えることになりますadd(..)

主な問題 2): 私の知る限り、レイアウト マネージャーが必要です。フレームの特定の X、Y で paint() したいだけなのに、なぜそれが必要なのですか?

JPanels をゲーム内のオブジェクトとして使用している場合は、 s の配置をsetLayout(null)完全に制御したいため、これを使用するのはこれだけです。JPanel

主な問題 3): JFrame が表示され、ボックスが 1 つしか表示されず (緑色のボックスは表示されません。何をしても表示されません。理由はわかりません)、移動すると、反対側から消去されます。ここ:箱の動き

あなたはこれをするのでg.fillRect(x,y,w,h)、そうあるべきですg.fillRect(0,0,w,h)

その他の問題:

1)あなたが抱えている大きな問題はここにあると思います:

public class Box extends JPanel{

    ...

    public void paint(Graphics g){

       ...
    }

}

をオーバーライドpaintComponentし、オーバーライドされたメソッドの最初の呼び出しとしてJPanel呼び出すことを忘れないでください。super.paintComponent(g)

3)のイメージまたはコンテンツに一致する正しい寸法をオーバーライドgetPreferredSizeして返す必要があります。JPanelJPanel

4)可視に設定する前に呼び出すsetSizeよりも、必要なコンテナーのJFrame正しい使用Layoutmanagerおよび/またはオーバーライドを呼び出さないでください。getPreferredSizepack()JFrame

5)@MadProgrammerが言ったように、Swingの同時実行SwingUtilities.inokeXXX性について読んでいますが、基本的にすべてのSwingコンポーネントは、ブロックを介してEDTで作成/操作する必要があります。

6)これを行うことは明らかに悪いです:

while (true){

    b1.update();
    b2.update();

    try {
        Thread.sleep(200);
    } catch (Exception e) {
        // TODO: handle exception
    }
}

連続ループを作成するだけでなく、Thread.sleepGUI を作成したスレッドを呼び出しているため、フリーズしているように見えます。How to use Swing Timersをご覧ください。また、上記のトピックに関するこの同様の質問の回答も参照してください。

上記の修正を実装したコードは次のとおりです。

ここに画像の説明を入力

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class Screen {

    private JFrame window;

    public static void main(String[] args) {

        //creat UI on EDT
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Screen();
            }
        });
    }

    public Screen() {
        window = new JFrame("Multiply components panel") {
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(600, 400);
            }
        };

        window.setLayout(null);//only reason this is warrented is because its a gmae using JPanels as game objects thus we need full control over its placing
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//changed from DISPOSE to EXIT so Timers  will be exited too

        final Box b1 = new Box(10, 10, 50, 50, "box1");

        final Box b2 = new Box(100, 100, 50, 50, "box2");

        window.add(b1);
        window.add(b2);

        window.pack();
        window.setVisible(true);

        Timer timer = new Timer(200, new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                b1.update();
                b2.update();
            }
        });
        timer.setInitialDelay(0);
        timer.start();

    }
}

class Box extends JPanel {

    int x, y, w, h;
    private String name;

    public Box(int x, int y, int w, int h, String name) {
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
        this.name = name;
        setBounds(x, y, w, h);//let the Box class handle setting the bounds more elegant OOP
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        System.out.println(this.name.equalsIgnoreCase("box1"));
        if (this.name.equalsIgnoreCase("box1")) {
            g.setColor(Color.BLACK);
            g.fillRect(0, 0, w, h);
        } else {
            g.setColor(Color.GREEN);
            g.fillRect(0, 0, w, h);
        }
    }

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

    public void update() {
        if (this.name.equalsIgnoreCase("box1")) {
            x++;
        } else {
            y++;
        }
        this.setBounds(x, y, w, h);//set the new bounds so box may be updated
        System.out.println("Current " + name + ": X: " + x + ", Y: " + y + ", W: " + w + ", H: " + h);
        revalidate();
        repaint();
    }
}

最後に、チュートリアル/コード スニペットのGame Development Loop, Logic and Collision detection Java Swing 2D をご覧ください。

ゲーム ループ、ロジック、ピクセル衝突検出、アニメーション (つまり、複数のスプライト間で交換してスプライト セットのアニメーションを作成する) など、単純な 2D ゲームを開始するために必要なものがすべて揃っています。ゲーム エンティティ、つまり、クラスはオブジェクトを描画するために必要なすべての情報を保持します。IMO これがゲームの実行方法です。グラフィックが激しくなり、多くの JPanel が画面が全体的な FPS を確実に低下させるのではないかと疑問に思うかもしれません。

于 2013-06-28T21:47:09.227 に答える