2017-02-22 11 views
-1

Я пытаюсь создать простую анимацию, в которой прямоугольник начинается с экрана (справа от правого края экрана) и перемещается влево. Таким образом, в этом случае мой кадр имеет ширину 1000, а стена начинается с значения х 1100. Очевидно, что сначала прямоугольник не должен отображаться . Но по мере того, как прямоугольник перемещается влево, он должен стать видимым. Однако эта анимация этого не делает. Даже когда x-значение стены находится в пределах экрана, оно не отображается.JComponent перестает получать визуализацию, когда она уходит с экрана

Я пытался ставить println() заявление в paintComponent() методе стены, и я обнаружил, что paintComponent() не вызывался по методу repaint() кадра. Я подумал, что когда стена была впервые добавлена ​​в рамку, Swing решил, что, поскольку она была на экране, ее не нужно отображать, и поэтому даже когда стена в конечном итоге попадает на экран, Swing считает, что она не нужна для рендеринга.

Я пробовал проверять и аннулировать рамку и компонент, но ничего не сработало. Пожалуйста, помогите мне исправить это. Ниже приведен код:

package graphics.simpleAnimation; 

public class Simple_Animation implements Runnable { 

    private UI ui; // The UI (frame) 

    private Wall wall; // Wall object that moves across the screen 

    private Simple_Animation() { 

     // Initialize the wall object (intentionally given an x value that is greater than the frame's width) 
     wall = new Wall(1100, 400, 200, 400); 

     // Initialize the UI (width is only 1000) 
     ui = new UI(1000, 600, "Geometry Dash"); 

     // Add the wall to the ui (the frame) 
     ui.add(wall); 

    } 

    public void run() { 
     // Set the frame visible 
     ui.setVisible(true); 

     // Repaint the frame and move the wall 
     while (true) { 
      ui.repaint(); 
      wall.moveWall(-2, 0); 

      try { 
       Thread.sleep(16); 
      } catch (InterruptedException IE) { 
       System.out.println(IE); 
      } 

     } 

    } 

    // Starts the program in a new thread 
    public static void main(String[] args) { 
     Simple_Animation simpleAnimation = new Simple_Animation(); 
     new Thread(simpleAnimation).start(); 
    } 

} 


package graphics.simpleAnimation; 

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

public class UI extends JFrame { 

    // Variables storing the width and height of the content pane (where the components are being rendered) 
    public int content_pane_width; 
    public int content_pane_height; 

    public UI(int frameW, int frameH, String frameTitle) { 

     setTitle(frameTitle); 
     setSize(frameW, frameH); 
     setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 
     setLayout(null); 

     content_pane_width = getContentPane().getWidth(); 
     content_pane_height = getContentPane().getHeight(); 

    } 

    @Override 
    public void paint(Graphics g) { 
     super.paint(g); 
    } 

} 

package graphics.simpleAnimation; 

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

public class Wall extends JComponent { 

    private int wallX; 
    private int wallY; 
    private int wallW; 
    private int wallH; 


    Wall(int x, int y, int sizeX, int sizeY) { 
     wallX = x; 
     wallY = y; 
     wallW = sizeX; 
     wallH = sizeY; 

     setSize(getPreferredSize()); 
    } 

    public void moveWall(int moveX, int moveY) { 
     wallX += moveX; 
     wallY += moveY; 
    } 

    @Override 
    public Dimension getPreferredSize() { 
     return new Dimension(wallW, wallH); 
    } 

    @Override 
    public void paintComponent(Graphics g) { 
     Graphics2D g2d = (Graphics2D) g; 

     setLocation(wallX, wallY); 
     g2d.fillRect(0, 0, wallW, wallH); 
    } 
} 
+1

Не делайте 'setLocation (wallX, wallY);' внутри метода рисования, рисование должно рисовать текущее состояние, которое никогда не меняет его. Вы также смешиваете свои собственные свойства с свойствами компонентов, я бы предложил просто использовать ранее существовавшие компоненты, поскольку вы пытаетесь сами поместить/размер компонента. Кроме того, 'getPreferredSize' ничего не сделает, если вы используете макет« null », что, вероятно, объясняет часть вашей проблемы. – MadProgrammer

+0

См. [Обнаружение/исправление для висящей скобки блока кода] (http: // meta .stackexchange.com/q/251795/155831) для проблемы я больше не мог беспокоить исправление. –

ответ

3

Есть несколько ошибок, я могу найти в вашей программе

  1. Вы используете a null layout, см. Null layout is evil и ответы в this question, чтобы узнать, почему вы должны избегать его использования. (Возможно, не в этом случае, как на @ MadProgrammer свой комментарий ниже), это просто другой подход

  2. while (true) { эта линия может блокировать Event Dispatch Thread (EDT) вместе с этой линии: Thread.sleep(16);, см Lesson: Concurrency in Swing, чтобы узнать больше о и How to use Swing Timers. Вы должны также поместить программу на EDT, которые можно сделать:

    public static void main(String[] args) { 
        SwingUtilities.invokeLater(new Runnable() { 
         @Override 
         public void run() { 
          //Your constructor here 
         } 
        }); 
    } 
    
  3. Вы не вызывая super.paintComponent() на вашем paintComponent() способе Wall класса, который мог бы разорвать цепь краски, всегда называют его первым.

  4. Вы простирающийся JComponent, было бы лучше, чтобы расширить JPanel и сделать заказную прорисовку над ним с помощью Shape сек API

Со всеми выше в виду, вы можете иметь код как это одна:

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.geom.Rectangle2D; 

import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.SwingUtilities; 
import javax.swing.Timer; 

public class SingleAnimation { 

    private JFrame frame; 
    private Timer timer; 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       new SingleAnimation().createAndShowGui(); 
      } 
     }); 
    } 

    public void createAndShowGui() { 
     frame = new JFrame(getClass().getSimpleName()); 

     Wall wall = new Wall(300, 0); 

     timer = new Timer(16, new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       wall.moveWall(-2, 0); 
      } 
     }); 

     timer.setInitialDelay(0); 
     timer.start(); 

     frame.add(wall); 
     frame.pack(); 
     frame.setVisible(true); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    } 
} 

class Wall extends JPanel { 
    private int xCoord; 
    private int yCoord; 

    public int getxCoord() { 
     return xCoord; 
    } 

    public void setxCoord(int xCoord) { 
     this.xCoord = xCoord; 
    } 

    public int getyCoord() { 
     return yCoord; 
    } 

    public void setyCoord(int yCoord) { 
     this.yCoord = yCoord; 
    } 

    public Wall(int x, int y) { 
     this.xCoord = x; 
     this.yCoord = y; 
    } 

    public void moveWall(int xUnits, int yUnits) { 
     xCoord += xUnits; 
     yCoord += yUnits; 
     repaint(); 
    } 

    @Override 
    public Dimension getPreferredSize() { 
     return new Dimension(400, 400); 
    } 

    @Override 
    protected void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     Graphics2D g2d = (Graphics2D) g; 
     g2d.setColor(Color.BLUE); 

     g2d.fill(new Rectangle2D.Double(xCoord, yCoord, 100, 20)); 
    } 
} 

Какой будет производить подобный вывод, как этот:

enter image description here

+0

Нет аргументов с вашим примером, но мне нужно больше контекста для вопроса, чтобы иметь возможность решить, какой подход правильный * «Вы «используя нулевой макет, пожалуйста, посмотрите, что Null layout - это зло, и ответы в этом вопросе, чтобы понять, почему вы должны избегать его использования». * - это упрощение проблемы и 99% времени, когда вы считаете, что вам нужен «null» 'layout, вы этого не делаете, но я могу придумать несколько раз, когда это полезно (например, выполнить анимацию на основе компонентов), макеты« null »- это инструмент, которым они могут быть при правильном использовании, но большинство людей используют их в неправильный путь и в неподходящее время;) – MadProgrammer

+0

@MadProgrammer благодарит за ваши отзывы, я уже видел ваш пример, он отлично работает, я узнал что-то новое сегодня благодаря вашему комментарию. Мне нужно посмотреть на другие примеры, где «нулевой макет» полезен (не для размещения компонентов в графическом интерфейсе, но более похожим на этот) :) – Frakcool

+0

Не поймите меня неправильно, я согласен, макеты 'null', как правило, плохие идея в чужих руках, это как огонь, это полезно, но если вы не будете осторожны, вы сжечь дом;) - Приятный пример, кстати;) – MadProgrammer

2
  • Не делать setLocation(wallX, wallY); в методе краски, картина должна окрашивать текущее состояние никогда не изменить его.
  • Вы также смешиваете свои собственные свойства с свойствами компонентов, я бы предложил просто использовать ранее существовавшие компоненты, поскольку вы пытаетесь сами поместить/размер компонента.
  • getPreferredSize ничего не будет делать, когда вы используете null макет, который, вероятно, объясняет, часть вашей проблемы в качестве компонента предполагает размер по умолчанию 0x0
  • Поскольку свинг не поточно, разумнее было бы использовать качели Timer действовать в качестве «основного цикла» вместо Thread

Я не фанат «на основе компонентов анимации» для такого рода целей, предпочитая вместо этого идти прямо на заказ картину, но это я

Но если Вы должны, вы должны попытаться использовать функциональные возможности API, которые доступны для вас

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.SwingUtilities; 
import javax.swing.Timer; 

class Test { 
    public static void main(String[] args) { 
     new Test(); 
    } 

    public Test() { 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       JFrame frame = new JFrame("Test"); 
       frame.add(new TestPane()); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

    public class TestPane extends JPanel { 

     private WallPane wallPane; 

     public TestPane() { 
      setLayout(null); // :(
      wallPane = new WallPane(); 
      wallPane.setLocation(-100, 150); 
      add(wallPane); 

      Timer timer = new Timer(16, new ActionListener() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 
        wallPane.moveBy(2, 0); 
        repaint(); 
       } 
      }); 
      timer.start(); 
     } 

     @Override 
     public Dimension getPreferredSize() { 
      return new Dimension(400, 400);    
     } 

    } 

    public class WallPane extends JPanel { 
     public WallPane() { 
      setSize(100, 100); 
      setBackground(Color.RED); 
     } 

     public void moveBy(int xDelta, int yDelta) { 
      int x = getX() + xDelta; 
      int y = getY() + yDelta; 
      setLocation(x, y); 
     } 
    } 
} 
+0

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

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