2

私はそれが実行されるときにいくつかの非常に奇妙で望ましくない振る舞いをする次のプログラムを持っています。「開始」と「停止」の2つのボタンがあるはずですが、「開始」をクリックすると、「開始」のすぐ下に別のボタンが表示されます。これが私が話していることの印刷画面です。

ここに画像の説明を入力してください

私は何を間違っているのですか、そしてこの醜い問題をどのように修正しますか?

コードは次のとおりです。

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;

public class TwoButtonsTest {

    JFrame frame;
    Timer timer;
    boolean isClicked;

    public static void main(String[] args) {
    TwoButtonsTest test = new TwoButtonsTest();
    test.go();
    }

    public void go() {
    frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(500, 500);

    JButton startButton = new JButton("Start");
    startButton.addActionListener(new StartListener());
    JButton stopButton = new JButton("Stop");
        stopButton.addActionListener(new StopListener());

    final DrawPanel myDraw = new DrawPanel();

    frame.getContentPane().add(BorderLayout.CENTER, myDraw);
    frame.getContentPane().add(BorderLayout.NORTH, startButton);
    frame.getContentPane().add(BorderLayout.SOUTH, stopButton);


    frame.setVisible(true);

    timer = new Timer(50, new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent ae) {
            myDraw.repaint();
        }
        });
    }

    class StartListener implements ActionListener {
    public void actionPerformed(ActionEvent e) {
        //needs to be implemented
        if(!isClicked) {
        }
        isClicked = true;
        timer.start();
    }
    }

    class StopListener implements ActionListener {
    public void actionPerformed(ActionEvent e) {
        //needs to be implemented
        timer.stop();
        isClicked = false;
    }
    }

    class DrawPanel extends JPanel {
    public void paintComponent(Graphics g) {

        int red = (int)(Math.random()*256);
        int blue = (int)(Math.random()*256);
        int green = (int)(Math.random()*256);

        g.setColor(new Color(red, blue, green));

        Random rand = new Random();
        // following 4 lines make sure the rect stays within the frame
        int ht = rand.nextInt(getHeight());
        int wd = rand.nextInt(getWidth());

        int x = rand.nextInt(getWidth()-wd);
        int y = rand.nextInt(getHeight()-ht);

        g.fillRect(x,y,wd,ht);
    }
    } // close inner class
}

また、スタートボタンで2つのことを実行しようとしています。1つはもちろんアニメーションを開始することですが、停止ボタンを押してもう一度[開始]を押すと、いわば画面がきれいになり、アニメーションを新しく開始する必要があります。そのためのヒントはありますか?

4

3 に答える 3

4

ペイントチェーンを尊重し、他のコンポーネントのペイントを尊重するために必要なsuper.paintComponent(Graphics g)オーバーライドされたpaintComponent(..)メソッドを呼び出さないでください。

この呼び出しは、メソッド内の最初の呼び出しでもある必要があります。

@Override
public void paintComponent(Graphics g) {
     super.paintComponent(g);

    //do painting here
}  

図面が永続的ではないという問題が発生する可能性があります。図面を保存して毎回再描画する方法が必要です。最も一般的なのは、ArrayList描画するオブジェクトを保持するものです(したがって、リストに追加したり、削除したりすることはできません)。リストを繰り返し処理して、の各オブジェクトを再描画しますpaintComponent例については、ここで私の答えを参照してください。

  • また、イベントディスパッチスレッドでSwingコンポーネントを作成および操作することを忘れないでください。

    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
             //create UI and components here
        }
    });
    
  • 表示を設定する前に(ただし、すべてのコンポーネントを追加した後に)呼び出すsetSize(..)よりも、すべてのコンポーネントに適合する適切な高さをJFrameオーバーライドgetPreferredSize()して返すのではなく、呼び出しないでください。JPanelJFrame#pack()JFrame

  • getContentPane().add(..)Java 6以降では、add(..)デフォルトでcontentPaneを使用する必要はありません。

  • 再宣言しないでください。Randomつまり、呼び出されるRandom r=new Random()たびに値の分布がランダムでなくなり、クラスが作成されたときに一度開始してインスタンスのメソッドを呼び出すため、再宣言しないでください。paintComponent

修正されたコードは次のとおりです(上記の修正が実装されています)。

ここに画像の説明を入力してください

import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.*;

public class TwoButtonsTest {

    JFrame frame;
    Timer timer;
    boolean isClicked;

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                TwoButtonsTest test = new TwoButtonsTest();
                test.go();
            }
        });
    }
    final DrawPanel myDraw = new DrawPanel();

    public void go() {
        frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JButton startButton = new JButton("Start");
        startButton.addActionListener(new StartListener());
        JButton stopButton = new JButton("Stop");
        stopButton.addActionListener(new StopListener());


        frame.add(myDraw, BorderLayout.CENTER);
        frame.add(startButton, BorderLayout.NORTH);
        frame.add(stopButton, BorderLayout.SOUTH);


        frame.pack();
        frame.setVisible(true);

        timer = new Timer(50, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                myDraw.repaint();
            }
        });
    }

    class StartListener implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {
            //needs to be implemented
            if (!isClicked) {
            }

            myDraw.clearRects();

            isClicked = true;
            timer.start();
        }
    }

    class StopListener implements ActionListener {

        public void actionPerformed(ActionEvent e) {
            //needs to be implemented
            timer.stop();
            isClicked = false;
        }
    }

    class DrawPanel extends JPanel {

        private ArrayList<MyRectangle> rects = new ArrayList<>();
        private Random rand = new Random();

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);

            addRect();
            for (MyRectangle r : rects) {
                g.setColor(r.getColor());
                g.fillRect(r.x, r.y, r.width, r.height);
            }
        }

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

        public void clearRects() {
            rects.clear();
        }

        public void addRect() {
            // following 4 lines make sure the rect stays within the frame
            int ht = rand.nextInt(getHeight());
            int wd = rand.nextInt(getWidth());

            int x = rand.nextInt(getWidth() - wd);
            int y = rand.nextInt(getHeight() - ht);

            int red = (int) (Math.random() * 256);
            int blue = (int) (Math.random() * 256);
            int green = (int) (Math.random() * 256);

            rects.add(new MyRectangle(x, y, wd, ht, new Color(red, blue, green)));
        }
    } // close inner class
}

class MyRectangle extends Rectangle {

    Color color;

    public MyRectangle(int x, int y, int w, int h, Color c) {
        super(x, y, w, h);
        this.color = c;
    }

    public Color getColor() {
        return color;
    }
}
于 2012-12-11T15:28:39.450 に答える
3

私は解決策を提供できればいいのですが、まだ解決策を見つけていません。ここでの「問題」の根本は、BorderLayoutのCenterセクションを描画する方法にあります。このプログラムのpaintComponent()関数全体をオーバーライドし、作成したものをすべてBoarderLayoutの中央に配置します。この場合、ボタンをクリックするたびに、プログラムは再描画を呼び出してクリックされたボタンの画像を描画しますが、描画されたオブジェクトのいずれかを中央パネルに追加したため、そこにも描画されます。この特定の再描画は場所を指定しないため、左上隅に配置されます。

于 2012-12-11T16:14:06.647 に答える
2

SwingUtilitiesを呼び出して、WindowsXPコンピュータのボタンの問題を修正しました。

Javaコードをフォーマットしました。

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class TwoButtonsTest implements Runnable {

    JFrame frame;
    Timer timer;
    boolean isClicked;

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new TwoButtonsTest());
    }

    @Override
    public void run() {
        frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(500, 500);

        JButton startButton = new JButton("Start");
        startButton.addActionListener(new StartListener());
        JButton stopButton = new JButton("Stop");
        stopButton.addActionListener(new StopListener());

        final DrawPanel myDraw = new DrawPanel();

        frame.getContentPane().add(BorderLayout.CENTER, myDraw);
        frame.getContentPane().add(BorderLayout.NORTH, startButton);
        frame.getContentPane().add(BorderLayout.SOUTH, stopButton);

        frame.setVisible(true);

        timer = new Timer(50, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                myDraw.repaint();
            }
        });
    }

    class StartListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            // needs to be implemented
            if (!isClicked) {
            }
            isClicked = true;
            timer.start();
        }
    }

    class StopListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            // needs to be implemented
            timer.stop();
            isClicked = false;
        }
    }

    class DrawPanel extends JPanel {
        @Override
        public void paintComponent(Graphics g) {
            int red = (int) (Math.random() * 256);
            int blue = (int) (Math.random() * 256);
            int green = (int) (Math.random() * 256);

            g.setColor(new Color(red, blue, green));

            Random rand = new Random();
            // following 4 lines make sure the rect stays within the frame
            int ht = rand.nextInt(getHeight());
            int wd = rand.nextInt(getWidth());

            int x = rand.nextInt(getWidth() - wd);
            int y = rand.nextInt(getHeight() - ht);

            g.fillRect(x, y, wd, ht);
        }
    } // close inner class
}

スタートボタンを押したときに画面をクリーンアップするには、DrawPanelクラスにいくつかのメソッドを追加する必要があります。

これを行う1つの方法があります。

class DrawPanel extends JPanel {
        protected boolean eraseCanvas;

        public void setEraseCanvas(boolean eraseCanvas) {
            this.eraseCanvas = eraseCanvas;
        }

        @Override
        public void paintComponent(Graphics g) {
            if (eraseCanvas) {
                g.setColor(Color.WHITE);
                g.fillRect(0,  0, getWidth(), getHeight());
            } else {
                int red = (int) (Math.random() * 256);
                int blue = (int) (Math.random() * 256);
                int green = (int) (Math.random() * 256);

                g.setColor(new Color(red, blue, green));

                Random rand = new Random();
                // following 4 lines make sure the rect stays within the frame
                int ht = rand.nextInt(getHeight());
                int wd = rand.nextInt(getWidth());

                int x = rand.nextInt(getWidth() - wd);
                int y = rand.nextInt(getHeight() - ht);

                g.fillRect(x, y, wd, ht);
            }
        }
    } // close inner class
于 2012-12-11T14:58:39.507 に答える