2

I have a class that draw some very simple graphics like lines, circles and rectangles. The lines are dynamically expandable and sometimes when they expand beyond the resolution, it is impossible to see without a scroll bar. Therefore, I've added JScrollPane to my JFrame but unfortunately, the scroll bar is not scrollable despite calling the Layout Manager already.

Here's what I have: - A class that draws components (lines, rectangles, circles) - A class that sets up the JFrame/JScrollPane

Here's an excerpt code of my GUI class:

    JFrame frame = new JFrame("GUIFrame");
    frame.setLayout(new BorderLayout()); // Layout already set
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    DrawComponent comp = new DrawComponent(); // Reference to class that draw components
    JScrollPane sp = new JScrollPane(comp, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
    sp.setPreferredSize(new Dimension(1000, 1000));

    frame.add(sp, BorderLayout.CENTER);
    frame.setSize(500,500);
    frame.setVisible(true);

With the code above, I've got Java to show me a JFrame with scrollpane containing my jcomponents. I have set the scrollbars to always appear as shown above but they are not scrollable, gray-ed out.

As suggested by Andrew, I took sometime to create a SSCCE to reflect what I'm trying to do:

import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import java.util.Random;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;


public class DrawTest {
    public static void main(String[] args){
        JFrame frame = new JFrame("SSCCE");
        frame.setLayout(new BorderLayout());
        frame.setSize(1000, 1000);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);       

        DrawComp d = new DrawComp();
        JScrollPane sp = new JScrollPane(d, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);

        frame.add(sp);      
        frame.setVisible(true);
    }
}

class DrawComp extends JComponent {

    public void paintComponent(Graphics g){
        Graphics2D g2 = (Graphics2D)g;

        Random ran = new Random();
        int ranNum = ran.nextInt(10);
        System.out.println(ranNum);
        double length = 100 * ranNum;
        g2.draw(new Line2D.Double(10, 10, length, length));
    }
}

The code above draws a diagonal line based on a random input. What I intend to do is that when the line gets so long that it goes out of the frame size, I hope that I'll be able to scroll and have a view of the full line. Again I have added the line component to JScrollPane but it's not scroll-able.

James Riden
  • 101
  • 1
  • 9
  • 1) For better help sooner, post an [SSCCE](http://sscce.org/). 2) `comp.setPreferredSize(new Dimension(1000, 1000)); sp.validate(); //sp.setPreferredSize(new Dimension(1000, 1000));` 3) `frame.pack();` – Andrew Thompson Jan 02 '13 at 03:46
  • I think you need to have a look at [how to use scroll panes](http://docs.oracle.com/javase/tutorial/uiswing/components/scrollpane.html) to get a better understanding of how they work. `sp.setPreferredSize(new Dimension(1000, 1000));` isn't going to effect the scrollable area, but the size of the component. The `ViewPort` is responsible for determining the scrollable area (at least from the perspective of what you are trying to achieve – MadProgrammer Jan 02 '13 at 04:08
  • Thank's for the help but I was under the impression that the use of setPreferredSize is discouraged? – James Riden Jan 02 '13 at 04:20
  • *"I was under the impression that the use of setPreferredSize is discouraged"* It ***is*** amongst the [top 5 in the FAQ](http://stackoverflow.com/questions/tagged/java?sort=faq&pagesize=5). Any chance of seeing that SSCCE? Better advice comes from code to play with. – Andrew Thompson Jan 02 '13 at 04:26
  • Designed a simple class to reflect on what I was doing as suggested by Andrew. – James Riden Jan 02 '13 at 05:19

2 Answers2

1

My apologies. You are using JScrollPane the right way. I ran your code and I think I got the reason why JScrollPane is not working. Picture this, when your set the jframe's background to all red (by paiting a red dot everywhere) should the jscrollpane be scrollable? No, because painting the background color is in the background. The actual VIEW isnt changing and it is not bigger then the display size so the scrollpane does not see the point of scrolling. Your paint component method is doing something similar. It is just drawing something in the background. The actual VIEW didnt change so scrollpane wont work.

public class DrawTest {
    public static void main(String[] args){
        JFrame frame = new JFrame("SSCCE");
        frame.setLayout(new BorderLayout());
        frame.setSize(500, 500);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);       

        final DrawComp d = new DrawComp();
        final JScrollBar hbar,vbar;
        hbar = new JScrollBar(JScrollBar.HORIZONTAL, 0, 1, 0, 500);
        vbar = new JScrollBar(JScrollBar.VERTICAL, 0, 1, 0, 500);

        frame.setLayout(null);
        frame.add(d);      
        frame.add(hbar);      
        frame.add(vbar);      
        d.setBounds(0, 0, 300, 300);
        vbar.setBounds(460, 0, 20, 480);
        frame.setVisible(true);

        vbar.addAdjustmentListener(new AdjustmentListener() 
        {
            public void adjustmentValueChanged(AdjustmentEvent e) 
            {
                d.setLocation(d.getX(), -vbar.getValue());
            }
        });
    }
}

Here is the code for sliding a component vertically. I made some changes to your existing code. The DrawComp is still the same

  • I added my components to scroll pane in JScrollPane sp = new JScrollPane(comp). In order to show the scoll pane in the window, I'll have to add scroll pane to frame, isn't that right? I couldn't spot what I was doing wrong – James Riden Jan 02 '13 at 05:33
  • The size of a component is set first. All painting will happen in that component's size rectangle (Clip area). If you try to draw anything beyond that it will be just ignored. It will not scroll as you expect. – basiljames Jan 02 '13 at 06:12
  • My apologies. You are using JScrollPane the right way. I ran your code and I think I got the reason why JScrollPane is not working. –  Jan 02 '13 at 07:21
  • I tried getPreferredSize() and apparently it returned 0,0, which might just be the cause of this problem. Theoretically a layout manager should have had that handled - and I did set up a layout manager but it just doesn't work for some reason. @Xiaoerge would you mind enlightening me where's the error that caused it to not work? – James Riden Jan 02 '13 at 07:26
  • @Xiaoerge I have to admit that is slightly confusing there. How do I make the "actual view" change then, instead of just drawing in the background? – James Riden Jan 02 '13 at 07:39
  • Sorry. I could have said it more clearer. I think this might be a work around method. Paint the compoment the same way your are doing. But do not set a layout type for jframe. Use Null instead. (This let you set size and position). And dont use scrollpane. Use 2 scrollbars and when the user slide the scrollbar, *Move* the painted-componment left right up down to show a sliding effect. –  Jan 02 '13 at 07:53
  • frame.setLayout(null); frame.add(painted-com); scrollbar.addActionListener(//..... action codes) move your painted-com by doing painted-com.setLocation(scrollbar.getvalue.....) –  Jan 02 '13 at 07:55
  • @Xiaoerge - Thanks for all your help!! Greatly appreciated. Although I did not opt for your way in the end, I now understand where was the underlying problem. Enjoyed the learning! – James Riden Jan 02 '13 at 08:11
0

I have found a makeshift solution to my problem. Given how simple the drawing is, I have decided to use the end point of the line to override preferredSize.

Pertaining to the SSCCE I posted above, I added a setPreferredSize(new Dimension(length, length) in paintComponent() so that the preferredSize will always be the end point of the line when it is called. This makes sure that I have got the whole area of the painting covered and yet be able to scroll, should there be a need to.

James Riden
  • 101
  • 1
  • 9
  • 2
    Instead, override `getPreferredSize()`, as suggested [here](http://stackoverflow.com/q/7229226/230513). – trashgod Jan 02 '13 at 18:48
  • 1
    _added a setPreferredSize(new Dimension(length, length) in paintComponent()_ that's **extremely** smelly, violating two basic rules at the same time: a) never-ever change the state of the component in during the painting cycle b) don't call setPreferredSize at all. – kleopatra Mar 30 '13 at 10:00