2010-01-22 30 views
3

以下代码绘制了一个正方形,其中包含两个较小的正方形。每当你点击键盘上的箭头时,整个系统就会朝这个方向移动。然而,我有一些图像撕裂问题,有时会跳过(它的小但仍然存在)。我想知道是否有人知道我可以如何解决这些问题w/o大规模改变代码。在Java动画中跳过和撕裂

import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 
import static java.awt.Color.*; 

public class GUI extends JPanel implements ActionListener, KeyListener 
{ 
    int x, y, x1, y1, x2, y2, changeX, changeY, changeX2, changeY2; 
    JFrame frame; 
    Runtime r; 
    public static void main(String[] args) 
    { 
     new GUI(); 
    } 
    public GUI() 
    { 
     try 
     { 
      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
     } catch (Exception e) 
     { 
      e.printStackTrace(); 
     } 

     setSize(1020,770); 
     setBackground(WHITE); 
     setOpaque(true); 
     setVisible(true); 

     x = 0; 
     y = 0; 
     x1 = 0; 
     y1 = 0; 
     x2 = 0; 
     y2 = 0; 
     changeX=1; 
     changeY=0; 
     changeX2=1; 
     changeY2=0; 
     r = Runtime.getRuntime(); 

     frame = new JFrame(); 
     frame.setSize(1020,819); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setJMenuBar(createMenuBar()); 
     frame.validate(); 
     frame.setBackground(WHITE); 
     frame.addKeyListener(this); 
     frame.setTitle("GUI"); 
     frame.setContentPane(this); 
     frame.setVisible(true); 
     frame.createBufferStrategy(2); 

     Timer t = new Timer(100,this); 
     t.setActionCommand("Draw"); 
     t.start(); 

     repaint(); 
    } 
    public JMenuBar createMenuBar() 
    { 
     JMenuBar menuBar = new JMenuBar(); 

     JMenu fileMenu = new JMenu("File"); 
     JMenuItem save = new JMenuItem("Save"); 
     save.setMnemonic(KeyEvent.VK_S); 
     save.setContentAreaFilled(false); 
     save.setOpaque(false); 
     save.addActionListener(this); 
     JMenuItem load = new JMenuItem("Load"); 
     load.setMnemonic(KeyEvent.VK_L); 
     load.setContentAreaFilled(false); 
     load.setOpaque(false); 
     load.addActionListener(this); 
     JMenuItem quit = new JMenuItem("Quit"); 
     quit.setMnemonic(KeyEvent.VK_Q); 
     quit.setContentAreaFilled(false); 
     quit.setOpaque(false); 
     quit.addActionListener(this); 
     fileMenu.add(save); 
     fileMenu.add(load); 
     fileMenu.addSeparator(); 
     fileMenu.add(quit); 
     fileMenu.setContentAreaFilled(false); 
     fileMenu.setBorderPainted(false); 
     fileMenu.setOpaque(false); 

     JMenu editMenu = new JMenu("Edit"); 
     JMenuItem undo = new JMenuItem("Undo"); 
     undo.setMnemonic(KeyEvent.VK_U); 
     undo.setContentAreaFilled(false); 
     undo.setOpaque(false); 
     undo.addActionListener(this); 
     JMenuItem redo = new JMenuItem("Redo"); 
     redo.setMnemonic(KeyEvent.VK_R); 
     redo.setContentAreaFilled(false); 
     redo.setOpaque(false); 
     redo.addActionListener(this); 
     editMenu.add(undo); 
     editMenu.add(redo); 
     editMenu.setContentAreaFilled(false); 
     editMenu.setBorderPainted(false); 
     editMenu.setOpaque(false); 

     JMenu helpMenu = new JMenu("Help"); 
     JMenuItem controls = new JMenuItem("Controls"); 
     controls.setMnemonic(KeyEvent.VK_C); 
     controls.setContentAreaFilled(false); 
     controls.setOpaque(false); 
     controls.addActionListener(this); 
     JMenuItem about = new JMenuItem("About"); 
     about.setMnemonic(KeyEvent.VK_A); 
     about.setContentAreaFilled(false); 
     about.setOpaque(false); 
     about.addActionListener(this); 
     helpMenu.add(controls); 
     helpMenu.addSeparator(); 
     helpMenu.add(about); 
     helpMenu.setContentAreaFilled(false); 
     helpMenu.setBorderPainted(false); 
     helpMenu.setOpaque(false); 

     menuBar.add(fileMenu); 
     menuBar.add(editMenu); 
     menuBar.add(helpMenu); 
     return menuBar; 
    } 
    public void paintComponent(Graphics g) 
    { 
     g.clearRect(0, 0, 1020, 770); 
     g.setColor(BLACK); 
     g.fillRect(x,y,100,100); 
     g.setColor(RED); 
     g.fillRect(x1,y1,50,50); 
     g.setColor(BLUE); 
     g.fillRect(x2,y2,25,25); 
     g.dispose(); 
    } 
    public void change() 
    { 
     if(x1>=x+50&&changeY==0&&changeX==1) 
     { 
      changeX=0; 
      changeY=1; 
     } 
     else if(y1>=y+50&&changeX==0&&changeY==1) 
     { 
      changeX=-1; 
      changeY=0; 
     } 
     else if(x1<=x&&changeX==-1&&changeY==0) 
     { 
      changeX=0; 
      changeY=-1; 
     } 
     else if(y1<=y&&changeY==-1&&changeX==0) 
     { 
      changeX=1; 
      changeY=0; 
     } 
     x1+=changeX*5; 
     y1+=changeY*5; 
    } 
    public void change2() 
    { 
     if(x2>=x1+25&&changeY2==0&&changeX2==1) 
     { 
      changeX2=0; 
      changeY2=1; 
     } 
     else if(y2>=y1+25&&changeX2==0&&changeY2==1) 
     { 
      changeX2=-1; 
      changeY2=0; 
     } 
     else if(x2<=x1&&changeX2==-1&&changeY2==0) 
     { 
      changeX2=0; 
      changeY2=-1; 
     } 
     else if(y2<=y1&&changeY2==-1&&changeX2==0) 
     { 
      changeX2=1; 
      changeY2=0; 
     } 
     x2+=changeX2*2; 
     y2+=changeY2*2; 
    } 
    public void actionPerformed(ActionEvent e) 
    { 
     if(e.getActionCommand().equalsIgnoreCase("Draw")) 
     { 
      r.runFinalization(); 
      r.gc(); 
      change(); 
      change2(); 
      repaint(); 
     } 
    } 
    public void keyPressed(KeyEvent e) 
    { 
     if(e.getKeyCode()==KeyEvent.VK_UP) 
     { 
      if(y-10>=0) 
      { 
       y-=10; 
       y1-=10; 
       y2-=10; 
      } 
     } 
     if(e.getKeyCode()==KeyEvent.VK_DOWN) 
     { 
      if(y+110<=getHeight()) 
      { 
       y+=10; 
       y1+=10; 
       y2+=10; 
      } 
     } 
     if(e.getKeyCode()==KeyEvent.VK_LEFT) 
     { 
      if(x-10>=0) 
      { 
       x-=10; 
       x1-=10; 
       x2-=10; 
      } 
     } 
     if(e.getKeyCode()==KeyEvent.VK_RIGHT) 
     { 
      if(x+110<=getWidth()) 
      { 
       x+=10; 
       x1+=10; 
       x2+=10; 
      } 
     } 
     repaint(); 
    } 
    public void keyReleased(KeyEvent e) 
    { 
    } 
    public void keyTyped(KeyEvent e) 
    { 
    } 
} 

回答

2

您不是在EDT上构建。由于动作事件处理程序在EDT上执行,因此javax.swing.Timer的一个实例使得这很容易。

附录1:您可能决定您需要double buffering,但首先将以下代码与您的代码进行比较并查看。如果你走这条路线,你可以看看这个tutorial

附录2:下面的示例显示了如何维护屏幕外缓冲区,但有时使用JPanel(boolean isDoubleBuffered)构造函数也可以获得类似的效果。

import java.awt.event.KeyAdapter; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.KeyEvent; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.Timer; 
import static java.awt.Color.*; 

/** @see http://stackoverflow.com/questions/2114455 */ 
public class GUI extends JPanel implements ActionListener { 

    int x, y, x1, y1, x2, y2, changeY, changeY2; 
    int changeX = 1; int changeX2 = 1; 
    Timer t = new Timer(100, this); 

    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       new GUI(true).display(); 
      } 
     }); 
    } 

    public GUI(boolean doubleBuffered) { 
     super(doubleBuffered); 
     this.setPreferredSize(new Dimension(320, 240)); 
    } 

    private void display() { 
     JFrame frame = new JFrame("GUI"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.addKeyListener(new KeyListener()); 
     frame.add(this); 
     frame.pack(); 
     frame.setVisible(true); 
     t.start(); 
    } 

    @Override 
    public void paintComponent(Graphics g) { 
     g.setColor(WHITE); 
     g.fillRect(0, 0, getWidth(), getHeight()); 
     g.setColor(BLACK); 
     g.fillRect(x, y, 100, 100); 
     g.setColor(RED); 
     g.fillRect(x1, y1, 50, 50); 
     g.setColor(BLUE); 
     g.fillRect(x2, y2, 25, 25); 
    } 

    public void change() { 
     if (x1 >= x + 50 && changeY == 0 && changeX == 1) { 
      changeX = 0; 
      changeY = 1; 
     } else if (y1 >= y + 50 && changeX == 0 && changeY == 1) { 
      changeX = -1; 
      changeY = 0; 
     } else if (x1 <= x && changeX == -1 && changeY == 0) { 
      changeX = 0; 
      changeY = -1; 
     } else if (y1 <= y && changeY == -1 && changeX == 0) { 
      changeX = 1; 
      changeY = 0; 
     } 
     x1 += changeX * 5; 
     y1 += changeY * 5; 
    } 

    public void change2() { 
     if (x2 >= x1 + 25 && changeY2 == 0 && changeX2 == 1) { 
      changeX2 = 0; 
      changeY2 = 1; 
     } else if (y2 >= y1 + 25 && changeX2 == 0 && changeY2 == 1) { 
      changeX2 = -1; 
      changeY2 = 0; 
     } else if (x2 <= x1 && changeX2 == -1 && changeY2 == 0) { 
      changeX2 = 0; 
      changeY2 = -1; 
     } else if (y2 <= y1 && changeY2 == -1 && changeX2 == 0) { 
      changeX2 = 1; 
      changeY2 = 0; 
     } 
     x2 += changeX2 * 2; 
     y2 += changeY2 * 2; 
    } 

    @Override 
    public void actionPerformed(ActionEvent e) { 
     change(); 
     change2(); 
     repaint(); 
    } 

    private class KeyListener extends KeyAdapter { 

     @Override 
     public void keyPressed(KeyEvent e) { 
      int d = 5; 
      if (e.getKeyCode() == KeyEvent.VK_UP) { 
       if (y - d >= 0) { 
        y -= d; 
        y1 -= d; 
        y2 -= d; 
       } 
      } 
      if (e.getKeyCode() == KeyEvent.VK_DOWN) { 
       if (y + 100 + d <= getHeight()) { 
        y += d; 
        y1 += d; 
        y2 += d; 
       } 
      } 
      if (e.getKeyCode() == KeyEvent.VK_LEFT) { 
       if (x - d >= 0) { 
        x -= d; 
        x1 -= d; 
        x2 -= d; 
       } 
      } 
      if (e.getKeyCode() == KeyEvent.VK_RIGHT) { 
       if (x + 100 + d <= getWidth()) { 
        x += d; 
        x1 += d; 
        x2 += d; 
       } 
      } 
     } 
    } 
} 
+0

我以为这是自动双缓冲,可我不会必须你为什么要改变从10偏移至5做任何事情 并(在我们的代码,你把它叫做D) – resotpvl 2010-01-22 22:40:21

+0

这是我的理解。我将d(delta)分解为它的效果并没有重置它。这个版本是对你的系统的改进吗? – trashgod 2010-01-23 03:49:54

+0

没有对不起,这有比我原来的代码 – resotpvl 2010-01-26 00:35:05

1

我会看看双缓冲。基本上,您可以绘制一个离屏图形对象,然后将离屏图形对象绘制到JPanel的图形对象上。

〜博尔特