2015-01-05 2 views
0

Я создаю приложение java, где я использую класс JComponent для рисования. У меня проблема с методом repaint(), не запускающим paintComponent(). Что может быть причиной этого?Repaint() не вызывает paintComponent() в классе JComponent

Код:

JComponent Класс:

import java.awt.Color; 
import java.awt.Graphics; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 

import javax.swing.JComponent; 
import javax.swing.Timer; 

public class Display extends JComponent implements ActionListener{ 

    private final static int Width = 400; 
    private final static int Height = 600; 
    private long period; 
    private Timer timer; 

    private Background background; 

    private boolean isRunning = false; 

    public Display(long period) { 
     this.period = period; 
     setSize(Width, Height); 
     prepeareUi(); 
     setOpaque(false); 
    } 

    public void addNotify() { 
     if(!isRunning) { 
      timer = new Timer((int)period, this); 
      timer.start(); 
      isRunning = true; 
     } 
    } 

    public void stop() { 
     if(isRunning) 
      isRunning = false; 
    } 

    private void prepeareUi() { 
     background = new Background(Width, Height); 
    } 

    public void paintComponent(Graphics g) { 
     g.setColor(Color.WHITE); 
     g.fillRect(0, 0, Width, Height); 
     background.draw(g); 
    } 

    @Override 
    public void actionPerformed(ActionEvent arg0) { 
     if(isRunning) { 
      background.update(); 
      repaint(); 
      return; 
     } 

     System.exit(0); 

    } 

} 

класса Рама:

import javax.swing.JFrame; 

public class Frame extends JFrame { 

    private static final int DEFAULTFPS = 20; 

    public Frame(long period) { 
     prepearUI(period); 
    } 

    private void prepearUI(long period) { 
     Display d = new Display(period); 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     add(d); 
     pack(); 
     setResizable(false); 
     setVisible(true); 
    } 

    public static void main(String[]args) { 
     String fpsS = null; 
     if(args.length==1) 
      fpsS = args[0]; 

     int fps = (fpsS != null) ? Integer.parseInt(fpsS) : DEFAULTFPS; 
     long period = (long) (1000.0/fps); //In Ms! 

     Frame f = new Frame(period); 
    } 

} 

Фоновый

import java.awt.Graphics; 
import java.awt.image.BufferedImage; 
import java.io.IOException; 

import javax.imageio.ImageIO; 


public class Background { 

    private int ParentWidth; 
    private int ParentHeight; 

    private int width; 
    private int height; 

    private BufferedImage image; 

    private float x = 0; 
    private float y = 0; 

    private final static float ANIMATIONSPEED = 1F; 
    private final static int ANIMATION_RIGHT = 0; 
    private final static int ANIMATION_LEFT = 1; 

    private int animationway = 1; 

    public Background(int W, int H) { 
     ParentWidth = W; 
     ParentHeight = H; 
     prepeareImage(); 
    } 

    private void prepeareImage() { 
     width = 0; height = 0; 
     try { 
      image = ImageIO.read(getClass().getResource("UI\\background.png")); 
      width = image.getWidth(null); 
      height = image.getHeight(null); 
     } catch (IOException e) { 
      System.err.println("Background.png not found!"); 
     } 
    } 

    public void update() { 
     if(animationway == ANIMATION_RIGHT) { 
      x += ANIMATIONSPEED; 
      if(x>=0F) { 
       animationway = ANIMATION_LEFT; 
      } 
     } 

     if(animationway == ANIMATION_LEFT) { 
      x -= ANIMATIONSPEED; 
      if(x<=width/-1+ParentWidth) { 
       animationway = ANIMATION_RIGHT; 
      } 
     } 
    } 

    public void draw(Graphics g) { 
     g.drawImage(image, (int) x, (int) y, null); 
    } 

} 
+0

Использовать getPreferredSize по setSize; вызов super.paintComponent перед выполнением пользовательской покраски – MadProgrammer

ответ

4

Проблема заключается в том, что ваш переопределение addNotify не вызвал реализацию родителя. Это сломало много вещей, поэтому правильные уведомления о переименовании, вероятно, являются одним из них. Вы можете исправить это, добавив super.addNotify(); к вашей реализации.

Но я бы не коснулся addNotify. Не отменяйте его. Инициализируйте таймер в конструкторе или добавьте метод, который родитель может вызвать для запуска таймера. У вас уже есть метод stop(), поэтому просто создайте метод start().

JComponent.addNotify() документации говорится:

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

EDIT:

Чтобы избежать нарушения краски цепи убедитесь, что вы называете super.paintComponent() в вашей реализации paintComponent(). Для получения дополнительной информации см. Performing Custom Painting и Painting in AWT and Swing.

+1

Можете ли вы добавить комментарий о разрыве цепочки лакокрасочных материалов, не назвав super.paintComponent – MadProgrammer

+0

@MadProgrammer да, сделано, спасибо! :) – tenorsax

+1

Хорошо! Не думал об этом! Спасибо большое :) – user3641882