Search code examples
javaswingwidthlayout-managerspringlayout

Width of components in SpringLayout after UI-Update equals 0


TL;DR On different DPI settings, components of my application can overlap. To get rid of that I want to check the components width, which always equals 0 after updating the UI. Simplyfied code at the end of the question.

The base problem is that on different DPI settings different parts of my program is the one that reaches farthest to the right. On higher DPI its a dynamically generated label and on lower DPI a fixed width textfield.
I am working with a SpringLayout to deal with possible changing DPI settings. With the above described I have the problem that on specific settings components overlap.

To overcome that, I wanted to check whether the left edge of the one component is further left than the right edge of the other component +10 pixels for more space.

if (labelRight.getX() < (labellist.get(0).getX() + labellist.get(0).getWidth+10)){ 
//Use one SpringLayout setting for labelRight
} else //Use another SpringLayout setting for labelRight

I assume the problem is that I check the width of the components after they were generated. The user may choose from different settings which will change parts of the panels content. labellist contains the rightmost labels from that area.
I made up a small testprogram to show the problem width the width check:

import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SpringLayout;
import javax.swing.UIManager;

public class testsforSO extends JFrame {

    private static final long serialVersionUID = -857761460788731909L;
    ArrayList<JLabel> lbls = new ArrayList<>();
    int lblCount = 6; 
    JPanel panel = new JPanel();
    SpringLayout sl_panel = new SpringLayout();

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                testsforSO frame = new testsforSO();
                frame.pack();
                frame.setVisible(true);
                frame.setSize(500, 500);
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        });
    }

    public testsforSO() {

        getContentPane().add(panel);

        updateUI();

        JButton incr = new JButton("Increment here!");
        incr.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                for (int i=0; i<=lbls.size()-1; i++){
                    panel.remove(lbls.get(i));
                }

                lblCount++;
                lbls.clear();
                updateUI();
                panel.repaint();
                panel.revalidate();

                System.out.println("Width of slimest label: " + lbls.get(0).getWidth());
                System.out.println("Width of widest label : " + lbls.get(lbls.size()-1).getWidth());
            }
        });
        panel.add(incr);
        sl_panel.putConstraint(SpringLayout.NORTH, incr, 10, SpringLayout.NORTH, panel);
        sl_panel.putConstraint(SpringLayout.EAST, incr, -10, SpringLayout.EAST, panel);

        panel.setLayout(sl_panel);
    }

    private void updateUI(){
        for (int i = 0; i <= lblCount; i++) {
            String abc = new String();
            for (int j = 0; j <= i; j++) {
                abc += "xx";
            }
            JLabel bfrLbl = new JLabel(abc);
            lbls.add(bfrLbl);
            panel.add(bfrLbl);
        }

        for (int i = 0; i <= lbls.size() - 1; i++) {
            if (i > 0)
                sl_panel.putConstraint(SpringLayout.NORTH, lbls.get(i), 8, SpringLayout.SOUTH, lbls.get(i - 1));
            else
                sl_panel.putConstraint(SpringLayout.NORTH, lbls.get(i), 8, SpringLayout.NORTH, panel);
        }

    }
}

When pressing the button, the UI gets updated with one more label at the bottom. The SpringLayout is fitted accordingly and the panel gets revalidated after. However the output of the width is 0. Why is it and what can I do against that?


Solution

  • After further investigation I found a way to correctly read the width of the component:

    sl_panel.getConstraint(SpringLayout.WIDTH, lbls.get(0)).getValue();
    

    Does the trick. Seems to be a very massive line compared to

    lbls.get(0).getWidth();
    

    though.