Orion31
Orion31

Reputation: 596

Flashing White Graphics Java

How would I clear a single shape from my JFrame without making the screen flash white.

import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Random;`

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;


public class Frame extends JFrame {
static Shape s;
Graphics2D g2D;
/**
 * 
 */
private static final long serialVersionUID = 7764273188525543212L;
private JPanel contentPane;
public Point startDrag = null, endDrag = null;
HashMap<Shape, Color> shapes = new HashMap<Shape, Color>();
/**
 * Launch the application.
 */
public static void main(String[] args) {
    Frame f = new Frame();
    f.setVisible(true);
}
/**
 * Create the frame.
 */
public Frame() {

    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setBounds(100, 100, 450, 300);
    contentPane = new JPanel();
    contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
    contentPane.setLayout(new BorderLayout(0, 0));
    setContentPane(contentPane);
    addMouseListener(new MouseAdapter() {

        @Override
        public void mousePressed(MouseEvent e) {
            startDrag = new Point(e.getX(), e.getY());
            endDrag = startDrag;
            repaint();
        }

        @Override
        public void mouseReleased(MouseEvent e) {
            Shape s = makeRectangle(startDrag.x, startDrag.y, e.getX(),
                    e.getY());
            Color[] colors = {Color.MAGENTA, Color.CYAN, Color.RED,
                    Color.BLUE, Color.PINK, Color.yellow};
            Random r = new Random();
            int i = r.nextInt(colors.length - 1);
            shapes.put(s, colors[i]);
            endDrag = null;
            startDrag = null;
            repaint();
        }

    });
    addMouseMotionListener(new MouseMotionAdapter() {



        @Override
        public void mouseDragged(MouseEvent e) {
            endDrag = new Point(e.getX(), e.getY());
            repaint();

        }
    });
}
public void paint(Graphics g) {
    Graphics2D g2 = (Graphics2D) g;
    paintBackground(g2);
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
    g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
            0.50f));
    g2.setStroke(new BasicStroke(2));
    for (Entry<Shape, Color> s : shapes.entrySet()) {

        g2.setPaint(Color.BLACK);
        g2.draw(s.getKey());
        g2.setPaint(s.getValue());
        g2.fill(s.getKey());
    }
    if (startDrag != null) {
        if (endDrag != null) {

            g2.setStroke(new BasicStroke(5.0f));
            g2.setColor(Color.darkGray);

            s = makeRectangle(startDrag.x, startDrag.y, endDrag.x,
                    endDrag.y);
            g2.draw(s);
        }

    }
}
private Rectangle2D.Float makeRectangle(int x1, int y1, int x2, int y2) {
    return new Rectangle2D.Float(Math.min(x1, x2), Math.min(y1, y2),
            Math.abs(x1 - x2), Math.abs(y1 - y2));
}
private void paintBackground(Graphics2D g2) {
    clear(g2);
    g2.setPaint(Color.red);
    g2.setStroke(new BasicStroke(0.4f));
    for (int i = 0; i < getSize().width; i += 10) {
        Shape line = new Line2D.Float(i, 0, i, getSize().height);
        g2.draw(line);
    }

    for (int i = 0; i < getSize().height; i += 10) {
        Shape line = new Line2D.Float(0, i, getSize().width, i);
        g2.draw(line);
    }

}

private void clear(Graphics g) {
    g.clearRect(0, 0, getWidth(), getHeight());

}

}

// If you try this code, just drag and let go to make a rectangle.

But when I drag, the screen flashes white, so it's hard for me to see what I'm doing. Is there anyway to make this work the same way, but that clears the JFrame faster than you can see?

Upvotes: 1

Views: 1144

Answers (1)

Hovercraft Full Of Eels
Hovercraft Full Of Eels

Reputation: 285405

Don't draw directly in a JFrame. Instead draw in the paintComponent(Graphics g) method of a JPanel. Be sure to call the super.paintComponent(g) within your override. This will give you double buffering by default and may help some of the flashing.

e.g.,

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Random;
import javax.swing.*;

@SuppressWarnings("serial")
public class DrawPanel extends JPanel {
   private static final int PREF_W = 450;
   private static final int PREF_H = 300;
   private static final int SMALL_SQR_SIZE = 10;
   private static final Stroke STROKE_5 = new BasicStroke(5f);
   private static final Stroke STROKE_2 = new BasicStroke(2f);
   private static final Color[] COLORS = { Color.MAGENTA, Color.CYAN, Color.RED,
         Color.BLUE, Color.PINK, Color.yellow };
   private Random random = new Random();
   private BufferedImage background;
   private Map<Shape, Color> shapes = new LinkedHashMap<>(); // so order is maintained
   private Shape drawingShape = null;

   public DrawPanel() {
      background = createBackground();
      MyMouseAdapater myMouseAdapater = new MyMouseAdapater();
      addMouseListener(myMouseAdapater);
      addMouseMotionListener(myMouseAdapater);
   }

   private BufferedImage createBackground() {
      BufferedImage bg = new BufferedImage(PREF_W, PREF_H, BufferedImage.TYPE_INT_ARGB);
      Graphics2D g2 = bg.createGraphics();
      g2.setPaint(Color.red);
      // g2.setStroke(new BasicStroke(BASIC_STROKE_POINTS));
      for (int i = 0; i < PREF_W; i += SMALL_SQR_SIZE) {
         g2.drawLine(i, 0, i, PREF_H);
      }

      for (int i = 0; i < PREF_H; i += SMALL_SQR_SIZE) {
         g2.drawLine(0, i, PREF_W, i);
      }

      g2.dispose();
      return bg;
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      if (background != null) {
         g.drawImage(background, 0, 0, null);
      }
      Graphics2D g2 = (Graphics2D) g;
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);
      g2.setStroke(STROKE_2);
      for (Shape shape : shapes.keySet()) {
         g2.setColor(Color.black);
         g2.draw(shape);
         g2.setColor(shapes.get(shape));
         g2.fill(shape);
      }
      if (drawingShape != null) {
         g2.setStroke(STROKE_5);
         g2.setColor(Color.DARK_GRAY);
         g2.draw(drawingShape);
      }
   }

   @Override
   public Dimension getPreferredSize() {
      if (isPreferredSizeSet()) {
         return super.getPreferredSize();
      }
      return new Dimension(PREF_W, PREF_H);
   }

   private class MyMouseAdapater extends MouseAdapter {
      private Point initP = null;
      @Override
      public void mousePressed(MouseEvent e) {
         if (e.getButton() != MouseEvent.BUTTON1) {
            return;
         }
         initP = e.getPoint();
      }

      @Override
      public void mouseDragged(MouseEvent e) {
         if (initP == null) {
            return;
         }
         Point p = e.getPoint();
         drawingShape = makeRectangle(p.x, p.y, initP.x, initP.y);
         repaint();
      }

      @Override
      public void mouseReleased(MouseEvent e) {
         if (initP == null) {
            return;
         }
         Point p = e.getPoint();
         Shape newShape = makeRectangle(p.x, p.y, initP.x, initP.y);
         shapes.put(newShape, COLORS[random.nextInt(COLORS.length)]);

         drawingShape = null;
         initP = null;
         repaint();         
      }

      private Rectangle2D.Float makeRectangle(int x1, int y1, int x2, int y2) {
         return new Rectangle2D.Float(Math.min(x1, x2), Math.min(y1, y2),
               Math.abs(x1 - x2), Math.abs(y1 - y2));
      }
   }

   private static void createAndShowGui() {
      DrawPanel mainPanel = new DrawPanel();

      JFrame frame = new JFrame("DrawPanel");
      frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

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

Note that I extended JPanel so that I can use its paintComponent method, and I called the super method. I also used a LinkedHashMap so that the Map's order of entry is maintained.

Upvotes: 2

Related Questions