views:

225

answers:

2

the following code draws a square with two smaller square rotating inside it. whenever you click an arrow on the keyboard, the whole system will move in that direction. however i'm having some problems with the image tearing and at times skipping (its small but still there). i was wondering if anybody knew how i could fix these issues w/o massively altering the code.

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  A: 

You are not constructing on the EDT. An instance of javax.swing.Timer makes this easy, as the action event handler executes on the EDT.

Addendum 1: You may decide you need double buffering, but first compare the code below to yours and see. If you go that route, you might look at this tutorial.

Addendum 2: The example below shows how to maintain an offscreen buffer, but it is sometimes easier to use the JPanel(boolean isDoubleBuffered) constructor for a similar effect.

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.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.Timer;
import static java.awt.Color.*;

public class GUI extends JPanel implements ActionListener, ComponentListener, KeyListener {

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

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

    public GUI() {
        this.setPreferredSize(new Dimension(320, 240));

        x = 0;
        y = 0;
        x1 = 0;
        y1 = 0;
        x2 = 0;
        y2 = 0;
        changeX = 1;
        changeY = 0;
        changeX2 = 1;
        changeY2 = 0;

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setJMenuBar(createMenuBar());
        frame.addKeyListener(this);
        frame.addComponentListener(this);
        frame.setTitle("GUI");
        frame.setContentPane(this);
        frame.pack();
        frame.setVisible(true);
        t.start();
    }

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

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

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

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

        menuBar.add(fileMenu);
        menuBar.add(editMenu);
        menuBar.add(helpMenu);
        return menuBar;
    }

    @Override
    public void paintComponent(Graphics g) {
        if (b == null) b = new BufferedImage(
            getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
        Graphics offscreen = b.getGraphics();
        offscreen.setColor(WHITE);
        offscreen.fillRect(0, 0, getWidth(), getHeight());
        offscreen.setColor(BLACK);
        offscreen.fillRect(x, y, 100, 100);
        offscreen.setColor(RED);
        offscreen.fillRect(x1, y1, 50, 50);
        offscreen.setColor(BLUE);
        offscreen.fillRect(x2, y2, 25, 25);
        offscreen.dispose();
        g.drawImage(b, 0, 0, null);
    }

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

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

    @Override
    public void keyReleased(KeyEvent e) {}

    @Override
    public void keyTyped(KeyEvent e) {}

    @Override
    public void componentResized(ComponentEvent e) { b = null; }

    @Override
    public void componentMoved(ComponentEvent e) {}

    @Override
    public void componentShown(ComponentEvent e) {}

    @Override
    public void componentHidden(ComponentEvent e) {}
}
trashgod
i thought it was automatically double buffered and that i wouldnt have to do anythingand also why did you change the offset from 10 to 5 (in ur code you called it d)
resotpvl
That is my understanding. I factored out the d (delta) to see its effect and didn't reset it. Is this version an improvement on your system?
trashgod
no sorry, this has significantly more tearing and skipping than my original code
resotpvl
I have trouble seeing tearing, but the version above may help that. Skipping is a function of d. How does the invaders tutorial run? http://www.stumbleupon.com/su/8wGoxm/www.cokeandcode.com/info/tut2d.html
trashgod
+1  A: 

I would take a look at double buffering. Basically, you draw to an offscreen graphics object and then draw the offscreen graphics object onto the JPanel's graphics object.

~Bolt

Boltimuss