Search code examples
javacodenameone

Codename One app UI Container not rendering after programmatic update


I am having a problem with making the UI work properly in a Codename One application. I have distilled it down to just the "starter application" which loads a ParentContainer.

The ParentContainer has a SINGLE button which updates a ChildContainer. It really just removes and adds a label when you click the button.

THE PROBLEM: The ChildContainer doesn't seem to want to render the label? Its empty. If I force a hard refresh in the Simulator by ROTATING THE DEVICE then it renders the label one time. I also checked the Codename One desktop application build and see the same problem. For the Desktop Build I can resize the main window and it will render the label.

Nothing programmatically makes it show up. invalidate() / repaint() / callSerially()

Even after I get it to display, if I push the ParentContainer button again it disappears. What am I doing wrong? Any help would be greatly appreciated.

public class BugTestApp extends Lifecycle {

    @Override
    public void runApp() {
        Form hi = new Form("Hi World");
        hi.setLayout(new BorderLayout());

        ParentContainer container = new ParentContainer();
        container.init();

        hi.add(BorderLayout.CENTER, container);
        hi.show();
    }
}
public class ParentContainer extends Container {
    ChildContainer childContainer=null;
    
    public void init() {
        
        this.setLayout(new BorderLayout());
        Button btnFilterCategory = new Button("CLICK ME TO ACTIVATE");
        btnFilterCategory.addActionListener(e-> {
            childContainer.reloadAll();
        });
        this.add(BorderLayout.NORTH,btnFilterCategory);

        childContainer = new ChildContainer();
        childContainer.initComponents();
        this.add(BorderLayout.CENTER, childContainer);
    }
}
public class ChildContainer extends Container {

    public void initComponents() {
        setLayout(new BoxLayout(BoxLayout.Y_AXIS));
        reloadAll();
    }

    public void reloadAll() {
        this.removeAll();
        this.add(new Label("This is a label."));
        this.repaint();
    }
}

Solution

  • repaint() isn't the right method here. What you need to use is revalidate() or animateLayout(int) etc.

    repaint() redraws the components without resizing/laying out. The new components are zero sized. You need to explicitly layout components if you add them to a Form that's already showing. Rotation will implicitly trigger a relayout of the form.