2

AWT を使用して簡単なゲームを作成しようとしていますが、ゲームを終了/リセットするためにいくつかの JButtons も必要です。問題は、 BufferedImage を可視フレーム内に描画するようにしたいので、コンテナの最後にこれがあります:

g.drawImage(bf,getParent().getInsets().left,getParent().getInsets().top,null);

私の問題は、そのフレームに JButton を追加すると、オフセットを考慮していない空間でのロールオーバーのみを検出しますが、オフセットを考慮した空間で描画されます。これは関連するコードです (con はコンテナーです)。

    private void addButtons()
{
    reset = new JButton("reset");
    reset.setBounds(180,460, 75,30);
    reset.addActionListener( this );
    con.add(reset);
    exit = new JButton("exit");
    exit.setBounds(290,460, 60,30);
    exit.addActionListener( this );
    con.add(exit);
    con.repaint();
}

コンテナ内のペイント方法

public void paint(Graphics g)
{
    bf = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_RGB);
    Graphics b = bf.getGraphics();
    b.setColor(Color.GRAY);
    b.fillRect(0, 0, this.getWidth(), this.getHeight());
    b.setColor(Color.BLACK);
    b.drawRect(0,0,420,420);
    super.paint(b);
    g.drawImage(bf,getParent().getInsets().left,getParent().getInsets().top,null);
}

ボタンを同じ場所に描画して検出するにはどうすればよいですか?

ここに問題のスクリーンショットがあります

リクエストに応じて:

import java.awt.*;
import javax.swing.*;
import java.util.*;
import java.awt.image.*;
import java.awt.event.*;
import java.awt.Color;
public class Draw implements ActionListener{
private SnakeFrame frame;
private SnakeCon con;
JButton reset, exit;
private boolean res;
public Draw() 
{
    frame = new SnakeFrame("Snake");
    frame.setResizable(false);
    frame.setLayout(null);
    frame.setSize(600,600);
    frame.setVisible(true);
    con = new SnakeCon();
    con.setBounds(0,0,600,600);
    frame.add(con);
}

private void addButtons()
{
    reset = new JButton("reset");
    reset.setBounds(180,460, 75,30);
    reset.addActionListener( this );
    con.add(reset);
    exit = new JButton("exit");
    exit.setBounds(290,460, 60,30);
    exit.addActionListener( this );
    con.add(exit);
    con.repaint();
}
public void run()
{

    addButtons();
    res = false;
    boolean dead = false;       
    while(!dead)
    {
        if( (res) )
            dead = true;
        if (!dead)
        {
            try{
            Thread.sleep(100);
            }
            catch (Exception e)
            {}
            frame.repaint();
        }
    }
    con.removeAll();
}

public void actionPerformed(ActionEvent e)
{
    if (e.getSource() == reset)
    res = true;
else if (e.getSource() == exit)
    System.exit(0);
}
}

--

    import java.awt.*;
import javax.swing.*;
import java.util.*;
import java.awt.image.*;
import java.awt.event.*;
import java.awt.Color;
public class SnakeCon extends Container{
    private BufferedImage bf;

    public SnakeCon()
    {
        super();
        setBounds(0,0,600,600);
    }
    public void paint(Graphics g)
    {
        bf = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_RGB);
        Graphics b = bf.getGraphics();
        b.setColor(Color.GRAY);
        b.fillRect(0, 0, this.getWidth(), this.getHeight());
        b.setColor(Color.BLACK);
        b.drawRect(0,0,420,420);
        super.paint(b);
        g.drawImage(bf,getParent().getInsets().left,getParent().getInsets().top,null);
    }
    public void update(Graphics g)
    {
        paint(g);
    }
    }

--

    import java.awt.*;
import javax.swing.*;
import java.util.*;
import java.awt.image.*;
import java.awt.event.*;
import java.awt.Color;
public class SnakeFrame extends Frame implements WindowListener{
    private BufferedImage bf;

    public SnakeFrame(String s)
    {
        super(s);
        addWindowListener( this );
    }
    public void paint(Graphics g)
    {

        bf = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_RGB);
        Graphics b = bf.getGraphics();
        super.paint(b);
        g.drawImage(bf,0,0,null);
    }
    public void update(Graphics g)
    {
        paint(g);
    }

    public void windowClosing(WindowEvent e) 
    {
            System.exit(0);
    }

    public void windowClosed(WindowEvent e) {    }

    public void windowOpened(WindowEvent e) {    }

    public void windowIconified(WindowEvent e) {    }

    public void windowDeiconified(WindowEvent e) {    }

    public void windowActivated(WindowEvent e) {    }

    public void windowDeactivated(WindowEvent e) {    }
    }

--

public class Main {
public static void main(String[] args) 
{
    boolean never = false;
    Draw d = new Draw();
    while(!never)
    {
        d.run();
    }
    System.exit(0);
}
}
4

1 に答える 1

1

何が間違っているのか、何が必要なのか正確にはわかりません(ボタンを常に描画して呼び出すループがあるのはなぜremoveAll()ですか?などですが、より読みやすく効率的な方法で実装される可能性があるという感覚を揺るがすことはできません)...

ただし、コードを改善するのに役立ついくつかの提案を以下に示します。

  • 使用しないでくださいnull/Absoluteレイアウトは適切なものLayoutManagerを選択してください。

  • オーバーライドしないでください。JFrame paint(..)むしろ、そこに追加JPanelJFrameてオーバーライドしpaintComponent(Graphics g)JPanelそこに描画してください。super.paintComponent(..)paintComponent

  • JFrameすべてのコンポーネントを追加する前に可視に設定しないでくださいJFrame

  • Event Dispatch Thread常に次のように Swing コンポーネントを作成して操作します。

     SwingUtilities.invokeLater(new Runnable() {
          @Override
          public void run() {
             //create Swing components
         }
     });
    
  • Swing Timer / Swing WorkerEvent Dispatch Threadを使用する代わりに、長時間実行されるタスクを実行しないでください

  • 可視に設定する前にon を呼び出すよりも、すべてのコンポーネントに適合する s をオーバーライドして返すのではなく (推論についてはこちらsetSize(..)を参照)、 onを呼び出さないでください。JFramegetPreferredSize()JPanelDimensionpack()JFrame

  • JFrame不必要に拡張しないでContainerください。

  • WindowListener終了を検出するために追加することJFrameは、次の行を使用する価値はありません。

    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    

Xが押されたときにSwingアプリケーションを終了します。

于 2012-12-05T18:56:46.277 に答える