-1

I'm trying to make a kitchen display system using a FlowLayout and I'm trying to figure out a way to add another panel on the 2nd row when the first row is already full. The width of the GUI will change according to user preference. When wider, it should show more of the components per row.

enter image description here

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
askManiac
  • 167
  • 1
  • 7
  • 17

2 Answers2

2

You can use a FlowLayout. From the tutorial How to Use FlowLayout:

The FlowLayout class puts components in a row, sized at their preferred size. If the horizontal space in the container is too small to put all the components in one row, the FlowLayout class uses multiple rows. If the container is wider than necessary for a row of components, the row is, by default, centered horizontally within the container.

EDIT If you want your layout to scroll vertically when there are too many rows, you can use a JScrollPane with horizontal scrolling disabled. You can do that with:

js.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);

(where js is the JScrollPane that contains your FlowLayout panel).

EDIT 2 Well, the above isn't enough. You also need to set a viewport view on the JScrollPane that will track the JScrollPane width. Here's a class that does this (taken from here):

static class MyPanel extends JPanel implements Scrollable{

    @Override
    public Dimension getPreferredScrollableViewportSize() {

        return this.getPreferredSize();
    }

    @Override
    public int getScrollableUnitIncrement(Rectangle visibleRect,
            int orientation, int direction) {
        return 50;
    }

    @Override
    public int getScrollableBlockIncrement(Rectangle visibleRect,
            int orientation, int direction) {
        return 80;
    }

    /*
     * (non-Javadoc)
     * @see javax.swing.Scrollable#getScrollableTracksViewportWidth()
     */
    @Override
    public boolean getScrollableTracksViewportWidth() {
        return true;
    }

    @Override
    public boolean getScrollableTracksViewportHeight() {
        return false;
    }

}

You would use this by adding your current FlowLayout layout to an instance of MyPanel (instead of directly to the JScrollPane) and then calling

js.setViewportView(myPanelInstance);
Community
  • 1
  • 1
Ted Hopp
  • 232,168
  • 48
  • 399
  • 521
  • @askManiac - Please explain how your requirements differ from what `FlowLayout` already does. When the first row is full, `FlowLayout` will start a second row (unless your entire layout is in a horizontal scroller, in which case it would be very hard to fill the first row). – Ted Hopp Sep 28 '14 at 01:19
  • well what I did was I put a JPanel inside a JscrollPane? – askManiac Sep 28 '14 at 01:21
  • *"put a JPanel inside a JscrollPane?"* That would result in a single row of components. – Andrew Thompson Sep 28 '14 at 01:22
  • @askManiac - Get rid of the JScrollPane. Either you want scrolling or you want the views to wrap. It doesn't make much sense to have both. – Ted Hopp Sep 28 '14 at 01:24
  • @TedHopp your answer is reasonable :) – Muhammad Sep 28 '14 at 01:25
  • @AndrewThompson hm if I removed the scrollPane would that solve the problem? I put the ScrollPane bcoz I wanted to make the system scrollable when there are 3 rows already :D – askManiac Sep 28 '14 at 01:25
  • @TedHopp ok removing scrollpanel, hmm then how can I make the system have a vertical scroll when the panel already has 3 rows – askManiac Sep 28 '14 at 01:26
  • My answer not only shows a better layout to use, it also links to code that accounts for more components than can be viewed in the available space (with a scroll pane). You would need to jump through some hoops to get this working with `FlowLayout`, such as enforcing a width for the panel that contains all the components. **Try the linked code.** – Andrew Thompson Sep 28 '14 at 01:27
  • @AndrewThompson - With all due respect, your answer has a deficiency: you have to know how many columns to set. From the way OP has posed the question, my guess is that this is not a fixed number and would have to be computed from the current width of the parent container. Not an easy task unless you're writing your own custom layout class. – Ted Hopp Sep 28 '14 at 01:30
  • *"For one, you have to know how many columns to set."* For one, **you** have to know what width to enforce on the parent container. If you don't even know how many components are in a row, how on earth do you expect to know the width to enforce? Seriously, you should ***try implementing your suggestion.*** – Andrew Thompson Sep 28 '14 at 01:32
  • @TedHopp `scrollGUI.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); scrollGUI.setAutoscrolls(true); scrollGUI.setViewportView(gui); ` hmm here's the code of the scrollpane, but still the 7th order added didn't go down the 2nd row – askManiac Sep 28 '14 at 01:35
  • *"Yeah, there was a piece missing."* I challenge you to produce an MCVE (and screen-shot, would be a bonus). Basically because I'm sure it won't be workable with `FlowLayout`. I'll change the -1 to +1 if you can prove me wrong. – Andrew Thompson Sep 28 '14 at 02:12
2

Approach - Variable width with WrapLayout

The GridLayout solution presumes the GUI requires 6 components per row.

For as many cols as needed to fill the width, & then show the components in as many rows as required, look to WrapLayout.

enter image description here enter image description here

Approach - Variable width with JList

A JList can also be used here, since it seems all the components consist of a single (GUI) object.

enter image description here enter image description here

import java.awt.*;
import java.awt.event.ActionEvent;
import javax.swing.*;
import javax.swing.border.*;

public class ListComponents {

    public static void main(String[] args) {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                String[] listData = {
                    "Component 1", "Component 2", "Component 3",};
                final DefaultListModel<String> model
                        = new DefaultListModel<String>();
                for (String datum : listData) {
                    model.addElement(datum);
                }
                JList list = new JList(model);
                list.setLayoutOrientation(JList.HORIZONTAL_WRAP);
                list.setVisibleRowCount(-1);
                list.setCellRenderer(new ObjectCellRenderer());

                Action addAction = new AbstractAction("Add New") {

                    @Override
                    public void actionPerformed(ActionEvent e) {
                        model.addElement("New Component");
                    }
                };
                JButton addNew = new JButton(addAction);

                JPanel ui = new JPanel(new BorderLayout(3, 3));
                ui.setBorder(new EmptyBorder(4, 4, 4, 4));
                ui.add(new JScrollPane(list), BorderLayout.CENTER);

                ui.add(addNew, BorderLayout.PAGE_START);

                JFrame f = new JFrame("Component List");
                f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                f.setContentPane(ui);
                f.pack();
                f.setLocationByPlatform(true);
                f.setVisible(true);
            }
        };
        SwingUtilities.invokeLater(r);
    }

}

class ObjectCellRenderer extends DefaultListCellRenderer {

    Border border = new EmptyBorder(20, 5, 20, 5);

    public Component getListCellRendererComponent(
            JList list,
            Object value,
            int index,
            boolean isSelected,
            boolean cellHasFocus) {
        JLabel label = (JLabel) super.getListCellRendererComponent(
                list, value, index, isSelected, cellHasFocus);
        label.setBorder(border);
        return label;
    }
}

Approach - Fixed width with GridLayout

Using a GridLayout, when we know we always want a fixed number per row, regardless of width.

JPanel mainPanel = new JPanel(new GridLayout(0,6));

See new GridLayout(rows,cols):

Creates a grid layout with the specified number of rows and columns. All components in the layout are given equal size.

One, but not both, of rows and cols can be zero, which means that any number of objects can be placed in a row or in a column.

See this code for an example using a GridLayout(0,2) for the labels beneath Add Another Label

Community
  • 1
  • 1
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
  • See the latest edits, and in the first two cases (the code here and the other answer I linked to) the scroll pane is automatic when needed (the scroll bar appears). – Andrew Thompson Sep 28 '14 at 02:08
  • 1
    Yes, `WrapLayout` is a very handy layout for this type of task. Glad you got it sorted. :) – Andrew Thompson Sep 28 '14 at 04:23