0

It has been a while since I programmed with Java Swing, so I'm not an expert with all it's methods. Just to contextualize what I'm doing, I'm building an URCap UI that I'm using in a UR Cobot (That's basically a UI that allows me to control something installed to the robot like a gripper, for example) and for this UI I have to create around 64 CheckBoxes to be selected by the user and he can check one or more at the same time. So, following tutorial and other questions from StackOverflow I began by creating a list of CheckBoxes private List<JCheckBox> checkBoxList = new ArrayList<JCheckBox>(); And I added each element of this list to a JPanel, then I added the panel to a JScrollPane, like this:

for (JCheckBox checkBox: checkBoxList) {
            panel.add(checkBox);
        }
        
        scrollPane.add(panel);

This is the further that I could get after tirelessly search for help and testing codes that I found, and this logic should (I think) normally work, according to the people that provide them, but in my case, when I build it, the ScrollPane is showed in the GUI, but there's no checkbox, see the below image:

UI using List

I'm not sure what is causing this problem, I don't know if I should use a list of CheckBoxes like this, just defining it as a List, but I tried a lot of different ways, using a JList, an Array JCheckBox[] and others, but they give me the same problem.

I know that besides this error, my code is working, because I tested the scrollPane using a single JCheckBox (see function createJobsPanel1()) and it's successfully rendering the checkbox:

UI using a single JCheckBox

This is my full code and to explain it breafly to you, you only have to focus on the functions createJobsPanelx(), setIOCheckBoxItems() and the global variables where I define my JCheckBox list. The funciont BuildUI() only calls the others to build the UI. Also, the setIOCheckBoxItems() is called by another function that is placed in another class, but just to explain what it does, it sets the JCheckBox list elements to "1, 2, 3, 4, 5 ..." and so on.

package com.sigmaclermont.ploc2dMultObjDetect.impl;

import java.awt.Component;

import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JCheckBox;
import javax.swing.JScrollPane;
import javax.swing.plaf.metal.MetalCheckBoxIcon;

import com.ur.urcap.api.contribution.ContributionProvider;
import com.ur.urcap.api.contribution.ViewAPIProvider;
import com.ur.urcap.api.contribution.program.swing.SwingProgramNodeView;


public class Ploc2dProgramNodeView implements SwingProgramNodeView<Ploc2dProgramNodeContribution>{
    
    private final ViewAPIProvider apiProvider;
    
    public Ploc2dProgramNodeView(ViewAPIProvider apiProvider) {
        this.apiProvider = apiProvider;
    }
    
    
    //private JCheckBox[] checkBoxList = new JCheckBox[64];
    //private JCheckBox checkBoxOrig = new JCheckBox();
    private List<JCheckBox> checkBoxList = new ArrayList<JCheckBox>();

    @Override
    public void buildUI(JPanel panel, ContributionProvider<Ploc2dProgramNodeContribution> provider) {
        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
        panel.add(createDescription("Select the active Jobs:"));
        panel.add(createJobsPanel2(checkBoxList));
    }
    
    /*public void setIOCheckBoxItem1(Integer item) {

        checkBoxOrig.setText(Integer.toString(item));
        checkBoxOrig.setIcon(new MetalCheckBoxIcon() {
            protected int getControlSize() {return 30;}
        });
        checkBoxOrig.setFont(new java.awt.Font("Arial", Font.LAYOUT_LEFT_TO_RIGHT, 20));
        
    }*/
    
    public void setIOCheckBoxItem2(Integer[] items) {
        
        for (Integer item: items) {
            checkBoxList.add(new JCheckBox(Integer.toString(item+1)));
        }
    }
    
    private Box createDescription(String desc) {
        Box box = Box.createHorizontalBox();
        box.setAlignmentX(Component.LEFT_ALIGNMENT);
        JLabel label = new JLabel(desc);
        box.add(label);
        
        return box;
    }
    
    /*private Box createJobsPanel1(final JCheckBox checkBox) {
        Box box = Box.createHorizontalBox();
        box.setAlignmentX(Component.LEFT_ALIGNMENT);
        
        JPanel panel = new JPanel();
        panel.add(checkBox);
        
        JScrollPane scrollPane = new JScrollPane(panel);
        scrollPane.setPreferredSize(new Dimension(100,100));
        scrollPane.setMaximumSize(scrollPane.getPreferredSize());
        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        
        checkBox.addItemListener(new ItemListener() {
            
            @Override
            public void itemStateChanged(ItemEvent arg0) {
                // TODO Auto-generated method stub
                
            }
        });
        
        box.add(scrollPane);
        
        return box;
    }*/
    
    private Box createJobsPanel2(final List<JCheckBox> checkBoxList) {
        Box box = Box.createHorizontalBox();
        box.setAlignmentX(Component.LEFT_ALIGNMENT);
        
        JScrollPane scrollPane = new JScrollPane();
        scrollPane.setPreferredSize(new Dimension(300,300));
        scrollPane.setMaximumSize(scrollPane.getPreferredSize());
        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        
        JPanel panel = new JPanel();
        panel.setPreferredSize(new Dimension(250,250));
        panel.setMaximumSize(panel.getPreferredSize());
        panel.setLayout(new GridLayout(8,1));
        
        for (JCheckBox checkBox: checkBoxList) {
            panel.add(checkBox);
        }
        
        scrollPane.add(panel);
        
        for (JCheckBox checkBox: checkBoxList) {
            checkBox.addItemListener(new ItemListener() {
                
                @Override
                public void itemStateChanged(ItemEvent arg0) {
                    // TODO Auto-generated method stub
                    
                }
            });
        }
        
        box.add(scrollPane);
        
        return box;
    }

}


I tried all types of solution, but none worked. I expect a ScrollPane containing 64 checkboxes with text from "1" to "64" where the user can select one or more.

EDIT: Here is the backend code that contains the openView() method, it calls the setIOCheckBoxItems() from the other code and passes the integer array from 1 to 64

package com.sigmaclermont.ploc2dMultObjDetect.impl;

import com.ur.urcap.api.contribution.ProgramNodeContribution;
import com.ur.urcap.api.contribution.program.ProgramAPIProvider;
import com.ur.urcap.api.domain.data.DataModel;
import com.ur.urcap.api.domain.script.ScriptWriter;
import com.ur.urcap.api.domain.undoredo.UndoRedoManager;
import com.ur.urcap.api.domain.undoredo.UndoableChanges;

public class Ploc2dProgramNodeContribution implements ProgramNodeContribution{
    
    private final ProgramAPIProvider apiProvider;
    private final Ploc2dProgramNodeView view;
    private final DataModel model;
    private final UndoRedoManager undoRedoManager;
    
    public Ploc2dProgramNodeContribution(ProgramAPIProvider apiProvider, Ploc2dProgramNodeView view,
            DataModel model) {
        this.apiProvider = apiProvider;
        this.view = view;
        this.model = model;
        this.undoRedoManager = this.apiProvider.getProgramAPI().getUndoRedoManager();
    }

    private Integer[] getOutputItems() {
        Integer[] items = new Integer[64];
        for(int i = 0; i<64; i++) {
            items[i] = i;
        }
        return items;
    }
    
    @Override
    public void openView() {
        view.setIOCheckBoxItems(getOutputItems());
    }

    @Override
    public void closeView() {
        // TODO Auto-generated method stub
        
    }

    @Override
    public String getTitle() {
        return "Ploc2D MultiObj";
    }

    @Override
    public boolean isDefined() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public void generateScript(ScriptWriter writer) {
        // TODO Auto-generated method stub
        
    }

}

EDIT 2: I tried the answer given by Caps and it didn't solve my problem, but it did change something, now, instead of a grey area inside the scrollpane, the area is white, so the panel probably is inside the scrollpane. Here's the screenshot:

New GUI after modifying the code

2
  • 1
    We can't see how you create the frame and add the scroll pane containing the checkboxes to the frame. Post a proper minimal reproducible example demonstrating the problem. Your question is about checkboxes on a panel in a frame. So that is all your code should do. You should not have 3rd party classes in the MRE. So your entire MRE will about about 20 lines of code. A few to create the frame a loop to add the check boxes to the panel. Then once you get the basic UI, you worry about your application logic.
    – camickr
    Commented Apr 19 at 13:48
  • It's not only a Java Swing code, it is mainly a URCap development library that has 4 main code, one for the "backend", another for the frontend (that is the code in my question and other 2 to configuration. The tutorial doesn't use JFrame, it only creates the BuildUI() method that creates the main panel and the rest is done on the back when you build your code, so you don't have to declare a JFrame here, at least that's what I understood of the tutorials. I hope I explained it better to you now.
    – Searcher
    Commented Apr 19 at 13:59

2 Answers 2

1

Initialize the scrollpane with the jpanel:

    private static Box createJobsPanel2(final List<JCheckBox> checkBoxList) {
    Box box = Box.createHorizontalBox();
    box.setAlignmentX(Component.LEFT_ALIGNMENT);


    JPanel panel = new JPanel();
    panel.setPreferredSize(new Dimension(250,250));
    panel.setMaximumSize(panel.getPreferredSize());
    panel.setLayout(new GridLayout(8,1));

    for (JCheckBox checkBox: checkBoxList) {
        panel.add(checkBox);
    }

    JScrollPane scrollPane = new JScrollPane(panel);
    scrollPane.setPreferredSize(new Dimension(300,300));
    scrollPane.setMaximumSize(scrollPane.getPreferredSize());
    scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);


    for (JCheckBox checkBox: checkBoxList) {
        checkBox.addItemListener(new ItemListener() {

            @Override
            public void itemStateChanged(ItemEvent arg0) {
                // TODO Auto-generated method stub

            }
        });
    }

    box.add(scrollPane);

    return box;
}
2
  • Hello, sorry for the late response. I just tried what you suggested and it didn't work either, the UI is still blank, but I changed something, instead of having a grey area at the scrollpane, now I have only the scrollbar and a blank area. I will put the resulting UI using your answer as an EDIT of my question, because I'll put the screenshot. If you could help me understand why now I have it all blank I would be much appreciated.
    – Searcher
    Commented Apr 22 at 13:00
  • It is possible that now the panel is well initialized inside the scrollpane, but the checkboxes are all NULL?
    – Searcher
    Commented Apr 22 at 13:08
0

Here to say that I finally found the solution and I had to do 2 changes in my code for it to work, the first one was to implement @Caps' suggestion in his answer, initializing the Scrollpane with the panel instead of adding it afterwards. So if anyone encounter the same problem, just do this changement.

JScrollPane scrollPane = new JScrollPane(panel);

The second thing that I discovered is that my JCheckBox list was empty because it wasn't initializing the JCheckBoxes inside the setIOCheckBoxItem2() function

public void setIOCheckBoxItem2(Integer[] items) {
    
    for (Integer item: items) {
        checkBoxList.add(new JCheckBox(Integer.toString(item+1)));
    }
}

So when createJobsPanel2(checkBoxList) is called, checkBoxList is empty, tho the panel will be empty as well, setIOCheckBoxItem2() is being called after this function, meaning that my list was being filled after creating the scrollPane, not before, as I thought. The solution was then initialize the checkBoxList in the constructor of the class, where I know for sure that is the first method called in my code before createJobsPanel(), so the checkBoxList will not be empty. After that, in setIOCheckBoxItem2() I just use setText() to change the checkBoxes text and other parameters.

Thanks you all, here is the working final code:

package com.sigmaclermont.ploc2dMultObjDetect.impl;

import java.awt.Component;

import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.DefaultListModel;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.ListCellRenderer;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.metal.MetalCheckBoxIcon;
import javax.swing.JList;

import com.ur.urcap.api.contribution.ContributionProvider;
import com.ur.urcap.api.contribution.ViewAPIProvider;
import com.ur.urcap.api.contribution.program.swing.SwingProgramNodeView;


public class Ploc2dProgramNodeView implements SwingProgramNodeView<Ploc2dProgramNodeContribution>{
    
    private final ViewAPIProvider apiProvider;
    private List<JCheckBox> checkBoxList = new ArrayList<JCheckBox>();
    
    public Ploc2dProgramNodeView(ViewAPIProvider apiProvider) {
        // Here the checkBoxList is initialized
        for (int i = 0; i < 64; i++) {
            checkBoxList.add(new JCheckBox());
        }
        
        this.apiProvider = apiProvider;
    }
    

    @Override
    public void buildUI(JPanel panel, ContributionProvider<Ploc2dProgramNodeContribution> provider) {
        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
        panel.add(createDescription("Select the active Jobs:"));
        panel.add(createJobsPanel(checkBoxList));
    }
    
    public void setIOCheckBoxItems(Integer[] items) {
        // Here I set the text and other parameter of the checkboxes
        for (Integer item: items) {
            checkBoxList.get(item).setText(Integer.toString(item+1));
            checkBoxList.get(item).setIcon(new MetalCheckBoxIcon() {
                protected int getControlSize() {return 40;}
            });
            checkBoxList.get(item).setFont(new java.awt.Font("Arial", Font.LAYOUT_LEFT_TO_RIGHT, 25));
        }
    }
    
    private Box createDescription(String desc) {
        Box box = Box.createHorizontalBox();
        box.setAlignmentX(Component.LEFT_ALIGNMENT);
        JLabel label = new JLabel(desc);
        box.add(label);
        
        return box;
    }
    
    Box createJobsPanel(final List<JCheckBox> checkBoxList) {
        Box box = Box.createHorizontalBox();
        box.setAlignmentX(Component.LEFT_ALIGNMENT);
        
        JPanel panel = new JPanel();
        panel.setLayout(new BoxLayout(panel,BoxLayout.Y_AXIS));
        
        for (JCheckBox checkBox: checkBoxList) {
            panel.add(checkBox);
        }
        
        JScrollPane scrollPane = new JScrollPane(panel);
        scrollPane.setPreferredSize(new Dimension(300,300));
        scrollPane.setMaximumSize(scrollPane.getPreferredSize());
        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        
        
        for (JCheckBox checkBox: checkBoxList) {
            checkBox.addItemListener(new ItemListener() {
                
                @Override
                public void itemStateChanged(ItemEvent arg0) {
                    // TODO Auto-generated method stub
                    
                }
            });
        }
        
        box.add(scrollPane);
        
        return box;
    }

}

And the resulting UI: Working UI

Not the answer you're looking for? Browse other questions tagged or ask your own question.