Java Swing JScrollPane 包含更多不滚动的窗格?

Java Swing JScrollPane Containing more Panes not Scrolling?

抱歉,如果这是一个愚蠢的问题,我是 Java swing UI 的新手。 我正在尝试开发一个程序来获取我的 Steam 成就,我有这方面的基本代码,但现在我想为它创建一个 UI。

下面的代码是UiHandlerclass,还有很多其他的,但是与这个问题无关。这个 class 基本上只给出了两个对话框,询问用户和应用程序 ID,然后应该给出一个包含所有成就和值的滚动框。相反,列表会离开屏幕,没有任何滚动选项。

问题是我的滚动面板(在主面板内)似乎没有滚动(它的侧面没有滚动条,滚轮什么也不做)。我希望 scrollPanel 的内容(它是面板,具有存储在地图中的所有成就的列表)会滚动。

这是我第一次使用滚动面板,所以我真的不知道我在做什么....

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);
        }
    });
}
}

这是 window 生成的屏幕截图: http://puu.sh/jVsto/4a4bcbdf6e.png

感谢您的帮助。 垫子

您的问题是您正在添加 JScrollPane BorderLayout.NORTH,并且正在设置 GUI 的大小。这会将 GUI 限制为一定大小,但不会限制 BorderLayout.NORTH 组件的大小,因此它将与显示 JScrollPane 视口的全部内容所需的大小一样大,无论是在小型 GUI 中。

可能的解决方案:

  • 如果您将 JScrollPane 添加到 BorderLayout.CENTER 位置,它实际上会起作用。
  • 如果可能,您将希望避免设置任何内容的大小。
  • 您可以限制 JScrollPane 视口的 preferredSize
  • 我最喜欢的解决方案:在 JScrollPane 中使用 JList 来显示您的数据,并通过 setVisibleRowCount(...).
  • 指定列表的可见行数

例如:

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;
    }

}