Добавить JPanel в JList? - PullRequest
       28

Добавить JPanel в JList?

3 голосов
/ 18 августа 2011

Использование редактора графического интерфейса пользователя NetBeans для создания программы боулинга для школы. Можно ли добавить JPanel в JList? если да как?

Ответы [ 4 ]

4 голосов
/ 02 ноября 2011

Это на самом деле невозможно (имеется в виду, что он не будет вести себя так, как вы ожидаете) - вам действительно нужен список LayoutManager, который будет размещать компоненты в вертикальном или горизонтальном списке. Таким образом, вместо использования JList, вы бы использовали JPanel с менеджером макета, похожим на список.

Попробуйте это:

  • BoxLayout поместит все JPanels в один столбец / строку
  • GridLayout поместит все JPanels в один столбец / строку и сделает их все одинакового размера
2 голосов
/ 09 декабря 2014

Попробуйте это.это работает для меня.

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 голос
/ 05 апреля 2012

Перейти к этому уроку: у него та же концепция с вашей проблемой ...

http://docs.oracle.com/javase/tutorial/uiswing/components/combobox.html#renderer

0 голосов
/ 22 мая 2019

Я только что создал что-то, что не является JList, поэтому в нем отсутствуют многие функции, но вы можете легко добавить их.

Но вы получите следующее: список (все члены имеют одинаковый размер).) который может легко вместить ~ 2 миллиарда панелей без проблем с памятью или производительностью - см. демонстрационный код.Кроме того, JPanels могут содержать все, что вы хотите, эти компоненты будут работать нормально.

В демонстрации члены JPanel не имеют внутренних JPanels и полностью прозрачны для событий мыши (кроме JButtons, и это хорошо): Слушатель, добавленный в общий контейнер, получает их, как показано в демонстрационной версии.Если вы добавите больше иерархии компонентов, все может стать сложнее, IDK.

В любом случае, эта вещь молниеносна и, прежде всего, выполняет свою работу: 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.util.HashMap;
import java.util.Map;
import java.util.function.Function;




/**
 * FastPanelList v[1, 2019-05-22 14!00 UTC] by Dreamspace President
 */
final public class FastPanelList {


    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, JPanel> panelSupplier;
    final private double fractionOfExtentToScrollPerArrowClick;
    final private double fractionOfExtentToScrollPerTrackClick;
    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, JPanel> 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.
     * @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.)
     * @param panelCount                            dto.
     */
    public FastPanelList(final FPLOrientation orientation,
                         final Function<Integer, JPanel> panelSupplier,
                         final double fractionOfExtentToScrollPerArrowClick,
                         final double fractionOfExtentToScrollPerTrackClick,
                         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.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.addComponentListener(new ComponentAdapter() {

            @Override
            public void componentResized(final ComponentEvent e) {

                update();
            }
        });

    }


    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 JPanel getItemUnderMouse(final MouseEvent e) {

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


    public JPanel 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 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, JPanel> 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).
            JPanel 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;
    }
}
...