Search code examples
javaswingscrolljscrollpane

Java Swing JScrollPane Containing more Panes not Scrolling?


Sorry if this is a stupid question, I am very new to Java swing UI. I am trying to develop a program that will grab my Steam achievements, and I have the base code for this, but now I want to create a UI for it.

The following code is the UiHandler class, there are many others however they are irrelevant to this problem. This class basically just gives two dialog boxes asking for the user and app ID, then should give a scroll box with all the achievements and there values. Instead the list goes off the screen without any option to scroll.

The problem is that my scrollPanel (inside mainPanel) does not seem to scroll (it has no scroll bars at the side and scroll wheel does nothing). I would expect the contents of scrollPanel (which is panel, has the list of all achievements stored in a Map) would scroll.

This is my first time using scroll panels, so I don't really know what I am doing....

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.WindowEvent;
import java.util.Iterator;
import java.util.Map;

import javax.swing.*;

@SuppressWarnings("serial")
public class UserInterface extends JFrame {

public UserInterface() {
    initUI();
}

@SuppressWarnings("unchecked")
private void initUI() {

    UserInteractionHandler uiHandler = new UserInteractionHandler();

    setTitle("Steam Stats");
    setSize(500, 400);
    setLocationRelativeTo(null);
    setDefaultCloseOperation(DISPOSE_ON_CLOSE);

    JPanel panel = new JPanel(new GridLayout(0, 1));

    JLabel header = new JLabel("Steam Stats", SwingConstants.CENTER);
    header.setFont(new Font("trebuchet ms", Font.BOLD, 20));
    panel.add(header);


    String userId = JOptionPane.showInputDialog("Steam ID 64");
    String appId = JOptionPane.showInputDialog("App Id of Game");

    Map<String, Integer> allAchievements = uiHandler.getAllAchievements(appId, userId);

    @SuppressWarnings("rawtypes")
    Iterator it = allAchievements.entrySet().iterator();
    while (it.hasNext()) {
        Map.Entry<String, Integer> pair = (Map.Entry<String, Integer>) it.next();

        JLabel key = new JLabel(pair.getKey());
        JLabel value = new JLabel(pair.getValue().toString());
        panel.add(key);
        panel.add(value);

        it.remove();
    }

    JScrollPane scrollPanel = new JScrollPane(panel);

    JPanel mainPanel = new JPanel(new GridLayout(0, 1));
    mainPanel.add(scrollPanel);

    getContentPane().add(mainPanel, BorderLayout.NORTH);



}

public static void runUi() {

    EventQueue.invokeLater(new Runnable() {
        public void run() {
            UserInterface ui = new UserInterface();
            ui.setVisible(true);
        }
    });
}
}

Here is a screenshot of the window this produces : http://puu.sh/jVsto/4a4bcbdf6e.png

Thanks for any help. Mat


Solution

  • Your problem is that you're adding the JScrollPane BorderLayout.NORTH, and are setting the size of the GUI. This will constrain the GUI to a certain size, but does not constrain the BorderLayout.NORTH component's size, and so it will be as large as required to show the entire contents of the JScrollPane's viewport, regardless of being in a small GUI.

    Possible solutions:

    • If you added the JScrollPane to the BorderLayout.CENTER position, it would actually work.
    • You will want to avoid setting the sizes of anything if possible.
    • You could constrain the preferredSize of the JScrollPane's viewport
    • My favorite solution: use a JList within a JScrollPane to display your data, and specify the list's visible row count via setVisibleRowCount(...).

    For example:

    import java.awt.BorderLayout;
    import java.awt.Component;
    import java.awt.EventQueue;
    import java.awt.Font;
    import java.awt.GridLayout;
    import java.awt.event.WindowEvent;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    
    import javax.swing.*;
    
    @SuppressWarnings("serial")
    public class UserInterface extends JFrame {
    
        public UserInterface() {
            initUI();
        }
    
        @SuppressWarnings("unchecked")
        private void initUI() {
    
            UserInteractionHandler uiHandler = new UserInteractionHandler();
    
            setTitle("Steam Stats");
            // !! setSize(500, 400);
            setLocationRelativeTo(null);
            setDefaultCloseOperation(DISPOSE_ON_CLOSE);
    
            JPanel panel = new JPanel(new GridLayout(0, 1));
    
            JLabel header = new JLabel("Steam Stats", SwingConstants.CENTER);
            header.setFont(new Font("trebuchet ms", Font.BOLD, 20));
            panel.add(header);
    
            String userId = JOptionPane.showInputDialog("Steam ID 64");
            String appId = JOptionPane.showInputDialog("App Id of Game");
    
            Map<String, Integer> allAchievements = uiHandler.getAllAchievements(
                    appId, userId);
    
            DefaultListModel<MyPair> listModel = new DefaultListModel<>();
            JList<MyPair> pairList = new JList<>(listModel);
            pairList.setCellRenderer(new MyPairRenderer());
            pairList.setVisibleRowCount(20);
    
            @SuppressWarnings("rawtypes")
            Iterator it = allAchievements.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry<String, Integer> pair = (Map.Entry<String, Integer>) it
                        .next();
    
                MyPair myPair = new MyPair(pair.getKey(), pair.getValue());
                listModel.addElement(myPair);
    
                it.remove();
            }
    
            //!! JScrollPane scrollPanel = new JScrollPane(panel);
            JScrollPane scrollPanel = new JScrollPane(pairList);
    
            JPanel mainPanel = new JPanel(new BorderLayout());
            mainPanel.add(header, BorderLayout.PAGE_START);
            mainPanel.add(scrollPanel);
    
            getContentPane().add(mainPanel, BorderLayout.PAGE_START);
            pack(); // !!
    
        }
    
        public static void runUi() {
    
            EventQueue.invokeLater(new Runnable() {
                public void run() {
                    UserInterface ui = new UserInterface();
                    ui.setVisible(true);
                }
            });
        }
    
        public static void main(String[] args) {
            UserInterface.runUi();
        }
    }
    
    class MyPair {
        private String name;
        private int value;
        public MyPair(String name, int value) {
            this.name = name;
            this.value = value;
        }
    
        public String getName() {
            return name;
        }
    
        public int getValue() {
            return value;
        }
    
    }
    
    class MyPairRenderer implements ListCellRenderer<MyPair> {
        private JPanel panel = new JPanel(new GridLayout(1, 2, 5, 5));
        private JLabel nameLabel = new JLabel();
        private JLabel valueLabel = new JLabel();
    
        public MyPairRenderer() {
            panel.add(nameLabel);
            panel.add(valueLabel);
        }
    
        @Override
        public Component getListCellRendererComponent(JList<? extends MyPair> list,
                MyPair value, int index, boolean isSelected, boolean cellHasFocus) {
            if (value != null) {
                nameLabel.setText(value.getName());
                valueLabel.setText("" + value.getValue());
            }
            return panel;
        }
    
    }