2014-11-21 3 views
2

Я использую Swing для создания небольшого GUI на Java. Все, что я пытаюсь сделать, это взять ArrayList из Circle s и нарисовать их. Я столкнулся с двумя проблемами:Рисовать и перемещать круг в Java

1) Мне нужно вызвать метод draw, прежде чем он начертит круг. Если я просто вызову свой метод draw, как только ничего не произойдет, я получу пустой рисунок. Если я вызову его в цикле, который выполняется менее 30 миллисекунд, он будет рисовать только первый из двух кругов, которые я хочу рисовать. Наконец, если я назову его более 30 миллисекунд, он рисует оба круга, которые я пытаюсь сделать.

и

2) Когда я двигаю один из кругов, я получаю «мерцание» на чертеже.

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

Вот мой GUI класс:

package gui; 

import draw.*; 
import java.util.List; 
import javax.swing.*; 

public class GUI extends JFrame { 
    private CirclePainter drawingBoard = new CirclePainter(); 

    public GUI() 
    { 
     setSize(500, 500); 
     this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 
     this.setVisible(true); 
     this.add(drawingBoard); 
     drawingBoard.setVisible(true); 
    } 

    public void draw(List<Circle> circles) 
    { 
     drawingBoard.paintComponent(drawingBoard.getGraphics(), circles); 
    } 
} 

мой CirclePainter класс

package gui; 

import draw.Circle; 

import javax.swing.*; 
import java.awt.*; 
import java.util.List; 

class CirclePainter extends JPanel 
{ 
    public void paintComponent(Graphics graphics, List<Circle> circles) 
    { 
     super.paintComponent(graphics); 
     for(Circle circle : circles) 
      graphics.fillOval(circle.getX(), circle.getY(), circle.getRadius() * 2, circle.getRadius() * 2); 
    } 
} 

EDIT: отредактированный некоторый код, так как это для школьного проекта. Остального кода должно быть достаточно для того, чтобы кто-то посетил в будущем, чтобы все еще понять вопрос.

ответ

4

Опираясь на свой код и предложения от Hovercraft Full Of Eels, небольшой шаг в правильном направлении, может быть приняты с этими изменениями к GUI и CirclePainter классов:

// GUI.draw 
public void draw(List<Circle> circles) 
{ 
// drawingBoard.paintComponent(drawingBoard.getGraphics(), circles); 
    drawingBoard.setCircles(circles); 
    drawingBoard.repaint(); 
} 


class CirclePainter extends JPanel 
{ 
// public void paintComponent(Graphics graphics, List<Circle> circles) 
// { 
//  super.paintComponent(graphics); 
//  for(Circle circle : circles) 
//   graphics.fillOval(circle.getX(), circle.getY(), circle.getRadius() * 2, circle.getRadius() * 2); 
// } 

    private List<Circle> circles; 

    public void setCircles(final List<Circle> circles) { 
     this.circles = circles; 
    } 

    @Override 
    protected void paintComponent(final Graphics graphics) { 
     super.paintComponent(graphics); 
     for (Circle circle : circles) 
      graphics.fillOval(circle.getX(), circle.getY(), circle.getRadius() * 2, circle.getRadius() * 2); 
    } 
} 

Таким образом, вы не могли бы исправлены все основные вопросы, но вы получаете вашу программу для работы с небольшими изменениями. И Swing - очень хорошая библиотека, которая может быть очень интересной, чтобы узнать больше.

+0

Я думаю, что совет Eels был лучше ... но этот ответил на мой вопрос. Итак ... я выбираю тебя. Благодаря! – ThomYorkkke

+0

@ThomYorkkke: так что мое быстрое и грязное исправление выбрано из-за хорошего совета [Hovercraft Full Of Eels] (http://stackoverflow.com/users/522444/hovercraft-full-of-eels) ... Спасибо. Пожалуйста, взгляните на другие примеры (например, [Java Animate JLabel] (http://stackoverflow.com/a/12545773/1694043)), чтобы найти больше кода анимации и удачи в ваших кругах! –

+0

Это все о простом выходе ... :-D – ThomYorkkke

7
  1. Никогда вызов paintComponent(...) непосредственно, как вы делаете.
  2. Вместо этого предложите ничью, вызвав при необходимости repaint().
  3. Не рисовать с помощью объекта Graphics, полученного посредством вызова компонента getGraphics(). Вместо этого нарисуйте объект Graphics, указанный в методе paintComponent.
  4. Избегайте использования циклов while (true) в графическом интерфейсе Swing, поскольку вы рискуете связывать поток событий Swing и замораживать графический интерфейс. Используйте Swing Timer для простой анимации.
  5. Возможно, вам даже не нужен Swing Timer, так как ваша анимация может управляться вашим MouseListener/MouseMotionListener.
  6. Большинство важно - прочитайте рисунок Swing и другие учебники, так как большая часть этой информации может быть найдена там. Похоже, вы угадываете, как сделать некоторые из ваших кодировок, и это опасно, когда дело доходит до рисования или анимации графического интерфейса. Вы можете найти большинство руководств в ссылке Swing info.
  7. Рассмотрите возможность использования объекта Shape для представления вашего круга, например, ellipse2D. Причина, по которой это поможет, заключается в том, что у нее есть очень полезные методы, включая метод contains(Point p), который поможет вам определить, попадает ли щелчок мыши внутри вашего круга.
  8. Вам нужно будет решить, где _x и _y представляют центр центр вашего круга или нет. Если да, то вам нужно будет отрегулировать свой рисунок, переместив его влево и вверх на величину _radius.
  9. Рассмотрите возможность переноса объекта Graphics в объект Graphics2D, чтобы использовать его дополнительные методы и свойства.
  10. Одним из таких свойств является RenderingHings. Установите GraphicsSD для рендеринга Graphics2D, чтобы избежать сглаживания, чтобы избавиться от изображения «jaggies». Это можно сделать с помощью: g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);, где g2 - ваш объект Graphics2D.
  11. Ваш метод paintComponent не является истинным элементом paintComponent и, следовательно, будет работать неправильно. Это должен быть метод protected, а не public, он должен иметь один параметр, объект Graphics и второй параметр, и вы должны разместить над ним примечание @Override.

Например, пожалуйста, взгляните на this answer на аналогичную проблему.

Пример метода paintComponent, что центры окружностей на _x и _y и использует рендеринга подсказки:

class CirclePainter extends JPanel implements Iterable<Circle> { 
    private static final int PREF_W = 500; 
    private static final int PREF_H = PREF_W; 
    private CircleList circleList = new CircleList(); 

    @Override 
    protected void paintComponent(Graphics graphics) { 
     super.paintComponent(graphics); 
     Graphics2D g2 = (Graphics2D) graphics; 
     g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
      RenderingHints.VALUE_ANTIALIAS_ON); 
     for (Circle circle : circleList) { 
     // if x and y are the center points, then you must subtract the radius. 
     int x = circle.getX() - circle.getRadius(); 
     int y = circle.getY() - circle.getRadius(); 
     int width = circle.getRadius() * 2; 
     int height = width; 
     g2.fillOval(x, y, width, height); 
     } 
    } 
+0

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

+0

@FreekdeBruijn: да, эксперимент всегда хорош, но по моему опыту что-то вроде графики Swing ** так ** встречно-интуитивно, большинство из нас, включая меня, ошибаются. Здесь вы должны получить руководство от учебников, чтобы двигаться вперед. Один плюс за голосом за ваш ответ. –

+0

Согласен, очень легко нарисовать себя в углу этим типом экспериментов с графикой Swing. Тем не менее, иногда сложно инвестировать много часов обучения, когда вы пытаетесь построить что-то маленькое. –

Смежные вопросы