将JPanel添加到JList中?

3
使用NetBeans GUI编辑器为学校创建保龄球程序。我能否将JPanel添加到JList中?如果可以,如何操作?
4个回答

7
这并不是真正的可能(意味着它不会按照你的期望行事) - 你实际上想要的是一个列表 LayoutManager,它将在垂直或水平列表中布置组件。因此,您可以使用具有类似列表的布局管理器的 JPanel,而不是使用 JList
试试这些:
  • BoxLayout 将把所有的 JPanels 放在单个列/行中
  • GridLayout 将把所有的 JPanels 放在单个列/行中,并使它们大小相同

4

试试这个。对我有用。

class PanelRenderer implements ListCellRenderer {

    @Override
    public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
        JPanel renderer = (JPanel) value;
        renderer.setBackground(isSelected ? Color.red : list.getBackground());
        return renderer;
    }
}

public void ShowItemList(List<JPanel> paneList, JPanel container) {


        DefaultListModel model = new DefaultListModel();

        for (JPanel pane:paneList) {

                model.addElement(pane);

        }
        final JList list = new JList(model);
        list.setFixedCellHeight(40);
        list.setSelectedIndex(-1);

        list.setCellRenderer(new JPanelToJList.PanelRenderer());
        JScrollPane scroll1 = new JScrollPane(list);
        final JScrollBar scrollBar = scroll1.getVerticalScrollBar();
        scrollBar.addAdjustmentListener(new AdjustmentListener() {
            @Override
            public void adjustmentValueChanged(AdjustmentEvent e) {
                System.out.println("JScrollBar's current value = " + scrollBar.getValue());
            }
        });


        container.add(scroll1);


}

1

0

(编辑:我已经使用了一段时间,感到惊讶。这是我迄今为止见过的最快速的列表组件。为什么我以前没有看到过?)

我刚刚编写了一个不是JList的东西,所以它缺少很多功能,但你可以相当容易地添加这些功能。

但你得到的是这样的:一个列表(所有成员大小相等),可以轻松地容纳约20亿个面板,没有内存或性能问题-请参见演示代码。此外,JPanels可以包含任何你想要的东西,这些组件将正常工作。

在演示中,JPanel成员没有内部JPanels,并且对鼠标事件完全透明(除了JButtons,这很好):添加到整个容器的侦听器接收它们,如演示所示。如果您添加更多组件层次结构,事情可能会变得棘手,我不知道。

无论如何,这个东西非常快,最重要的是完成了任务:在列表中操作但也可以选择JPanels。(没有内置的选择代码,但像我说的那样:很容易做到。鼠标悬停演示代码内。)

enter image description here

示例类:

final public class FastPanelListDemo {


    private static JFrame window = null;
    private static FastPanelList panelList = null;


    public static void main(final String[] args) {

        SwingUtilities.invokeLater(() -> {

            setLookAndFeelDefault();

            panelList = new FastPanelList(FastPanelList.FPLOrientation.VERTICAL,
                                          FastPanelListDemo::supplyPanel,
                                          0.1,
                                          0.95,
                                          false,
                                          80,
                                          Integer.MAX_VALUE);
            final Container contentPane = panelList.container;
            contentPane.setPreferredSize(new Dimension(300, 800));
            contentPane.setBackground(Color.GRAY);

            window = new JFrame("FastPanelList demo");
            window.setContentPane(contentPane);
            window.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
            window.pack();
            window.setLocationRelativeTo(null);
            window.setVisible(true);


            contentPane.addMouseMotionListener(new MouseAdapter() {

                @Override
                public void mouseMoved(final MouseEvent e) {

                    final JPanel itemUnderMouse = panelList.getItemUnderMouse(e);
                    if (itemUnderMouse != null) {
                        itemUnderMouse.setBackground(new Color((float) Math.random(),
                                                               (float) Math.random(),
                                                               (float) Math.random()));
                    }
                }
            });

        });
    }


    private static JPanel supplyPanel(final int panelIndex) { // Just supply something that extends JPanel. You can put as much data in as you want. E.g. "boolean isMouseHovering" etc.

        final JLabel label = new JLabel("panel " + panelIndex);
        label.setHorizontalAlignment(SwingConstants.CENTER);
        label.setVerticalAlignment(SwingConstants.CENTER);

        final JButton button = new JButton("click me");
        button.addActionListener(e -> {
            JOptionPane.showMessageDialog(window,
                                          "That was button " + panelIndex + ".",
                                          "* CLICK *",
                                          JOptionPane.INFORMATION_MESSAGE);
        });

        final JPanel panel = new JPanel(new BorderLayout(0,
                                                         0));
        panel.setBorder(BorderFactory.createEmptyBorder(10,
                                                        10,
                                                        10,
                                                        10));
        panel.setBackground(new Color((float) Math.random(),
                                      (float) Math.random(),
                                      (float) Math.random()));
        panel.add(label, BorderLayout.CENTER);
        panel.add(button, BorderLayout.EAST);

        return panel;
    }


    private static void setLookAndFeelDefault() {

        setLookAndFeel("Windows",
                       UIManager.getSystemLookAndFeelClassName(),
                       UIManager.getCrossPlatformLookAndFeelClassName(),
                       "Windows Classic",
                       "Nimbus",
                       "Metal",
                       "CDE/Motif");
    }


    /**
     * @param intendedLAFIs ANYTHING, but ideally a LookAndFeel name or several. The first value that equalsIgnoreCase
     *                      an installed LookAndFeelInfo.getName() will be used.
     */
    private static void setLookAndFeel(final String... intendedLAFIs) {

        if (intendedLAFIs != null && intendedLAFIs.length > 0) {
            final UIManager.LookAndFeelInfo[] installedLAFIs = UIManager.getInstalledLookAndFeels();
            LAFILOOP:
            for (String intendedLAFI : intendedLAFIs) {
                for (final UIManager.LookAndFeelInfo lafi : UIManager.getInstalledLookAndFeels()) {
                    if (lafi.getName().equalsIgnoreCase(intendedLAFI)) {
                        try {
                            UIManager.setLookAndFeel(lafi.getClassName());
                            break LAFILOOP;
                        } catch (Exception e) {
                            continue LAFILOOP;
                        }
                    }
                }
            }
        } else {
            throw new IllegalArgumentException("intendedLAFIs is null or empty.");
        }
    }
}

FastPanelList 类:

import javax.swing.*;
import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;




/**
 * FastPanelList v[2pre1, 2019-05-28 10!00 UTC] by Dreamspace President
 */
final public class FastPanelList<T extends JPanel> {


    public enum FPLOrientation {
        HORIZONTAL(Adjustable.HORIZONTAL),
        VERTICAL(Adjustable.VERTICAL);


        final public int orientationAsConstant;


        FPLOrientation(final int orientationAsConstant) {


            this.orientationAsConstant = orientationAsConstant;
        }


    }




    final public FPLOrientation orientation;
    final private Function<Integer, T> panelSupplier;
    final private double fractionOfExtentToScrollPerArrowClick;
    final private double fractionOfExtentToScrollPerTrackClick;
    final private double fractionOfExtentToScrollPerMouseWheelStep;
    final private boolean hideScrollbarWhenUnnecessary;

    final private JScrollBar scrollBar;
    final private int scrollBarWidth; // The default width it normally has in any GUI.
    final public JPanel container; // The container of it all.

    private int panelSize = 0;  // The horizontal or vertical extent of each contained panel.
    private int panelCount = 0; // The amount of panels, indeed max Integer.MAX_VALUE.

    private long contentSize = 0; // The sum total extent of all "contained panels". (They're not really contained, but nobody will see that.)
    private long actualScrollPosition = 0; // The true scroll position, think contentSize.
    private Dimension lastKnownContainerSize = new Dimension(0, 0);


    private Map<Integer, T> knownPanels = new HashMap<>(); // All panels of which some pixels are currently potentially visible are cached here.


    /**
     * @param orientation                           Whether horizontal or the more common vertical arrangement.
     * @param panelSupplier                         Your code that supplies the panels as needed on the fly. The
     *                                              argument will NEVER be null - and your return value, too, must never
     *                                              be null.
     * @param fractionOfExtentToScrollPerArrowClick E.g. 0.1 for 10% of the visible area to become hidden/shown when you
     *                                              click a scrollbar arrow.
     * @param fractionOfExtentToScrollPerTrackClick E.g. 0.95 for 95% of the visible area to become hidden/shown when
     *                                              you click in the scrollbar track.
     * @param hideScrollbarWhenUnnecessary          Guess.
     * @param panelSize                             Can later also be done via setter. (Not tested.) KEEP IN MIND THAT
     *                                              THIS IS NOT YET SCALED, so if you have Desktop scaling 200% and are
     *                                              running Java 8, you need to double the value (e.g. use my GUIScaling
     *                                              class to automate this).
     * @param panelCount                            dto.
     */
    public FastPanelList(final FPLOrientation orientation,
                         final Function<Integer, T> panelSupplier,
                         final double fractionOfExtentToScrollPerArrowClick,
                         final double fractionOfExtentToScrollPerTrackClick,
                         final double fractionOfExtentToScrollPerMouseWheelStep,
                         final boolean hideScrollbarWhenUnnecessary,
                         final int panelSize,
                         final int panelCount) {


        if (orientation == null) {
            throw new IllegalArgumentException("orientation is null.");
        }
        if (panelSupplier == null) {
            throw new IllegalArgumentException("panelSupplier is null.");
        }

        this.orientation = orientation;
        this.panelSupplier = panelSupplier;
        this.fractionOfExtentToScrollPerArrowClick = Math.max(0, fractionOfExtentToScrollPerArrowClick);
        this.fractionOfExtentToScrollPerTrackClick = Math.max(0, fractionOfExtentToScrollPerTrackClick);
        this.fractionOfExtentToScrollPerMouseWheelStep = Math.max(0, fractionOfExtentToScrollPerMouseWheelStep);
        this.hideScrollbarWhenUnnecessary = hideScrollbarWhenUnnecessary;
        setPanelSize(panelSize);
        setPanelCount(panelCount);

        scrollBarWidth = determineScrollBarDefaultWidth();
        scrollBar = new JScrollBar(orientation.orientationAsConstant, 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE);
        scrollBar.addAdjustmentListener(e -> update());

        container = new JPanel(null); // NULL: We want to layout everything manually.
        //        container.add(scrollBar);
        container.addComponentListener(new ComponentAdapter() {

            @Override
            public void componentResized(final ComponentEvent e) {

                update();
            }
        });

        container.addMouseWheelListener(this::mouseWheelEvent);

    }


    public void mouseWheelEvent(final MouseWheelEvent e) {

        final int rotation = e.getWheelRotation();
        final int extent = scrollBar.getModel().getExtent();
        final int increment = (int) Math.max(1, Math.min(extent,
                                                         extent * fractionOfExtentToScrollPerMouseWheelStep));

        scrollBar.setValue(scrollBar.getValue() + (rotation * increment));
    }


    private int determineScrollBarDefaultWidth() { // Called only ONE time.

        final JScrollPane dummyForDefaultSize = new JScrollPane(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
                                                                ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
        dummyForDefaultSize.setPreferredSize(new Dimension(1000, 1000));
        dummyForDefaultSize.setSize(dummyForDefaultSize.getPreferredSize());
        dummyForDefaultSize.doLayout();
        return dummyForDefaultSize.getVerticalScrollBar().getSize().width;
    }


    /**
     * FastPanelList requires each item to have the exact same size. This is where you define it (if you reconsidered
     * after your constructor call).
     *
     * @param panelSize Will become >=1
     */
    public void setPanelSize(final int panelSize) {

        this.panelSize = Math.max(1, panelSize);
    }


    /**
     * FastPanelList easily manages Integer.MAX_VALUE (about 2 billion) panels with no memory or performance problems.
     * You define the amount here. You don't add/remove panels in this thing: Instead, you will be asked to provide
     * panels as required depending on screen layout etc.
     *
     * @param panelCount Will become >=0
     */
    public void setPanelCount(final int panelCount) {

        this.panelCount = Math.max(0, panelCount);
    }


    /**
     * Clears the internal JPanel cache. Necessary if you want to repopulate the list. Setting the panel count and
     * calling update() is not sufficient. (Call update AFTER this method.)
     */
    public void clear() {

        knownPanels.clear();
    }


    public T getItemUnderMouse(final MouseEvent e) {

        return getItemUnderMouse(e.getX(), e.getY());
    }


    public T getItemUnderMouse(final int xInComponent,
                               final int yInComponent) {

        final long realPositionUnderMouse = (actualScrollPosition + (orientation == FPLOrientation.HORIZONTAL ? (long) xInComponent : (long) yInComponent));

        final int indexUnderMouse = (int) (realPositionUnderMouse / panelSize);
        return knownPanels.get(indexUnderMouse);
    }


    /**
     * This method is very lenient.
     *
     * @param index                   Anything.
     * @param callSupplierIfNotCached Depends on what you're trying to achieve. E.g. use FALSE if you want to set the
     *                                background color of one of the visible JPanels. The method would return null if
     *                                the panel is not visible, because then it is also no longer cached.
     * @return NULL if index is NULL, or is less than 0, or is equal to or greater than panelCount. Else the cached
     * JPanel (or whatever it secretly is via "extends"), meaning one of the panels that are currently visible or at the
     * edge of visibility. In all other cases, either null will be returned - or your supplier will be called, so you
     * get your own JPanel spat right back at you.
     */
    public T getItem(final Integer index,
                     final boolean callSupplierIfNotCached) {

        T ret = null;
        if (index != null && index >= 0 && index < panelCount) {
            ret = knownPanels.get(index);
            if (ret == null && callSupplierIfNotCached) {
                ret = panelSupplier.apply(index);
                if (ret == null) {
                    throw new IllegalArgumentException("panelSupplier returned null for index " + index);
                }
            }
        }
        return ret;
    }


    /**
     * @return a NEW Map containing the Map entries of the internal knownPanels map. These maps contain all panels that
     * are currently visible on screen. The index is identical to the number handed to your Supplier.
     * <p>
     * The purpose of that internal map is to not request EVERY panel anew every time, but only the panels that are
     * scrolled in at the edge of the screen. Obviously, this is also very useful to you, because you can call this
     * method to get all panels to change their look, data, whatever. And ONLY THOSE panels need to be changed. All
     * others ... don't exist. They only exist in the fantasy of the user. Until they scroll there, then some have
     * become real while others have fallen out of existence.
     */
    public Map<Integer, T> getCachedItems() {

        return new HashMap<>(knownPanels);
    }


    /**
     * This layouts the component. This is done automatically when the scrollbar is moved or the container is resized,
     * but any other action would require YOU to call this.
     */
    public void update() {

        container.removeAll();

        lastKnownContainerSize = container.getSize();

        final int containerSize;
        if (orientation == FPLOrientation.HORIZONTAL) {
            scrollBar.setLocation(0, lastKnownContainerSize.height - scrollBarWidth);
            scrollBar.setSize(lastKnownContainerSize.width, scrollBarWidth);
            containerSize = lastKnownContainerSize.width;
        } else {
            scrollBar.setLocation(lastKnownContainerSize.width - scrollBarWidth, 0);
            scrollBar.setSize(scrollBarWidth, lastKnownContainerSize.height);
            containerSize = lastKnownContainerSize.height;
        }


        contentSize = (long) panelCount * (long) panelSize;
        final long invisibleStuff = contentSize - containerSize;
        actualScrollPosition = Math.max(0, Math.min(invisibleStuff,
                                                    (long) (getScrollBarPosRatio() * (invisibleStuff))
        ));


        final int extent;
        if (contentSize > 0) {
            final double visibleRatio = containerSize / (double) contentSize;
            extent = (int) Math.max(0, Math.min(Integer.MAX_VALUE, Integer.MAX_VALUE * visibleRatio));
        } else {
            extent = Integer.MAX_VALUE;
        }
        final int unitIncrement = (int) Math.max(1, Math.min(extent,
                                                             extent * fractionOfExtentToScrollPerArrowClick));
        final int blockIncrement = (int) Math.max(1, Math.min(extent,
                                                              extent * fractionOfExtentToScrollPerTrackClick));
        scrollBar.getModel().setExtent(extent);
        scrollBar.setUnitIncrement(unitIncrement);
        scrollBar.setBlockIncrement(blockIncrement);
        scrollBar.setVisible(!hideScrollbarWhenUnnecessary || extent < Integer.MAX_VALUE);

        final Dimension panelSizes = getPanelSize();

        long n = actualScrollPosition;
        final long endOfScreen = actualScrollPosition + containerSize + panelSize;
        final Map<Integer, T> newKnownPanels = new HashMap<>();

        while (n < endOfScreen) { // Loop ongoing = need more panels to fill the view.

            // Calc index of current panel.
            final long panelIndex = n / panelSize;
            if (panelIndex > Integer.MAX_VALUE) {
                throw new Error();
            } else if (panelIndex >= panelCount) {
                break;
            }
            final int panelIndexInt = (int) panelIndex;


            // Obtain current panel - if possible from cache, else from external provider (which might likely create it from scratch).
            T panel = knownPanels.get(panelIndexInt);
            if (panel == null) {
                panel = panelSupplier.apply(panelIndexInt);
                if (panel == null) {
                    throw new IllegalArgumentException("panelSupplier returned null for index " + panelIndex);
                }
            }
            newKnownPanels.put(panelIndexInt, panel);


            // Set position and size.
            final int panelPos = (int) ((panelIndex * panelSize) - actualScrollPosition);
            final Point location;
            if (orientation == FPLOrientation.HORIZONTAL) {
                location = new Point(panelPos, 0);
            } else {
                location = new Point(0, panelPos);
            }
            panel.setLocation(location);
            panel.setSize(panelSizes);


            n += panelSize;
        }
        knownPanels = newKnownPanels; // Will now contain all panels needed for display. All panels that were in the map, but are no longer needed, are now gone forever.


        // Layout.
        container.add(scrollBar);
        for (JPanel panel : newKnownPanels.values()) {
            container.add(panel);
            panel.revalidate();
        }


        container.repaint(); // required
    }


    /**
     * @return the correct width&height a contained JPanel needs to have. Is applied by update() automatically.
     */
    public Dimension getPanelSize() {

        if (orientation == FPLOrientation.HORIZONTAL) {
            return new Dimension(panelSize,
                                 lastKnownContainerSize.height - (scrollBar.isVisible() ? scrollBarWidth : 0));
        } else {
            return new Dimension(lastKnownContainerSize.width - (scrollBar.isVisible() ? scrollBarWidth : 0),
                                 panelSize);
        }
    }


    /**
     * @return 0 to 1, expressing position of scroll bar handle.
     */
    public double getScrollBarPosRatio() {

        final int scrollRangeSize = Integer.MAX_VALUE - scrollBar.getVisibleAmount(); // Which should really be named getExtent(). Or rather the other way round.
        return scrollBar.getValue() / (double) scrollRangeSize;
    }


}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接