Search code examples
javaswingjlistjradiobutton

JRadioButton invalid alignment when add to JList


Hi I am making a gui for a flight booking system and I have to make sure user selects only one flight in the JList when the query button is clicked, so I decided to make a JList of RadioButton as follows:

  flightsList = new JList<JRadioButton>();

  button.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
      //user inputs
      String takeoff = (String) from.getSelectedItem();
      String destina = (String) to.getSelectedItem();
      String flyDate = (String) date.getText();

      try {
        //get all available flights
        Flight[] flights = manager.getFlights(takeoff, destina, flyDate);
        //model for list
        DefaultListModel<JRadioButton> model =
                                      new DefaultListModel<JRadioButton>();
        //fill model with flights found
        for(int flightNum = 0; flightNum < flights.length; flightNum++) {
          model.addElement(new JRadioButton(flights[flightNum].toString()));
        }//for

        //put model into jlist
        flightsList.setModel(model);

      } catch (BadQueryException bqe) {
        JRadioButton[] errorMessage = {
                      new JRadioButton("Error: " +  bqe.getMessage()) };
        //put error message into list
        flightsList.setListData(errorMessage);
      }//try catch

    }//actionPerformed
  });

When I run, the JList shows lines of:

javax.swing.JRadioButton[,0,0,0x0,invalid,alignmentX=0.0,alignmentY=0.5,border=javax.swing.plaf.BorderUIResource$CompoundBorderUIResource@78092fac,flags=296,maximumSize=,minimumSize=,preferredSize=,defaultIcon=,disabledIcon=,disabledSelectedIcon=,margin=javax.swing.plaf.InsetsUIResource[top=2,left=2,bottom=2,right=2],paintBorder=false,paintFocus=true,pressedIcon=,rolloverEnabled=true,rolloverIcon=,rolloverSelectedIcon=,selectedIcon=,text=BA002 | London >> Manchester | Tue, 01/10/2019 06:30]

May I know what happened and how to solve this?
Thank you.


Solution

  • When I run, the JList shows lines of:

    javax.swing.JRadioButton[,0,0,0x0,invalid,alignmentX=0.0,alignmentY=0.5....]

    May I know what happened and how to solve this?

    This happens because your JList has a DefaultListCellRenderer. As you can see, this class extends JLabel. The method DefaultListCellRenderer#getListCellRendererComponent() is getting an argument Object value. This value's type is equals to the type of your JList.

    With that being said, your JList has JRadioButton as a generic type (JList< JRadioButton>), which means the Object value arguemnt is a JRadioButton.

    Now, DefaultListCellRenderer in order to get its text, it calls the toString() method of the value hence you get this kind of text in your list's cells. (The toString() method of a JRadioButton, returns its details, coordinates, sizes, etc...)

    The solution:

    It would be to use a custom ListCellRenderer. This way you can render any value-property of the argument named "value"i in getListCellRendererComponent() method. In your case, you need to render JRadioButton.

    I will share an example with comments inside the code in order to understand this better.

    SSCCE:

    import java.awt.BorderLayout;
    import java.awt.Component;
    import java.util.List;
    
    import javax.swing.DefaultListModel;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JList;
    import javax.swing.JRadioButton;
    import javax.swing.ListCellRenderer;
    import javax.swing.SwingUtilities;
    
    public class JListJRadioButtonRenderer extends JFrame {
        public JListJRadioButtonRenderer() {
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            addList();
            setSize(300, 300);
            setLocationRelativeTo(null);
        }
    
        private void addList() {
            JList<JRadioButton> list = new JList<>();
            DefaultListModel<JRadioButton> model = new DefaultListModel<>();
            // Add the custom renderer.
            list.setCellRenderer(new ListCellRenderer<JRadioButton>() {
    
                @Override
                public Component getListCellRendererComponent(JList<? extends JRadioButton> list, JRadioButton value,
                        int index, boolean isSelected, boolean cellHasFocus) {
                    // Fix background for selected cells.
                    value.setBackground(isSelected ? list.getSelectionBackground() : null);
                    // Select the JRadioButton too since it is selected in the list.
                    value.setSelected(isSelected);
                    return value;
                }
            });
            list.setModel(model);
            JRadioButton stackButton = new JRadioButton("Hello Stack");
            JRadioButton overButton = new JRadioButton("Hello Over");
            JRadioButton flowButton = new JRadioButton("Hello Flow");
            model.addElement(stackButton);
            model.addElement(overButton);
            model.addElement(flowButton);
            getContentPane().add(list);
    
            JButton printSelected = new JButton("Print selected");
            printSelected.addActionListener(e -> {
                List<JRadioButton> selectedButtons = list.getSelectedValuesList();
                for (JRadioButton r : selectedButtons)
                    System.out.println(r.getText());
            });
            getContentPane().add(printSelected, BorderLayout.PAGE_END);
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(() -> new JListJRadioButtonRenderer().setVisible(true));
        }
    }
    

    Preview:

    enter image description here