4

次のコード、または一般的なメソッドをどのようにスレッド化するのか疑問に思いました。

public void run (){

    public void paint(Graphics g) {
        g.fillRect(20, 20, 20, 20);
        for (int i = 20; i < 1000; i++) {
            g.fillRect(20, i, 20, 20);
            Thread.sleep(10);
        }
    }
}

不正な式の開始エラーが発生したため、このコードのスレッドを作成できないことがわかりました。これは公正ですが、回避策がわかりません。

4

1 に答える 1

13

あなたが何をしているのか見分けるのは難しいです、

paint()しかし、メソッドRunnable内からをオーバーライドしようとしているようです。run()

これは確かにできません。

論理は

  • コンポーネントを取る
  • ペイントメソッドをオーバーライドして、必要なものを描画します
  • メソッドを呼び出して長方形の座標を更新します(またはこの場合、タイマーがそれを行います)
  • コンポーネントを呼び出すrepaint()よりも、ペイントメソッドを再度呼び出して、新しい座標で長方形を再描画できます(タイマーは、長方形の座標を変更した後の再ペイントも処理します)
  • 最後の2つのステップを必要な回数/必要な回数繰り返します

(私が実際に意味するコンポーネントと言うとき、これがベストプラクティスであるためJPanelペイント方法はオーバーライドされることを指します。)paintComponent(..)JPanel

いくつかの提案:

1)オーバーライドするのpaintではなく、を使用JPanelしてオーバーライドしますpaintComponent

2)意図的に除外しない限り、ペイントチェーンを尊重し、オーバーライドされた(またはその事実のためのオーバーライドされたメソッド)super.XXXの実装を呼び出すことを忘れないでください。paintComponent(Graphics g)すなわち

class MyPanel extends JPanel {
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

         //do drawings here
    }
}

3)描画する場合は、通常、の内容/描画に適合するspaintComponentをオーバーライドgetPreferredSize()して返す必要があります。つまり、次のようになります。DimensionJPanel

class MyPanel extends JPanel {
    @Override
    public Dimension getPreferredSize() {
         return new Dimension(300,300);
    }
}

3)GUIスレッドをブロックする代わりに見て、フリーズSwing Timerしているように見せます。すなわちThread.sleep(..)sleep

Timer t = new Timer(10, new AbstractAction() {
    int count = 20;
    @Override
    public void actionPerformed(ActionEvent ae) {
        if (count < 1000) {
            //increment rectangles y position
            //now repaint container so we can see changes in co-ordinates (unless you have a timer which repaints for you too)
            count++;
        } else {//counter is at 1000 stop the timer
            ((Timer) ae.getSource()).stop();
        }
    }
});
t.start();

Rectangle4) Swingタイマーの代替(今のところSwingコンポーネントではないaのみを移動していることがわかります)はです。これは、Swingコンポーネントがそのメソッド内から作成/操作されないTimerTask限り使用できます( SwingTimerのようなEDTでは実行されません)。に注意してください。スレッドセーフであるため、内で使用できます。run()TimerTaskrevalidate()repaint()TimerTask

上記の利点は、EDTの不要なコードが保持されることです(つまり、座標を変更してAWT長方形を移動する)。

    final TimerTask tt = new TimerTask() {
        @Override
        public void run() {
            if (count < 1000) {
               //increment rectangles y position
                //now repaint container so we can see changes in co-ordinates (unless you have a timer which repaints for you too)
            count++;
            } else {//counter is at 1000 stop the timer
                cancel();
            }
        }
    };

    new Timer().scheduleAtFixedRate(tt, 0, 10);//start in 0milis and call run every 10 milis
于 2012-12-28T17:00:34.240 に答える