Search code examples
javaswinguser-interfacejscrollpanegraphics2d

How to smoothen scrolling of JFrame in Java


I have a JFrame in my Java application that contains a JPanel where I have some drawing objects created at run-time. The problem is while scrolling the JFrame for large figures the scrolling slows up and scroll bar does not move smoothly. Please note I am using Graphics 2D object and doing repaint on scroll action.

Is there any way of smoothing the scrolling action of JFrame.

Here is some part of the code

public class DiagramPanel implements MouseListener{

    int click=0;
    Point p1;
    Point p2;
    private Dimension panelDimension;
    .... // variables

    public void go() {
        p1 = new Point();
        p2 = new Point();

        JFrame f = new JFrame();
        f.setVisible(true);
        f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        f.setSize(1200,500);
        panelx = new DiaPanel();
        panelx.setOpaque(true);
        panelx.setBackground(Color.white);
        panelx.setAutoscrolls(true);
        panelx.addMouseListener(this);


        JScrollPane scrollPane = new JScrollPane();

        // scrollPane.add(panelx);

        ClassRectangle tempRect = null;
        for (ClassRectangle rect : this.classRectangles) {
            tempRect = rect;
        }


        Rectangle rect = new Rectangle();
        rect.setBounds(tempRect.getW() - 100, 0, 1000,
                tempLife.getEndpointY() * 500);

        panelDimension = new Dimension(0,0);
        for (ClassRectangle rectx : classRectangles){
            panelDimension.width=rectx.getW()+300;
        }
        for (LifeLine life : lifeLines) {
            panelDimension.height=life.getEndpointY()+300;
        }

        scrollPane.setViewportView(panelx);
        panelx.computeVisibleRect(rect);
        JScrollPane scrollPane1 = new JScrollPane(panelx);

        panelx.setPreferredSize(panelDimension);
        panelx.repaint();
        panelx.revalidate();
        p1.x=0;
        p1.y=0;
        p2.y=panelDimension.height;
        p2.x=panelDimension.width;
        f.add( scrollPane1);
        scrollPane.revalidate();
        f.setBackground(Color.white);
    }

    public DiagramPanel(ArrayList<Rectangle> classRectangles,
            ArrayList<Pair> pairs, ArrayList<Line> lines,
            ArrayList<Life> meth) {

            // constructing obj of DrawingPanel Here
    }

    public class SeqDiaPanel extends JPanel {
        /**
         * 
         */

        private static final long serialVersionUID = 1L;

        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d2 = (Graphics2D) g;
            g2d2.setColor(Color.orange);

            //grid
            for (int i = 0; i < panelDimension.height; i++) {
                g2d2.drawLine(0, 0 + i * 5, panelDimension.width+1000, 0 + i * 5);

            }

            for (int i = 0; i < panelDimension.width; i++) {
                g2d2.drawLine(0 + i * 5, 0, 0 + i *5,panelDimension.height+300);
            }

            g2d2.setColor(Color.black);

            // objects 
            .......... some objects here


            }
            }
            // draw Lines

            Stroke drawingStroke = new BasicStroke(2, BasicStroke.CAP_BUTT,
                    BasicStroke.JOIN_BEVEL, 0, new float[] { 5 }, 0);
            // Stroke drawingStroke = new BasicStroke();
            Graphics2D g2d = (Graphics2D) g;
            g2d.setStroke(drawingStroke);
            for (Line life : lines) {
                g2d.drawLine(life.getStartpointX(), life.getStartpointY(),
                        life.getEndpointX(), life.getEndpointY());
                panelDimension.height=life.getEndpointY()+300;
            }

            // draw methodLfe
            for (Object2 ml1 : Obj2) {
                g2d2.fill3DRect(ml1.StartX(), ml1.getMethodStartY(),
                        ml1.getBreadth(), ml1.getEndX(),true);
            }

        }


    }

    // tobeused

    public int calculateWidth(String name){
        Font font = new Font("Serif", Font.BOLD, 12);
         FontMetrics metrics = new FontMetrics(font){

            /**
             * 
             */
            private static final long serialVersionUID = 1L;};
        int tempInt2=SwingUtilities.computeStringWidth( metrics, name);
        tempInt2=tempInt2+10;
        return tempInt2;
    }




    /*public class MouseClick implements MouseListener{
        Point p =  new Point(0,0);
        @Override
        public void mouseClicked(MouseEvent evnt) {

            p.x=evnt.getX();
            p.y=evnt.getY();
            System.out.println("MouseClicked @"+p.x+":"+p.y);

        }

        @Override
        public void mouseEntered(MouseEvent arg0) {
            // TODO Auto-generated method stub

        }

        @Override
        public void mouseExited(MouseEvent arg0) {
            // TODO Auto-generated method stub

        }

        @Override
        public void mousePressed(MouseEvent arg0) {
            // TODO Auto-generated method stub

        }

        @Override
        public void mouseReleased(MouseEvent arg0) {
            // TODO Auto-generated method stub

        }

    }*/

    @Override
    public void mouseClicked(MouseEvent evnt) {
        click++;
        if(click==1){
        //Point p= new Point();
        p1.x=evnt.getX();
        p1.y=evnt.getY();
    //  System.out.println("MouseClicked1 @"+p1.x+":"+p1.y);
        }

        if(click==2){
            p2.x=evnt.getX();
            p2.y=evnt.getY();
            //System.out.println("MouseClicked2 @"+p2.x+":"+p2.y);
            click=0;
            if(p1.x<p2.x&&p1.y<p2.y){
            panelx.repaint();
            }
            else{

            }

        }/*else{
            p1.x=0;
            p1.y=0;
            p2.x=panelDimension.width+500;
            p2.y=panelDimension.height+700;
        }*/
    }

    @Override
    public void mouseEntered(MouseEvent arg0) {
        // TODO Auto-generated method stub

    }

    @Override
    public void mouseExited(MouseEvent arg0) {
        // TODO Auto-generated method stub

    }

    @Override
    public void mousePressed(MouseEvent arg0) {
        // TODO Auto-generated method stub

    }

    @Override
    public void mouseReleased(MouseEvent arg0) {
        // TODO Auto-generated method stub

    }
}

Solution

  • Why not put the Graphics2D drawing in a (large) BufferedImage and display it in a label in a scroll-pane? Something like this (animated, 5000x5000px):

    import java.awt.*;
    import java.awt.event.*;
    import java.awt.image.BufferedImage;
    import java.util.Random;
    import javax.swing.*;
    
    public class BigScrollImage {
    
        BigScrollImage() {
            final int x = 5000;
            final int y = 5000;
            final BufferedImage bi = new BufferedImage(x,y,BufferedImage.TYPE_INT_RGB);
            Graphics2D g1 = bi.createGraphics();
    
            g1.setColor(Color.BLACK);
            g1.fillRect(0, 0, x, y);
    
            g1.dispose();
    
            final JLabel label = new JLabel(new ImageIcon(bi));
    
            ActionListener listener = new ActionListener() {
                Random rand = new Random();
                @Override
                public void actionPerformed(ActionEvent ae) {
                    Graphics2D g2 = bi.createGraphics();
                    int x1 = rand.nextInt(x);
                    int x2 = rand.nextInt(x);
                    int y1 = rand.nextInt(y);
                    int y2 = rand.nextInt(y);
                    int r = rand.nextInt(255);
                    int g = rand.nextInt(255);
                    int b = rand.nextInt(255);
                    g2.setColor(new Color(r,g,b));
                    g2.drawLine(x1,y1,x2,y2);
    
                    g2.dispose();
                    label.repaint();
                }
            };
    
            Timer t = new Timer(5,listener);
    
            JScrollPane scroll = new JScrollPane(label);
            JFrame f = new JFrame("Big Scroll");
            f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    
            f.add(scroll);
            f.pack();
            f.setSize(800, 600);
    
            f.setLocationByPlatform(true);
            f.setVisible(true);
            t.start();
        }
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable(){
                @Override
                public void run() {
                    new BigScrollImage();
                }
            });
        }
    }
    

    It tries to draw 200 hundred lines per second, and seems to scroll smoothly here.