Swing:如何创建不使用Layout的JPanel的可滚动列表

时间:2014-11-15 12:24:35

标签: java swing jpanel jscrollpane layout-manager

我正在尝试找到一种方法来创建没有布局管理器的JPanel列表。

我找到了几个关于SO的例子,为可滚动的JPanel列表提供了解决方案。问题。更具体地说,我从this thread开始研究它。

我当前的问题是,当我从列表中的JPanels中删除布局时,我遇到了问题。

它们被正确添加但是在需要时不会出现滚动条,并且面板开始重叠。

注意:我知道布局是首选,但我发现使用纯X,Y坐标和模型程序更直接。请不要因此而抨击我......

这是一个小工作示例(从this comment获取和修改):

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.MatteBorder;

public class JScrollPanels {
    private int i;
    private JPanel listContainer;

    private void initUI() {
        final JFrame frame = new JFrame(JScrollPanels.class.getSimpleName());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        listContainer = new JPanel();
        listContainer.setLayout(new BoxLayout(listContainer, BoxLayout.Y_AXIS));

        frame.add(new JScrollPane(listContainer), BorderLayout.CENTER);
        JButton button = new JButton("Add");
        button.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                final JPanel newPanel = new JPanel();
                newPanel.setLayout(null);

                newPanel.setSize(272, 110);

                JLabel name = new JLabel("Name " + i++);
                name.setBounds(18, 13, 84, 21);
                newPanel.setBorder(new MatteBorder(0, 0, 1, 0, Color.GRAY));

                JLabel date = new JLabel("12/11/2014");

                date.setBounds(10, 44, 123, 21);

                JButton btn= new JButton(">");
                btn.addActionListener( new NameListener(name, date) );

                btn.setBounds(205, 44, 48, 30);

                newPanel.add(name);
                newPanel.add(date);
                newPanel.add(btn);

                listContainer.add(newPanel);
                listContainer.revalidate();

                // Scroll down to last added panel
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        newPanel.scrollRectToVisible(newPanel.getBounds());
                    }
                });
            }
        });
        frame.add(button, BorderLayout.PAGE_END);

        frame.setSize(272, 300);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (UnsupportedLookAndFeelException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new JScrollPanels().initUI();
            }
        });
    }

    public class NameListener implements ActionListener {

        private JLabel name;
        private JLabel date;

        public NameListener(JLabel name, JLabel date) {
            this.name = name;
            this.date = date;
        }

        public void actionPerformed(ActionEvent e) {
            System.out.println("Clicked " + name.getText() + " on " + date.getText());
        }

    }
}

修改

使用此修复:

final JPanel newPanel = new JPanel(){
                    @Override
                    public Dimension getPreferredSize() {
                        return new Dimension(272, 110);
                    }
                };

谢谢,mKorbel!

1 个答案:

答案 0 :(得分:2)

同样,我仍然坚持我的主张,从长远来看,布局管理器将发挥最佳作用。例如,您的GUI可能会使用这样的东西:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.swing.*;
import javax.swing.border.Border;

@SuppressWarnings("serial")
public class JScrollPanels2 extends JPanel {
   private static final int PREF_W = 300;
   private static final int PREF_H = 300;
   private int i;
   private JPanel listContainer;

   public JScrollPanels2() {
      JPanel outerWrapperPanel = new JPanel(new BorderLayout());
      listContainer = new JPanel();
      listContainer.setLayout(new BoxLayout(listContainer, BoxLayout.Y_AXIS));
      outerWrapperPanel.add(listContainer, BorderLayout.PAGE_START);

      JPanel buttonPanel = new JPanel(new GridLayout(1, 0, 5, 0));
      buttonPanel.add(new JButton(new AddAction("Add")));

      setLayout(new BorderLayout());
      add(new JScrollPane(outerWrapperPanel), BorderLayout.CENTER);
      add(buttonPanel, BorderLayout.PAGE_END);
   }

   @Override
   public Dimension getPreferredSize() {
      if (isPreferredSizeSet()) {
         return super.getPreferredSize();
      }
      return new Dimension(PREF_W, PREF_H);
   }

   private class AddAction extends AbstractAction {
      public AddAction(String name) {
         super(name);
         int mnemonic = (int) name.charAt(0);
         putValue(MNEMONIC_KEY, mnemonic);
      }

      @Override
      public void actionPerformed(ActionEvent evt) {
         listContainer.add(new CellPanel(i));
         listContainer.revalidate();
         listContainer.repaint();
         i++;
      }
   }

   private class CellPanel extends JPanel {

      private final int gap = 4;
      private int index;
      private String name;
      private Date date;
      private final String format = "MM/dd/yyyy";
      private SimpleDateFormat sdf = new SimpleDateFormat(format);

      public CellPanel(int i) {
         this.index = i;
         this.name = "Name " + index;
         setLayout(new GridBagLayout()); 
         date = new Date();
         Border emptyBorder = BorderFactory.createEmptyBorder(gap, gap, gap, gap);
         Border lineBorder = BorderFactory.createLineBorder(Color.black);
         setBorder(BorderFactory.createCompoundBorder(lineBorder, emptyBorder));

         add(new JLabel(name), createGbc(0, 0));
         add(new JLabel(""), createGbc(1, 0));
         add(new JLabel(sdf.format(date)), createGbc(0, 1));
         add(new JButton(new MyBtnAction(">")), createGbc(1, 1));
      }

      private GridBagConstraints createGbc(int x, int y) {
         GridBagConstraints gbc = new GridBagConstraints();
         gbc.gridx = x;
         gbc.gridy = y;
         gbc.gridwidth = 1;
         gbc.gridheight = 1;
         gbc.weightx = 1.0;
         gbc.weighty = 1.0;

         if (x % 2 == 0) {
            gbc.anchor = GridBagConstraints.WEST;
         } else {
            gbc.anchor = GridBagConstraints.EAST;
         }
         return gbc;
      }

      private class MyBtnAction extends AbstractAction {

         public MyBtnAction(String name) {
            super(name);
            // int mnemonic = (int) name.charAt(0);
            // putValue(MNEMONIC_KEY, mnemonic);
         }

         @Override
         public void actionPerformed(ActionEvent evt) {
            System.out.println("Button pressed for " + name);
         }
      }

   }

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

      JFrame frame = new JFrame("JScrollPanels2");
      frame.setDefaultCloseOperation(JFrame.DISPOSE_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();
         }
      });
   }
}

使用布局管理器的一个好处是它们的灵活性。如果您想要将新组件添加到内部JPanel,您可以轻松地这样做,而无需手动重新计算每个组件的其他位置(如果需要移位)。相反,让布局经理为您做繁重的工作。此外,虽然使用GUI的null布局在一个平台上可能看起来不错,但在大多数其他平台或屏幕分辨率上通常看起来很糟糕。