Skip to Main Content

Java SE (Java Platform, Standard Edition)

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

Interested in getting your voice heard by members of the Developer Marketing team at Oracle? Check out this post for AppDev or this post for AI focus group information.

Can someone optimise the following code ?

843805Aug 2 2006 — edited Aug 2 2006
Hi,
Recently i wrote a (simple) piece of code to test a functionality in JPanel. It was ,to
draw a rectangle as the user drags the mouse in the Panel. Just like in file browser , to select
multiple files by dragging the mouse.

In this, I see the box flickering so much, whenever
the user drags the mouse.As the box is getting repainted with every co-ordinates as it moved.
I dont have any idea to optimise the code and to stop fickering ..
as far as i can think of.

can someone help me with this ?

Well , when i tried the same thing in Ubuntu linux , i couldnt the box at all !!!
That was totally strange !!!! . Any solution for this ???
import java.awt.event.MouseMotionAdapter;
import javax.swing.JLabel;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import java.awt.Point;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.Graphics;
import java.awt.AlphaComposite;

public class Dragtest extends JFrame{
    
    boolean blPaintRect = false;
    Polygon d = new Polygon();
    Point srcPoint = null;
    Point destPoint = null;
    boolean blchecked;
    AlphaComposite alcomp = AlphaComposite.getInstance(
                    AlphaComposite.SRC_OVER, 0.4f);

    public Dragtest() {
        getContentPane().setLayout(new java.awt.FlowLayout());
        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        
        pack();

        setSize(300, 300);
        setLocation(300, 100);
        setTitle("Java Speed Test");
        setVisible(true);

        addMouseMotionListener(new MouseMotionAdapter(){
            public void mouseDragged(MouseEvent e){
                // blPaintRect is made true and repaint is called , to draw the box
                blPaintRect = true;
                if(srcPoint == null){
                    srcPoint = e.getPoint();
                    destPoint = e.getPoint();
                }
                else{
                    destPoint = e.getPoint();
                }
                // As the user drags the mouse , the new co-ordinates are stored
                // in destPoint variable and the intial point in
                // srcPoint variable
                
                d.reset();
                d.addPoint(srcPoint.x, srcPoint.y);
                d.addPoint(destPoint.x, srcPoint.y);
                d.addPoint(destPoint.x, destPoint.y);
                d.addPoint(srcPoint.x, destPoint.y);
                repaint();
            }
        } );

        addMouseListener(new MouseAdapter(){
            public void mouseReleased(MouseEvent e) {
                blPaintRect = false;
                srcPoint = null;
                repaint();
            }
        });
        
    }

    public void paint(Graphics g){
        if(blPaintRect){
            super.paint(g);
            Graphics2D  g2d = (Graphics2D) g;            
            g2d.setComposite(alcomp);
            // One optimisation is that ,
            // drawPolygon  be skipped , and only fillPolygon can be used 
            g2d.drawPolygon(d);
            g2d.fillPolygon(d);
        }
        else{
            super.paint(g);
        }
    }

    public static void main(String args[]) {
        new Dragtest().setVisible(true);
    }
    
}

Comments

843805
here ya go... there is a huge performance trick called double buffering.

Notice how each time we need to re-draw the polygon, we only draw to the buffered image instead of directly on the passed-in graphics argument? Thats the trick.

It avoid doing any geometry/java2d work in the majority of painting requests and instead painting is usualy only a simple copy-buffer operation.
import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.image.BufferedImage;

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

public class Dragtest extends JFrame {

  boolean blPaintRect = false;
  Polygon d = new Polygon();
  Point srcPoint = null;
  Point destPoint = null;
  boolean blchecked;
  AlphaComposite alcomp = AlphaComposite.getInstance(
      AlphaComposite.SRC_OVER,
      0.4f);
  BufferedImage buffer;
  boolean dirty = true;

  JPanel canvas;

  public Dragtest() {
    
    canvas = new JPanel() {

      public void paintComponent(Graphics g) {

        if (dirty) {
          buffer = getUpdatedImage(canvas);
          Graphics2D bufferGraphics = (Graphics2D) buffer.getGraphics();
          super.paintComponent(bufferGraphics);

          if (blPaintRect) {
            bufferGraphics.setComposite(alcomp);
            // One optimisation is that ,
            // drawPolygon  be skipped , and only fillPolygon can be used 
            bufferGraphics.drawPolygon(d);
            bufferGraphics.fillPolygon(d);
          }
          dirty = false;
        }

        g.drawImage(buffer, 0, 0, getWidth(), getHeight(), this);
      }
    };

    canvas.addMouseMotionListener(new MouseMotionAdapter() {
      public void mouseDragged(MouseEvent e) {
        // blPaintRect is made true and repaint is called , to draw the box
        blPaintRect = true;
        Point p = e.getPoint();
       // p = SwingUtilities.convertPoint(Dragtest.this, p, canvas);
        if (srcPoint == null) {
          srcPoint = new Point(p.x, p.y);
          destPoint = srcPoint;
        } else {
          destPoint = new Point(p.x, p.y);
        }
        // As the user drags the mouse , the new co-ordinates are stored
        // in destPoint variable and the intial point in
        // srcPoint variable
        d.reset();
        d.addPoint(srcPoint.x, srcPoint.y);
        d.addPoint(destPoint.x, srcPoint.y);
        d.addPoint(destPoint.x, destPoint.y);
        d.addPoint(srcPoint.x, destPoint.y);
        dirty = true;
        repaint();
      }
    });

    canvas.addMouseListener(new MouseAdapter() {
      public void mouseReleased(MouseEvent e) {
        blPaintRect = false;
        srcPoint = null;
        dirty = true;
        repaint();
      }
    });

    canvas.setBorder(null);
    getContentPane().setLayout(new BorderLayout());
    getContentPane().add(canvas, BorderLayout.CENTER);
    setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

    pack();

    setSize(300, 300);
    setLocation(300, 100);
    setTitle("Java Speed Test");
    setVisible(true);
  }

  /**
   * @return a buffer same size as the given component.
   */
  private BufferedImage getUpdatedImage(Component c) {
    if (buffer == null) {
      buffer = new BufferedImage(1, 1, BufferedImage.TYPE_INT_BGR);
    } else {
      int bufferWidth = buffer.getWidth();
      int bufferHeight = buffer.getHeight();

      int componentWidth = c.getWidth();
      int componentHeight = c.getHeight();

      if (bufferWidth != componentWidth || bufferHeight != componentHeight) {
        buffer = new BufferedImage(
            componentWidth,
            componentHeight,
            BufferedImage.TYPE_INT_BGR);

      }
    }

    return buffer;
  }

  public static void main(String args[]) {
    new Dragtest().setVisible(true);
  }

}
843805
Hmmm ... Thx for ur reply ..
I have a comment for ur code ..

1) The double buffering as u said as trick , which i dont think
rules here, because , evry time the component is painted when the mouse is presed , u have created a new graphics object in which u painted the polygon and displayed .

2) The Frame is the culprit here, Overriding the paint method of Frame is what making the fickering. When i tried my code (courtesy : your code !! ) with overriding a JPanel paint method , it works as smooth as possible .
import java.awt.event.MouseMotionAdapter;
import javax.swing.JLabel;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import java.awt.Point;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.Graphics;
import java.awt.AlphaComposite;
import javax.swing.plaf.basic.BasicScrollPaneUI;
import javax.swing.JPanel;
import java.awt.BorderLayout;

public class DragTest2 extends JFrame{

    boolean blPaintRect = false;
    Polygon d = new Polygon();
    Point srcPoint = null;
    Point destPoint = null;
    boolean blchecked;
    AlphaComposite alcomp = AlphaComposite.getInstance(
                    AlphaComposite.SRC_OVER, 0.4f);
    JPanel myPanel;

    public DragTest2() {        
        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        
        myPanel = new JPanel(){
            public void paint(Graphics g) {                
                if (blPaintRect) {
                    super.paint(g);
                    g.drawPolygon(d);
                    Graphics2D g2d = (Graphics2D) g;
                    g2d.setComposite(alcomp);
                    // One optimisation is that ,
                    // drawPolygon  be skipped , and only fillPolygon can be used
//                    g2d.drawPolygon(d);
                    g2d.fillPolygon(d);
                } else {
                    super.paint(g);
                }
            }
        };
        
        myPanel.addMouseMotionListener(new MouseMotionAdapter(){
            public void mouseDragged(MouseEvent e){
                // blPaintRect is made true and repaint is called , to draw the box
                blPaintRect = true;
                if(srcPoint == null){
                    srcPoint = e.getPoint();
                    destPoint = e.getPoint();
                }
                else{
                    destPoint = e.getPoint();
                }
                // As the user drags the mouse , the new co-ordinates are stored
                // in destPoint variable and the intial point in
                // srcPoint variable

                d.reset();
                d.addPoint(srcPoint.x, srcPoint.y);
                d.addPoint(destPoint.x, srcPoint.y);
                d.addPoint(destPoint.x, destPoint.y);
                d.addPoint(srcPoint.x, destPoint.y);

                myPanel.repaint();
            }
        } );

        myPanel.addMouseListener(new MouseAdapter(){
            public void mouseReleased(MouseEvent e) {
                blPaintRect = false;
                srcPoint = null;
                myPanel.repaint();
            }
        });
        
        add(myPanel, BorderLayout.CENTER);
        pack();

        setSize(300, 300);
        setLocation(300, 100);
        setTitle("Java Speed Test");
        setVisible(true);
    }

    public void paint2(Graphics g){
        if(blPaintRect){
            super.paint(g);
            Graphics2D  g2d = (Graphics2D) g;
            g2d.setComposite(alcomp);
            // One optimisation is that ,
            // drawPolygon  be skipped , and only fillPolygon can be used
            g2d.drawPolygon(d);
            g2d.fillPolygon(d);
        }
        else{
            super.paint(g);
        }
    }

    public static void main(String args[]) {
        new DragTest2().setVisible(true);
    }

}
camickr
When i tried my code (courtesy : your code !! ) with overriding a JPanel paint method ,
Actually JVaudry overrode the paintComponent(...) method of JPanel, which is what you should be doing. In your particular example if probably won't make a difference, but overriding paint(..) is not the best approach. Read the [url http://java.sun.com/docs/books/tutorial/uiswing/14painting/concepts.html]Painting tutorial for more information.
843805
yeah, i guess the main thing was to paint on the JPanel instead of the frame. The double buffering was not really needed.
1 - 4
Locked Post
New comments cannot be posted to this locked post.

Post Details

Locked on Aug 30 2006
Added on Aug 2 2006
4 comments
377 views