Forum Stats

  • 3,728,688 Users
  • 2,245,675 Discussions
  • 7,853,703 Comments

Discussions

Can someone optimise the following code ?

843805
843805 Member Posts: 49,999
edited August 2006 in Swing
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
    843805 Member Posts: 49,999
    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
    843805 Member Posts: 49,999
    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
    camickr Member Posts: 24,931
    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
    843805 Member Posts: 49,999
    yeah, i guess the main thing was to paint on the JPanel instead of the frame. The double buffering was not really needed.
This discussion has been closed.