3

画面にボールを描画し、実行ボタンが押されたときにボールが端で跳ね返るアプレット インターフェイスがあります。他にも機能がありますが、機能するにはこの最初の機能が必要です。現在実行を押しても何も起こりません。オブジェクトを正しく描画しているとは思いません。私はSystem.err.println()周りにステートメントを入れており、コンソールをチェックすると、ボタンがクリックされたときにプログラムが正しいメソッドに移動します。オブジェクトを描画する必要があるメソッドの何が問題なのかわかりません。

コードは 500 行近くありますが、必要に応じてこの本文に貼り付けます。ここにあります:http://ideone.com/JL0B2

4

1 に答える 1

1

まず、ペイントをオーバーライドする必要がdrawingpanelあります。これは、円を描く場所です。現在、円はコンポーネントの上にペイントされているため、実行ボタンを押したときにのみ表示されます。
通常の描画中に、アプレット領域が描画され (これが現在のpaint作業場所です)、追加したすべてのコンポーネントが、既に描画されたドットの上に描画されます。

プログラムの先頭dotnullであるため、ペイントはそれを正しく描画できません。NullPointerException がスローされます。

Graphics インスタンスを「キャッシュ」する必要はありません。ペイントで提供される Graphics を常に使用してください。

円を移動する場合は、値を更新してから の再描画をスケジュールするように、別のスレッドを作成する必要がありますdrawingpanel
また、アプレット全体を再描画する必要はなく、drawingpanel.

それでも助けが必要な場合は、コメントで質問してください。

編集:

drawingpanelドットが描かれている場所は次のとおりです。

    Panel drawingpanel = new Panel() {
        public void paint(Graphics g) {
            if (dot == null) {
                return;
            }
            g.drawOval(dot.leftOf(), dot.topOf(), dot.widthOf(), dot.heightOf());
            g.fillOval(dot.leftOf(), dot.topOf(), dot.widthOf(), dot.heightOf());
        };
    };

また、アプレットはメソッドBounceをオーバーライドしません。paint()

アニメーションを実装するRunnableには、セクションにインターフェイスを追加しますimplements
別のフィールドを追加します。

    volatile boolean running = false;
    private Thread animationThread;

それでは、簡単なアニメーションを実装しましょう。

    public void run() {
        while (running) {
            if (!showtails) {
                dot.setColor(drawingpanel.getBackground());
            }
            update();// check if speed, size, or shape changed
            draw();// draw next dot based on move(), or initial condition
            pause();
            move();// calculate and prepare the coordinates for the next
                   // iteration to be drawn
        }
    }

    public void draw() {
        drawingpanel.repaint();
    }

    public void pause() {
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void move() {
        dot.left--;
        dot.top--;
    }

最後の詳細はアクション ハンドラです。

    public void actionPerformed(ActionEvent e) {
        Object source = e.getSource();

        if (source == this.runbutton) {
            running = !running;
            if (animationThread == null) {
                animationThread = new Thread(this); 
            }

            if (running) {
                dot = new CircDot(100, 100, sizebar.getValue(), Color.RED);
                animationThread.start();
            }
        } else
            ...
    }

仕組みは次のとおりです。アクション ハンドラーで実装が開始さrun()れ、コントロールが EDT に返されなかったため、アプリケーションがハングしたように見え、メッセージの処理が停止しました。

[実行] ボタンをクリックすると、状態フィールドrunningが反転し、新しいスレッドがまだ開始されていない場合は作成されます。スレッドはrun()メソッドを実行します。したがって、whilebody内のアクションは、にrunningなるまで実行されますfalse

  • ペイント操作をスケジュールするrepaint()上でdraw メソッドを呼び出します。drawingpanelメッセージ キューが空になると、システムはそのpaintメソッドを呼び出してパネルを再描画します。
  • 一時停止メソッドを呼び出しThread.sleep(500)て、500 ミリ秒間実行を停止します。数字が小さいほど、ドットは速く移動します。ここでの値は、何らかの形で速度に依存します。loop を使用して一時停止を実装しないでください。プロセッサの時間を浪費するだけで、どれだけの時間がかかるかを予測できません。
  • move は減少topleft、ウィンドウの左上隅に移動するようにドットの座標を調整します。

フィールドは他の同期手段なしで複数のスレッドからアクセスされるため、runningが宣言されていることに注意してください。volatileそこにない場合、実行中のアニメーションは、アクション ハンドラーの EDT からの変更を認識しない可能性があります。

于 2012-10-15T16:35:20.883 に答える