1

我有一个由面板上的多个 JList 组件组成的 GUI,它位于 JScrollPane 上。滚动窗格可以一次滚动所有列表。但是,当我在包含列表的面板上使用 MigLayout 时,我无法滚动超过前 1819 个列表元素。限制似乎与列表的高度有关,而不是与元素的数量有关。如果我使用更大的元素大小,我可以滚动更少的元素。我目前正在使用 MigLayout 4.2。

这是一个展示此行为的简化示例。

import net.miginfocom.swing.MigLayout;

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

public final class MigLayoutListTest {
    public static void main(final String... args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                final String[] listData = new String[5000];
                for (int i = 0; i < 5000; i++) {
                    listData[i] = "Index " + i;
                }

                final JPanel panel = new JPanel(new MigLayout());
                panel.add(new JList(listData));

                final JFrame frame = new JFrame();
                frame.setContentPane(new JScrollPane(panel));

                frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
                frame.setPreferredSize(new Dimension(600, 400));
                frame.pack();
                frame.setVisible(true);
            }
        });
    }
}

如果我消除 JPanel 并将 JList 直接放在 JScrollPane 上,则滚动可以正常工作,但我不能使用此解决方法,因为我需要在同一个 JScrollPane 上有多个列表。如果我对 JPanel 使用除 MigLayout 以外的任何布局,则滚动工作正常。

这是 MigLayout 的错误还是限制?是否需要将一些配置选项应用于 MigLayout 才能使其正常工作?

4

1 回答 1

2

我认为你的方法很笨拙。相反,在他们自己的 JScrollPane 中使用 JLists 并同步滚动:

import java.awt.*;
import java.util.*;

import javax.swing.*;

public class ScrollingDemo implements Runnable
{
  public static void main(String args[])
  {
    SwingUtilities.invokeLater(new ScrollingDemo());
  }

  public void run()
  {
    JScrollPane sp1 = new JScrollPane(getJList(1));
    sp1.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
    JScrollPane sp2 = new JScrollPane(getJList(3));
    sp2.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);

    JScrollBar sBar1 = sp1.getVerticalScrollBar();
    JScrollBar sBar2 = sp2.getVerticalScrollBar();

    // synchronize:
    sBar2.setModel(sBar1.getModel());

    JPanel p = new JPanel(new GridLayout(1,2));
    p.add(sp1);
    p.add(sp2);

    JFrame frame = new JFrame("Synch Scrolling");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().add(p, BorderLayout.CENTER);
    frame.pack();
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }

  public JList getJList(int factor)   
  {
    Vector<String> items = new Vector<String>();
    for(int i = 0; i < 5000; i++)
    {
      items.add(Integer.toString((i+1)*factor));
    }
    JList list = new JList(items);
    list.setPrototypeCellValue("XXXXXXXXXX");
    list.setVisibleRowCount(10);
    return list;
  }
}

如果只想看到 1 个垂直滚动条,只需将滚动条策略设置为JScrollPane.VERTICAL_SCROLLBAR_NEVER要隐藏的滚动条即可。

注意:这假定每个 JList 具有相同数量的元素。如果您有多个不同长度的列表,您可能(相反)需要向AdjustmentListener垂直滚动条添加一个。

编辑:示例:

import java.awt.*;
import java.awt.event.*;
import java.util.*;

import javax.swing.*;

public class ScrollingDemo2 implements Runnable
{
  public static void main(String args[])
  {
    SwingUtilities.invokeLater(new ScrollingDemo2());
  }

  public void run()
  {
    JScrollPane sp1 = new JScrollPane(getJList(100));
    sp1.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
    JScrollPane sp2 = new JScrollPane(getJList(200));
    sp2.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);

    // synchronize:
    sp2.getVerticalScrollBar().addAdjustmentListener(new Synchronizer(sp1, sp2));

    JPanel p = new JPanel(new GridLayout(1,0));
    p.add(sp1);
    p.add(sp2);

    JFrame frame = new JFrame("Synch Scrolling 2");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().add(p, BorderLayout.CENTER);
    frame.pack();
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }

  public JList getJList(int count)   
  {
    Vector<String> items = new Vector<String>();
    for(int i = 0; i < count; i++)
    {
      items.add(Integer.toString(i+1));
    }

    JList list = new JList(items);
    list.setPrototypeCellValue("XXXXXXXXXX");
    list.setVisibleRowCount(10);
    return list;
  }

  class Synchronizer implements AdjustmentListener
  {
    JScrollPane sp1, sp2;

    public Synchronizer(JScrollPane sp1, JScrollPane sp2)
    {
      this.sp1 = sp1;
      this.sp2 = sp2;
    }

    public void adjustmentValueChanged(AdjustmentEvent e)
    {
      if (! e.getValueIsAdjusting())
      {
        return;
      }

      JScrollBar vert1 = sp1.getVerticalScrollBar();
      JScrollBar vert2 = sp2.getVerticalScrollBar();

      int range1 = vert1.getMaximum() - vert1.getMinimum() -
                   vert1.getModel().getExtent();

      int range2 = vert2.getMaximum() - vert2.getMinimum() -
                   vert2.getModel().getExtent();

      float percent2 = (float) (vert2.getValue()) / range2;
      int newVal1 = (int) (percent2 * range1);

      vert1.setValue(newVal1);
    }
  }
}
于 2013-07-30T14:16:37.413 回答