4 Replies Latest reply: Feb 5, 2009 12:11 AM by 843799 RSS

    Adding ScrollPane to my canvas

    843799
      I have a problem in adding scrollpane to my canvas. Below is my zoom program. i want to add scrollpane. in that the scroll bars should be enabled when i start zooming.. how can i accomplish this
      public class AffineTransformTest extends JFrame {
           private static TransformingCanvas canvas;
            static BufferedImage image;
           public static void main(String[] args) throws IOException {
                JFrame frame = new JFrame();
                String path = "123.jpg";
                   image = ImageIO.read(new File(path));
                canvas = new TransformingCanvas();
                TranslateHandler translater = new TranslateHandler();
                canvas.addMouseListener(translater);
                canvas.addMouseMotionListener(translater);
                frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                canvas.addMouseWheelListener(new ScaleHandler());
                frame.getContentPane().add(canvas,BorderLayout.CENTER);
                frame.setSize(100, 100);
                frame.setVisible(true);
           }
       
           private static class TransformingCanvas extends JComponent {
                private double translateX;
                private double translateY;
                private double scale;
       
                TransformingCanvas() {
                     translateX = 0;
                     translateY = 0;
                     scale = 1;
                     setOpaque(true);
                     setDoubleBuffered(true);
                }
       
                @Override public void paint(Graphics g) {
       
                     AffineTransform tx = new AffineTransform();
                     tx.translate(translateX, translateY);
                     tx.scale(scale, scale);
                     Graphics2D ourGraphics = (Graphics2D) g;
                     ourGraphics.setColor(Color.WHITE);
                     ourGraphics.fillRect(0, 0, getWidth(), getHeight());
                     ourGraphics.setTransform(tx);
                     ourGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                               RenderingHints.VALUE_ANTIALIAS_ON);
                     ourGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                               RenderingHints.VALUE_TEXT_ANTIALIAS_ON);               
                     ourGraphics.setColor(Color.RED);
                        ourGraphics.drawImage(image,20,20,this);
                }
           }
       
           private static class TranslateHandler implements MouseListener,
                     MouseMotionListener {
                private int lastOffsetX;
                private int lastOffsetY;
       
                public void mousePressed(MouseEvent e) {
                     // capture starting point
                     lastOffsetX = e.getX();
                     lastOffsetY = e.getY();
                }
       
                public void mouseDragged(MouseEvent e) {
                     
                     // new x and y are defined by current mouse location subtracted
                     // by previously processed mouse location
                     int newX = e.getX() - lastOffsetX;
                     int newY = e.getY() - lastOffsetY;
       
                     // increment last offset to last processed by drag event.
                     lastOffsetX += newX;
                     lastOffsetY += newY;
       
                     // update the canvas locations
                     canvas.translateX += newX;
                     canvas.translateY += newY;
                     
                     // schedule a repaint.
                     canvas.repaint();
                }
       
                public void mouseClicked(MouseEvent e) {}
                public void mouseEntered(MouseEvent e) {}
                public void mouseExited(MouseEvent e) {}
                public void mouseMoved(MouseEvent e) {}
                public void mouseReleased(MouseEvent e) {}
           }
       
           private static class ScaleHandler implements MouseWheelListener {
                public void mouseWheelMoved(MouseWheelEvent e) {
                     if(e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL) {
                          
                          // make it a reasonable amount of zoom
                          // .1 gives a nice slow transition
                          canvas.scale += (.1 * e.getWheelRotation());
                          // don't cross negative threshold.
                          // also, setting scale to 0 has bad effects
                          canvas.scale = Math.max(0.00001, canvas.scale); 
                          canvas.repaint();
                     }
                }
           }
       
      }
        • 1. Re: Adding ScrollPane to my canvas
          843799
          you should use JScrollPane instead of canvas
          • 2. Re: Adding ScrollPane to my canvas
            843799
            First, a few minor changes. Change
             public void paint(Graphics g) {}
            to
            public void paintComponent(Graphics g) {}
            You should override paintComponent for Swing and not paint

            Change
            ourGraphics.drawImage(image,20,20,this);
            to
            ourGraphics.drawImage(image,0,0,this);
            The (20,20) offset gets scaled with the transform. So the image slowly drifts to the bottom right as it scales. I don't imagine you wanted this to happen.

            Change
            ourGraphics.setTransform(tx);
            to
            ourGraphics.transform(tx);
            The graphics object may already have a transform on it. You need to concat your transformation instead of set it. Otherwise painting artifacts will occur when only a partial repaint is done on the canvas (try moving the frame slightly out of the destop view and bring it back into view to see what I mean).

            Now to add automatic scrolling you

            1) Add the canvas to a scroll pane, and add the scroll pane to the frame.

            2) Override the getPreferredSize() method of your canvas like so,
            public Dimension getPreferredSize() {
               return new Dimension((int) (image.getWidth() * scale + translateX),
                                     (int) (image.getHeight() * scale + translateY));
            }
            3) Whenever the canvas has a reason its size may have change, you add canvas.revalidate(). That is, everywhere you see this
            canvas.repaint();
            change it to
            canvas.revalidate();
            canvas.repaint();
            This is at two spots in your code.
            • 3. Re: Adding ScrollPane to my canvas
              843799
              Thanks..It worked perfectly. But i have another doubt now.. My canvas is at the top left corner. How can i place the canvas at the centre of the frame... also now the zoom happens from top left corner. how can i make it centered zoom..
              • 4. Re: Adding ScrollPane to my canvas
                843799
                Raghavan wrote:
                How can i place the canvas at the centre of the frame...
                I'm not sure what you mean by this. Does the frame have other components besides the scrollpane/canvas combo? In the code you posted there's only the canvas and it should take up the whole view, with the exception of the scrollbars on the side.
                also now the zoom happens from top left corner. how can i make it centered zoom..
                center zoom?

                EDIT

                Oh, I think I know what you mean by center zoom. That will require you to reposition the scrollpane view.
                canvas.revalidate();
                canvas.repaint();
                scrollPane.getViewport().setViewPosition(newPoint);
                You'll need to do the math and figure out the correct view position.