Results 1 to 7 of 7
  1. #1
    yemista is offline Member
    Join Date
    Oct 2011
    Posts
    41
    Rep Power
    0

    Default forcing scrollpane to autoscroll

    Ok, this one should be easy, but I cant quite figure it out. Ive done some research, and found the way your supposed to do it, but it doesnt work. What I want to do is, in my drawing panel, when you try to draw too far to the right, resize the panel, and have it scroll all the way to the right. Here is my code:

    Java Code:
    public void scrollRight() {
            getHorizontalScrollBar().setValue(getHorizontalScrollBar().getMaximum());
            getHorizontalScrollBar().updateUI();
        }
    I can get it to reize just fine(which was a bit tricky in itself), but for some reason this wont work. I also tried calling validate instead of updateUI, but that didnt help either. ONce this works, I will probably scroll a bit at a time so the drawing can work easier, but for now scrolling to the maximum is fine just to get it to work. By the way, I know this code is being called because I put a print statement before it, so that is not the issue.
    Last edited by yemista; 05-19-2012 at 10:55 PM.

  2. #2
    DarrylBurke's Avatar
    DarrylBurke is offline Forum Police
    Join Date
    Sep 2008
    Location
    Madgaon, Goa, India
    Posts
    11,455
    Rep Power
    20

    Default Re: forcing scrollpane to autoscroll

    1. Don't call updateUI(). That's not what the method is for.
    2. How did you 'resize' the panel? There's (at least) one correct way and several wrong ways to try that.
    3. After 'resizing' the panel, did you revalidate() it's container / hierarchy?

    To get better help sooner, post a SSCCE (Short, Self Contained, Correct (Compilable), Example) that demonstrates the problem.

    db
    If you're forever cleaning cobwebs, it's time to get rid of the spiders.

  3. #3
    yemista is offline Member
    Join Date
    Oct 2011
    Posts
    41
    Rep Power
    0

    Default Re: forcing scrollpane to autoscroll

    ok, so i stripped away much of my old code, and created a SSCCE. The main difference between this and my code is that this doesnt have all the functions for drawing, but instead increases the width of the canvas on a mouseClicked event, but after that the behavior should be the same, resize the canvas, and supposedly, scroll to the right.

    Java Code:
    /**
     * To change this template, choose Tools | Templates
     * and open the template in the editor.
     */
    package test;
    
    
    import javax.swing.*;
    
    public class Test {
    
        /**
         * @param args the command line arguments
         */
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    new MyFrame();
                }
            });
        }
    }
    
    /**
     * To change this template, choose Tools | Templates
     * and open the template in the editor.
     */
    package test;
    
    import java.awt.*;
    import javax.swing.*;
    import java.util.*;
    import java.awt.event.*;
    
    public class DrawingPanel extends JScrollPane implements ComponentListener/**, MouseMotionListener */{
        private double width_percent;
        private CanvasPanel canvaspanel;
        private int padding;
        
        public DrawingPanel(Component content) {
            super(content);
            addComponentListener(this);
            canvaspanel = (CanvasPanel)content;
            setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
            setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
            //addMouseMotionListener(this);
        }
        
        @Override
        public Dimension getPreferredSize() {
            return new Dimension((int)(this.getParent().getWidth()), this.getParent().getHeight());
        }
        
        public void componentHidden(ComponentEvent e) {
            
        }
        
        public void componentMoved(ComponentEvent e) {
            
        }
        
        public void componentResized(ComponentEvent e) {
            setPreferredSize(new Dimension((int)(getParent().getWidth()), getParent().getHeight()));
            canvaspanel.componentResized(e);
            revalidate();
        }
        
        public void componentShown(ComponentEvent e) {
            
        }
        
       /** public void mouseMoved(MouseEvent e) {
            setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR ));
            canvaspanel.mouseMoved(e);
            //System.out.println(getHorizontalScrollBar().getValue());
        }
    
        public void mouseDragged(MouseEvent e) {
           
        }*/
        
        public void scrollDown() {
            getVerticalScrollBar().setValue(getVerticalScrollBar().getMaximum());
            getVerticalScrollBar().updateUI();
        }
        
        public void scrollRight() {
            //System.out.println("here");
            this.getHorizontalScrollBar().setValue(this.getHorizontalScrollBar().getMaximum());
            this.getHorizontalScrollBar().updateUI();
        }
    }
    
    /**
     * To change this template, choose Tools | Templates
     * and open the template in the editor.
     */
    package test;
    
    import java.awt.*;
    import javax.swing.*;
    import java.awt.event.*;
    import java.awt.geom.*;
    import java.util.*;
    
    public class CanvasPanel extends JComponent implements ComponentListener, MouseMotionListener, MouseListener {
        
        
        private Image image;
        private Graphics2D graphics2D;
        
        private int height;
        private int width;
        private int old_height;
        private int old_width;
       
        private int old_x, old_y;
        
        private DrawingPanel father;    
    
        public CanvasPanel(int width, int height) {
            super();       
            this.width = width;
            this.height = height;
            old_width = width;
            old_height = height;
            setPreferredSize(new Dimension(width, height));
            //this.setSize(width, height);
            revalidate();
            //this.setVisible(true);
            addMouseMotionListener(this);
            addMouseListener(this);
        }
        
        public void setFather(DrawingPanel p) {
            father = p;
        }
        
        @Override
        public void paintComponent(Graphics g){  
            super.paintComponent(g);
            
            if(image == null){
                image = createImage(getParent().getSize().width, getParent().getSize().height);
                graphics2D = (Graphics2D)image.getGraphics();
                graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                
            }
            
            else if(this.width < getParent().getSize().width || this.height < getParent().getSize().height) {
                image = createImage(getParent().getSize().width, getParent().getSize().height);
                this.width = getParent().getSize().width;
                this.height = getParent().getSize().height;
                graphics2D = (Graphics2D)image.getGraphics();
                graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                
            }
            else if(old_height < height || old_width < width) {
                //System.out.println("here");
                setSize(width, height);
                image = createImage(width, height);
                graphics2D = (Graphics2D)image.getGraphics();
                graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                
                if(old_width < width)
                    father.scrollRight();
                if(old_height < height)
                    father.scrollDown();
                
                old_width = width;
                old_height = height;
                getParent().validate();
            }
            
            clear();
            g.drawImage(image, 0, 0, null);
         }
        
        @Override
        public void paint(Graphics g){  
            super.paintComponent(g);
            paintComponent(g);
         }
        
        @Override
        public Dimension getPreferredSize() {
            return new Dimension(width, height);
        }
         
        public void clear(){
            graphics2D.setPaint(Color.white);
            graphics2D.fillRect(0, 0, this.width, this.height);
            graphics2D.setPaint(Color.black);
            
         }
    
        public void componentHidden(ComponentEvent e) {
            
        }
        
        public void componentMoved(ComponentEvent e) {
            
        }
        
        public void componentResized(ComponentEvent e) {
            if(getParent().getWidth() > width || getParent().getHeight() > height) {
                this.width = getParent().getWidth();
                this.height = getParent().getHeight();
            }
            repaint();
            revalidate();
        }
        
        public void componentShown(ComponentEvent e) {
            
        }
        
        public void mouseMoved(MouseEvent e) {
            
        }
    
        public void mouseDragged(MouseEvent e) {
            
        }
        
        public void mousePressed(MouseEvent e) {
     
        }
    
        public void mouseReleased(MouseEvent e) {
         
        }
    
        public void mouseEntered(MouseEvent e) {
           
        }
    
        public void mouseExited(MouseEvent e) {
           
        }
    
        public void mouseClicked(MouseEvent e) {
            width*= 2;
            
             SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    repaint();
                }
            });
        }
    }
    
    /**
     * To change this template, choose Tools | Templates
     * and open the template in the editor.
     */
    package test;
    
    import java.awt.*;
    import javax.swing.*;
    import java.util.*;
    import java.awt.event.*;
    
    public class MyFrame extends JFrame implements  ComponentListener {
        private int width;
        private int height;
        private Container content;
        private CanvasPanel canvas;
        private DrawingPanel drawingpanel;
        
        public MyFrame() {
            super();
            Toolkit toolkit =  Toolkit.getDefaultToolkit();
            Dimension screen = toolkit.getScreenSize();
            width = (screen.width > 800 ? 800 : screen.width);
            height = (screen.height > 600 ? 600 : screen.width);
            this.setSize(width,height);
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            content = this.getContentPane();
            content.setSize(width,height);
            canvas = new CanvasPanel(width, height);
            drawingpanel = new DrawingPanel(canvas);
            canvas.setFather(drawingpanel);
            //mainpanel.addComponentListener(this);
            content.add(drawingpanel);
            pack();
            this.setVisible(true);
            this.addComponentListener(this);
        }
        
        public void componentResized(ComponentEvent e) {
            if(this.getWidth() < this.width){
               setSize(this.width,this.getHeight());
            }   
            if(this.getHeight() < this.height) {
               setSize(getWidth(),this.height);
            } 
           
            drawingpanel.componentResized(e);
            content.validate();
            //pack();
        }
        
        public void componentHidden(ComponentEvent e) {
            
        }
        
        public void componentMoved(ComponentEvent e) {
            
        }
        
        public void componentShown(ComponentEvent e) {
            
        }
        
    }
    Last edited by DarrylBurke; 05-20-2012 at 07:30 PM. Reason: Edited to overcome forum formatting bug

  4. #4
    DarrylBurke's Avatar
    DarrylBurke is offline Forum Police
    Join Date
    Sep 2008
    Location
    Madgaon, Goa, India
    Posts
    11,455
    Rep Power
    20

    Default Re: forcing scrollpane to autoscroll

    4 classes complete with inane IDE generated comments is not a SSCCE. But looking through that mess, I do see state-changing method calls within a painting method override. You need to get rid of that immediately.

    Here's a working SSCCE. Figure out how to adapt it to your program.
    Java Code:
    import java.awt.*;
    import javax.swing.*;
    import javax.swing.border.*;
    import javax.swing.event.*;
    
    public class ScrollOnResize {
    
      public static void main(String[] args) throws Exception {
        SwingUtilities.invokeLater(new Runnable() {
    
          @Override
          public void run() {
            new ScrollOnResize().makeUI();
          }
        });
      }
    
      public void makeUI() {
        final JPanel panel = new JPanel();
        panel.setBorder(new CompoundBorder(new LineBorder(Color.RED), new LineBorder(Color.BLUE)));
        final JScrollPane scrollPane = new JScrollPane(panel);
    
        final JSlider slider = new JSlider(400, 4000, 400);
        slider.addChangeListener(new ChangeListener() {
    
          @Override
          public void stateChanged(ChangeEvent e) {
            if (!slider.getValueIsAdjusting()) {
              int newSize = slider.getValue();
              panel.setPreferredSize(new Dimension(newSize, newSize));
              panel.revalidate();
              final JScrollBar scrollBar = scrollPane.getHorizontalScrollBar();
              SwingUtilities.invokeLater(new Runnable() {
    
                @Override
                public void run() {
                  scrollBar.setValue(scrollBar.getMaximum());
                }
              });
            }
          }
        });
    
        JFrame frame = new JFrame();
        frame.add(scrollPane, BorderLayout.CENTER);
        frame.add(slider, BorderLayout.SOUTH);
    
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(400, 400);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
      }
    }
    db
    If you're forever cleaning cobwebs, it's time to get rid of the spiders.

  5. #5
    kjkrum's Avatar
    kjkrum is offline Senior Member
    Join Date
    Apr 2011
    Location
    Tucson, AZ
    Posts
    1,060
    Rep Power
    6

    Default Re: forcing scrollpane to autoscroll

    I'm not sure if my code would be adaptable to your needs, but this seems to be a common problem, and I think my solution is the cleanest one around.

    I created a custom text component and I wanted it to behave like a typical terminal. If it's scrolled to the bottom when a new line is appended, it remains scrolled to the bottom. If it's not scrolled to the bottom when new text is added, it scrolls its viewport so the same text remains visible until it scrolls off the top of the buffer.

    I achieved this by customizing the viewport layout manager of JScrollPane and making the component that was to be placed in the JScrollPane implement a new interface, StickyScrollable. StickyScrollable's only method (in addition to those of Scrollable, which it extends) informs the scroll pane where the component wants the viewport scrolled.

    Java Code:
    package krum.swing;
    
    import java.awt.Component;
    import java.awt.Container;
    import java.awt.Dimension;
    import java.awt.Point;
    import java.awt.Rectangle;
    
    import javax.swing.JViewport;
    import javax.swing.ViewportLayout;
    
    public class StickyViewportLayout extends ViewportLayout {
    	private static final long serialVersionUID = 1L;
    	
    	protected int previousHeight = 0;
    
    	// TODO: stick all Scrollables to the bottom, and honor
    	// the desired scroll offset of StickyScrollables.
    	
    	@Override
    	public void layoutContainer(Container parent) {
    		JViewport viewport = (JViewport) parent;
    		Component view = viewport.getView();
    		if(view instanceof StickyScrollable) {
    			StickyScrollable component = (StickyScrollable) view;
    			Rectangle visible = viewport.getViewRect();
    			Dimension size = viewport.getViewSize();
    			//boolean atBottom = (visible.y == size.height - visible.height);
    			boolean atBottom = (visible.y == size.height - visible.height ||
    					(previousHeight < visible.height && size.height > visible.height));
    			previousHeight = size.height;
    			super.layoutContainer(parent);
    			if(atBottom) {
    				// lie to the component, make it think we're scrolling it where it wants
    				component.getScrollOffset();
    				// actually scroll it to the bottom
    				size = viewport.getViewSize();
    				visible.y = size.height - visible.height;
    				viewport.setViewPosition(visible.getLocation());
    			}
    			else {
    				Point scrollOffset = component.getScrollOffset();
    				visible.x += scrollOffset.x;
    				if(visible.x < 0) visible.x = 0;
    				visible.y += scrollOffset.y;
    				if(visible.y < 0) visible.y = 0;
    				viewport.setViewPosition(visible.getLocation());
    			}
    		}
    		else super.layoutContainer(parent);
    	}
    }

    Java Code:
    package krum.swing;
    
    import java.awt.Point;
    
    import javax.swing.Scrollable;
    
    public interface StickyScrollable extends Scrollable {
    	/**
    	 * Called by a <tt>StickyScrollPane</tt>'s viewport layout to determine
    	 * where a component wants its viewport scrolled relative to the current
    	 * viewport.  This method should have the side effect of resetting the
    	 * component's desired scroll offset to (0, 0).
    	 * 
    	 * @return this component's desired relative scroll
    	 * @see StickyScrollPane
    	 */
    	public abstract Point getScrollOffset();
    }
    Java Code:
    package krum.swing;
    
    import java.awt.Component;
    
    import javax.swing.JScrollPane;
    
    /**
     * A scroll pane with a viewport layout that recognizes
     * <tt>StickyScrollable</tt> components.  If the viewport is at the bottom
     * when the component's height increases, it will be kept at the bottom.  If
     * the component wishes to adjust its viewport, such as to maintain a view of
     * the same data as it scrolls through a circular buffer, it can communicate
     * this to the layout manager using the methods of <tt>StickyScrollable</tt>.
     *
     * @author Kevin Krumwiede (kjkrum@gmail.com)
     * @see StickyScrollable
     */
    public class StickyScrollPane extends JScrollPane {
    	private static final long serialVersionUID = 1L;
    	
    	public StickyScrollPane() {
    		super();
    		replaceViewportLayout();
    	}
    
    	public StickyScrollPane(Component view, int vsbPolicy, int hsbPolicy) {
    		super(view, vsbPolicy, hsbPolicy);
    		replaceViewportLayout();
    	}
    
    	public StickyScrollPane(Component view) {
    		super(view);
    		replaceViewportLayout();
    	}
    
    	public StickyScrollPane(int vsbPolicy, int hsbPolicy) {
    		super(vsbPolicy, hsbPolicy);
    		replaceViewportLayout();
    	}
    
    	protected void replaceViewportLayout() {
    		viewport.setLayout(new StickyViewportLayout());
    	}
    }
    Last edited by kjkrum; 05-26-2012 at 08:16 AM.
    Get in the habit of using standard Java naming conventions!

  6. #6
    DarrylBurke's Avatar
    DarrylBurke is offline Forum Police
    Join Date
    Sep 2008
    Location
    Madgaon, Goa, India
    Posts
    11,455
    Rep Power
    20

    Default Re: forcing scrollpane to autoscroll

    Quote Originally Posted by kjkrum View Post
    I created a custom text component and I wanted it to behave like a typical terminal. If it's scrolled to the bottom when a new line is appended, it remains scrolled to the bottom. If it's not scrolled to the bottom when new text is added, it scrolls its viewport so the same text remains visible until it scrolls off the top of the buffer.
    If I'm reading that description correctly, you can achieve it by setting the caret's update policy.

    This code was originally posted at https://forums.oracle.com/forums/thr...readID=1352982 with a link to camickr's Text Area Scrolling Java Tips Weblog
    Java Code:
    import java.awt.BorderLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.AdjustmentEvent;
    import java.awt.event.AdjustmentListener;
    import javax.swing.*;
    import javax.swing.text.DefaultCaret;
     
    public class ScrollControl {
     
       JTextArea textArea;
       JScrollBar scrollBar;
       DefaultCaret caret;
       BoundedRangeModel model;
     
       public static void main(String[] args) {
          SwingUtilities.invokeLater(new Runnable() {
     
             @Override
             public void run() {
                new ScrollControl().makeUI();
             }
          });
       }
     
       public void makeUI() {
          textArea = new JTextArea(20, 30);
          textArea.setWrapStyleWord(true);
          textArea.setLineWrap(true);
          caret = (DefaultCaret) textArea.getCaret();
          
          JScrollPane scrollPane = new JScrollPane(textArea);
          scrollBar = scrollPane.getVerticalScrollBar();
          model = scrollBar.getModel();
          scrollBar.addAdjustmentListener(new AdjustmentListener() {
     
             public void adjustmentValueChanged(AdjustmentEvent e) {
                if (model.getValue() == model.getMaximum() - model.getExtent()) {
                   caret.setDot(textArea.getText().length());
                   caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
                } else {
                   caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE);
                }
             }
          });
     
          JButton button = new JButton("Click");
          button.addActionListener(new ActionListener() {
     
             public void actionPerformed(ActionEvent e) {
                for (int i = 0; i < 10; i++) {
                   textArea.append("The quick brown fox jumps over the lazy dog. ");
                }
             }
          });
          
          JFrame frame = new JFrame();
          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          frame.setSize(400, 400);
          frame.add(scrollPane, BorderLayout.CENTER);
          frame.add(button, BorderLayout.SOUTH);
          frame.setLocationRelativeTo(null);
          frame.setVisible(true);
       }
    }
    db
    If you're forever cleaning cobwebs, it's time to get rid of the spiders.

  7. #7
    kjkrum's Avatar
    kjkrum is offline Senior Member
    Join Date
    Apr 2011
    Location
    Tucson, AZ
    Posts
    1,060
    Rep Power
    6

    Default Re: forcing scrollpane to autoscroll

    Well, mine's not a text component in the sense of extending JTextComponent. It's actually a graphical component that renders text using tiles from a sprite sheet. (Very fast!) My approach could be extended to any component that wants to control its viewport position as the component's size changes. A more generally useful version of my StickyViewportLayout would consider the component's width as well as its height, and provide the option to stick to any of its sides.

    The nice thing about my approach is that it happens automatically whenever the scroll pane is repainted. Also, it happens ONLY when the scroll pane is repainted; you're not creating a bunch of Runnable instances, many of which will be redundant if the component's size changes more frequently than the container is repainted.
    Get in the habit of using standard Java naming conventions!

Similar Threads

  1. GridBagLayout - forcing all components to stay on top
    By Serpenthelm in forum AWT / Swing
    Replies: 3
    Last Post: 01-05-2012, 07:52 PM
  2. forcing a thread to run
    By yemista in forum Threads and Synchronization
    Replies: 6
    Last Post: 11-03-2011, 07:12 PM
  3. How to autoscroll a JScrollPane
    By Junky in forum AWT / Swing
    Replies: 2
    Last Post: 03-10-2011, 10:32 PM
  4. Forcing the mouse to stay quiet
    By ProspectiveDeveloper in forum AWT / Swing
    Replies: 4
    Last Post: 05-03-2010, 12:17 AM
  5. Forcing a thread to stop
    By sukatoa in forum Threads and Synchronization
    Replies: 7
    Last Post: 07-17-2009, 07:41 AM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •