Метод нанесения краски

Мне было интересно, как я буду использовать следующий код или просто метод в целом:

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);
        }
    }
}

Я обнаружил, что не могу создать поток этого кода, потому что получаю недопустимую ошибку начала выражения, что справедливо, но я не вижу способа обойти это.


person Nick Haughton    schedule 28.12.2012    source источник
comment
Вам не разрешено рисовать вне потока Gui. Вы не можете перенаправить рисунок во вторичный поток.   -  person MTilsted    schedule 28.12.2012


Ответы (1)


Трудно сказать, что ты делаешь,

но похоже, что вы пытаетесь переопределить 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) При рисовании в paintComponent обычно необходимо переопределить getPreferredSize() и вернуть Dimensions, которые соответствуют содержимому/рисункам JPanel, т.е.:

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

3) Посмотрите на Swing Timer вместо Thread.sleep(..), так как sleep заблокирует поток GUI и создаст видимость быть замороженным. то есть

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();

4) Альтернатива (потому что я вижу, что вы перемещаете только Rectangle, который не является компонентом Swing) на таймер Swing: TimerTask, и это можно использовать до тех пор, пока никакие компоненты Swing не будут создаваться/управляться из его метода run() (поскольку TimerTask не работает в EDT, как Swing Timer). Примечание. revalidate() и 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
person David Kroukamp    schedule 28.12.2012
comment
@NickHaughton Также см. этот аналогичный ответ, в котором используется один таймер Swing, чтобы перемещать мяч и впоследствии перекрашивать его контейнер, чтобы отразить изменения: stackoverflow.com/questions/14068472/ - person David Kroukamp; 28.12.2012