Distribution of components in Grouplayout

Asked

Viewed 140 times

1

The example below has a GroupLayout which contains two elements, a custom search and filter bar (JPanelSearchAndFilter) and a JScrollPane.

When it runs and then the window is maximized you can notice that these two elements are distributed equally on the screen.

When selecting any item in the combo box, the screen fills with lines of text and the search and filter bar occupies a smaller size on the screen, giving space to the lines of text.

I would like to know how to make this bar smaller since the start of the execution. Preferably without using a BorderLayout for that reason.

I thought I’d set the size of JScrollPane or fill it with invisible items, but this seems to me gambiarra. I believe it is possible a solution using layout managers.

Grouppanel.java

import java.awt.EventQueue;
import java.awt.Font;

import javax.swing.BoxLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

public class GroupPanel extends JPanel implements Listener   {

    private static final long serialVersionUID = 1L;

    private JPanelSearchAndFilter jPanelSearchAndFilter = new JPanelSearchAndFilter();
    private JPanel jPanelListaOrders = new JPanel();
    private JScrollPane jScrollPaneOrders = new JScrollPane(jPanelListaOrders);

    public GroupPanel() {

        javax.swing.GroupLayout jPanelMainLayout = new javax.swing.GroupLayout(this);

        jPanelMainLayout.setHorizontalGroup(jPanelMainLayout.createParallelGroup(Alignment.LEADING)
                .addGroup(jPanelMainLayout.createSequentialGroup()
                        .addGroup(jPanelMainLayout.createParallelGroup(Alignment.LEADING)
                                .addComponent(jPanelSearchAndFilter)
                                .addComponent(jScrollPaneOrders))
                        ));

        jPanelMainLayout.setVerticalGroup(jPanelMainLayout.createParallelGroup(Alignment.LEADING)
                .addGroup(jPanelMainLayout.createSequentialGroup().addGroup(
                        jPanelMainLayout.createParallelGroup(Alignment.LEADING)
                        .addGroup(jPanelMainLayout.createSequentialGroup()
                                .addComponent(jPanelSearchAndFilter)
                                .addComponent(jScrollPaneOrders)))));

        this.setLayout(jPanelMainLayout);

        jPanelListaOrders.setBackground(new java.awt.Color(254, 254, 254));
        jPanelListaOrders.setLayout(new javax.swing.BoxLayout(jPanelListaOrders, javax.swing.BoxLayout.Y_AXIS));

        jPanelSearchAndFilter.setListener(this);
    }

    private static void display() {
        JFrame f = new JFrame("GroupPanel");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setLayout(new BoxLayout(f.getContentPane(), BoxLayout.Y_AXIS));
        f.add(new GroupPanel());
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                display();
            }
        });
    }

    @Override
    public void onEvent(String event) {
        for (int i = 1; i <= 10; i++) {
            JLabel label = new JLabel(event + " " + i);
            label.setFont(new Font("Tahoma", Font.BOLD, 60));
            jPanelListaOrders.add(label);
        }

        revalidate();
        repaint();
    }
}

Jpanelsearchandfilter.java

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.Objects;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class JPanelSearchAndFilter extends JPanel {

    private static final String [] ORDER_STATUSES = {
            "Todos",
            "Novos",
            "Confirmados",
            "Prontos/Enviados",
            "Entregues",
            "Cancelados"
            };

    private Listener listener = null;

    public JPanelSearchAndFilter() {

        setForeground(Color.GRAY);
        setLayout(new BoxLayout(this, BoxLayout.X_AXIS));

        setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));

        searchField = new JTextField("Pesquisar");
        searchField.setForeground(Color.GRAY);
        searchField.setFont(new Font("Tahoma", Font.PLAIN, 15));
        searchField.setToolTipText("Pesquisar");
        add(searchField);
        searchField.setColumns(10);

        // Cria um espaço vazio de tamanho fixo entre searchField e filterComboBox.
        add(Box.createRigidArea(new Dimension(20, 0)));

        ComboBoxModel<String> filterComboModel = new DefaultComboBoxModel<>(ORDER_STATUSES);
        JComboBox<String> filterComboBox = new JComboBox<>(filterComboModel);
        filterComboBox.setFont(new Font("Tahoma", Font.PLAIN, 15));
        filterComboBox.setSelectedIndex(0);

        filterComboBox.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent itemEvent) {
                JPanelSearchAndFilter.this.listener.onEvent((String)itemEvent.getItem());
            }
        });

        add(filterComboBox);
    }

    public void setListener(Listener listener) {
        this.listener = listener;
    }

    private static final long serialVersionUID = 1L;
    private JTextField searchField;
}

Java listener.

public interface Listener {
    public void onEvent(String event);
}
  • This grouppanel is really necessary?

  • @Sorry about my inexperience. It could be a Jpanel (actually it’s one), was the way I found to transpose the application code I’m working on to the example. I believe it is a root element of the structure that is needed yes. What you thought?

1 answer

2


The layout manager you are using(GroupLayout) works with relative values, and you end up mixing another layout(BoxLayout) above which also works with relative values to define the distribution of the components on the screen, but the first one ends up prevailing. The problem is that, when revalidating the panel, it understands that it needs more space for the list and reduces the size of the other panel with the text field.

Although it is a very robust layout manager, Grouplayout is extremely complex to use, so much so that it is usually used only by IDE’s screen generation Engines like the netbeans case.

The solution to the problem I found was to completely remove the GroupLayout and use the BorderLayout, that although it also works with relative values, it better defines the distribution of the components on the screen, distributing in 5 fixed regions. As you want the search panel to be at the top and the list panel at the rear of the search panel, just set as below your class GroupPanel:

    this.setLayout(new BorderLayout());

    this.add(jPanelSearchAndFilter, BorderLayout.NORTH);
    this.add(jScrollPaneOrders, BorderLayout.CENTER);

If there is no other defined region, the JSCrollPane will occupy all the rest of the Borderlayout, from the defined region.

Another detail I modified is also the repaint(), since, in accordance with this answer, the same is already invoked internally when you run the revalidate() to redesign the screen.

The code was as follows:

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Font;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

public class GroupPanel extends JPanel implements Listener {

    private static final long serialVersionUID = 1L;

    private JPanelSearchAndFilter jPanelSearchAndFilter = new JPanelSearchAndFilter();
    private JPanel jPanelListaOrders = new JPanel();
    private JScrollPane jScrollPaneOrders = new JScrollPane(jPanelListaOrders);

    public GroupPanel() {

        this.setLayout(new BorderLayout());

        this.add(jPanelSearchAndFilter, BorderLayout.NORTH);
        this.add(jScrollPaneOrders, BorderLayout.CENTER);

        jPanelListaOrders.setBackground(new java.awt.Color(254, 254, 254));
        jPanelListaOrders.setLayout(new javax.swing.BoxLayout(jPanelListaOrders, javax.swing.BoxLayout.Y_AXIS));

        jPanelSearchAndFilter.setListener(this);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                JFrame f = new JFrame("GroupPanel");
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.add(new GroupPanel());
                f.pack();
                f.setLocationRelativeTo(null);
                f.setVisible(true);
            }
        });
    }

    @Override
    public void onEvent(String event) {
        for (int i = 1; i <= 10; i++) {
            JLabel label = new JLabel(event + " " + i);
            label.setFont(new Font("Tahoma", Font.BOLD, 60));
            jPanelListaOrders.add(label);
        }

        revalidate();
    }
}
  • A question, what is the problem of Jframe being static?

  • @Piovezan researching here, I realized I was mistaken, it does not leak from the EDT because the jvm already starts automatically inside it when you da setVisible(). But in the future if you are going to add multithreading operations, you may have some problems with listeners, so to avoid problems, it is better to leave everything to the EDT even.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.