3

I've found some examples scattered around the internet involving getting an image or a textbox to display scroll bars, but they all involve a program that basically displays its entire contents in a scroll pane. What I need to get it to do is stick a JPanel somewhere, pile a bunch of text, icons, etc into that panel until its too big for the space I've got for it, and then scroll across it.

I'm probably going to need to be able to null-layout that panel, too, because I'm probably going to have to manually position things within it sooner or later.

So I tried to make a pretty simply program that would put three colored blocks in a space big enough for two, and display a scrollbar that would let you scroll down to see the third one. It doesn't add the scroll bar.

The imports are a bit of a mess and redundant, because this is cobbled together from a couple different files, but they're not generating any errors.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

import java.awt.BorderLayout;
import java.awt.GridLayout;

import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;

public class ScrollDemo extends JFrame {

  JScrollPane scrollpane;

  public ScrollDemo() {
    super("JScrollPane Demonstration");
    setSize(800, 600);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    init();
    setVisible(true);
  }

  public void init() {
    setLayout(null);
    JPanel innerPanel = new JPanel();
    JPanel outerPanel = new JPanel();
    getContentPane().setBounds(0,0,800,600);
    outerPanel.setBounds(400,0,400,400);
    innerPanel.setBounds(0,0,600,600);
    innerPanel.setLayout(null);

    JPanel greenPanel = new JPanel();
    JPanel yellowPanel = new JPanel();
    JPanel bluePanel = new JPanel();

    greenPanel.setBounds(0,0,200,200);
    yellowPanel.setBounds(0,200,200,200);
    bluePanel.setBounds(0,400,200,200);
    greenPanel.setBackground(Color.GREEN);
    yellowPanel.setBackground(Color.YELLOW);
    bluePanel.setBackground(Color.BLUE);

    innerPanel.add(greenPanel);
    innerPanel.add(yellowPanel);
    innerPanel.add(bluePanel);
    JScrollPane scrollPane = new JScrollPane();
    scrollPane.setViewportView(innerPanel);
    scrollPane.setBounds(200,0,200,400);
    add(scrollPane);


  }

  public static void main(String args[]) {
    new ScrollDemo();
  }
}
mKorbel
  • 109,525
  • 20
  • 134
  • 319
user1299656
  • 630
  • 1
  • 9
  • 15

3 Answers3

4

Better that you should use layout managers to your advantage and to let these managers do the heavy lifting of calculating component sizes and placements for you. For example:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;

import javax.swing.*;

public class ScrollDemo2 extends JPanel {
   public static final Color[] COLORS = {Color.green, Color.red, Color.blue};
   private static final Dimension PANEL_SIZE = new Dimension(300, 300);
   public ScrollDemo2() {
      JPanel innerPanel = new JPanel(new GridLayout(0, 1));
      for (int i = 0; i < COLORS.length; i++) {
         JPanel colorPanel = new JPanel();
         colorPanel.setPreferredSize(PANEL_SIZE);
         colorPanel.setBackground(COLORS[i]);
         innerPanel.add(colorPanel);
      }
      JScrollPane scrollPane = new JScrollPane(innerPanel);
      scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
      scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
      scrollPane.getViewport().setPreferredSize(PANEL_SIZE);

      int eb = 10;
      setBorder(BorderFactory.createEmptyBorder(eb, eb, eb, eb));
      setLayout(new BorderLayout());
      add(scrollPane, BorderLayout.CENTER);
   }

   private static void createAndShowGui() {
      ScrollDemo2 mainPanel = new ScrollDemo2();

      JFrame frame = new JFrame("ScrollDemo2");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
4

In Swing, sizing and positioning of children is the exclusive job of a LayoutManager. Choose one that supports your requirements, as a last resort implement a highly specialized one. Children collaborate by reporting sizing hints, so implement any custom components to return something reasonable in the getXXSize methods.

When you feel an irresistable urge to manually interfere, at least let the manager do as much as possible. In your context that might be to take over the positioning but let the manager handle the sizing, particularly calculating the sizing hints of the parent. Here's a code snippet using Rob's DragLayout:

DragLayout layout = new DragLayout();
JComponent field = new JPanel(layout);
JComponent player = new JLabel("I'm moving around");
field.add(player);
player.setLocation(200, 200);
frame.add(new JScrollPane(field));
frame.pack();
frame.setVisible(true);
kleopatra
  • 51,061
  • 28
  • 99
  • 211
1

Figures. Soon as I post I realize what's wrong.

Because innerPanel has a null Layout it needs to have its preferred size explicitly declared.

    innerPanel.setPreferredSize(new Dimension(200,600));

fixes it.

user1299656
  • 630
  • 1
  • 9
  • 15
  • In fact you really should read up on and learn to use the layout managers. Your Swing experience and GUI quality and maintainability will improve greatly if you do so. – Hovercraft Full Of Eels Jul 08 '12 at 00:12
  • Seriously, the internet. Sometimes I need to put images or buttons in a totally arbitrary, not-mathematically-determined place. – user1299656 Jul 08 '12 at 00:53
  • 1
    Yes, but that's usually the rare exception and not the rule. Your code seems to default to null layout, and for Swing that's really a bad habit to get into. Just sayin'. – Hovercraft Full Of Eels Jul 08 '12 at 01:46
  • 2
    whenever you seem to need setXXSize in Swing, you are doing something wrong, which here is a null layout :-) Simply don't, as @HovercraftFullOfEels already stated. – kleopatra Jul 08 '12 at 07:48
  • *"totally arbitrary, ... place."* If it is 'a place', it is hardly arbitrary. A (custom/3rd party) `XYLayout` can handle that, and it should also presumably handle layering of components which might appear in the same screen space (layer, overlap) and PLAF changes etc. Whatever logic is used for the positioning of a components on-screen should be done using a `LayoutManager`, even if you implement one yourself. – Andrew Thompson Jul 09 '12 at 08:54