codenameone / CodenameOne

Cross-platform framework for building truly native mobile apps with Java or Kotlin. Write Once Run Anywhere support for iOS, Android, Desktop & Web.
https://www.codenameone.com/
Other
1.71k stars 408 forks source link

frame layout never called under some conditions #2989

Open ddyer0 opened 4 years ago

ddyer0 commented 4 years ago

Under some conditions, layout never occurs. It seems to be the case that content added to the frame after it is initially seen doesn't trigger the layout machinery. The new setAllowEnableLayoutOnPaint(true); option doesn't help with this example, although (fortunately) it does help for my action application. This example fails (as intended) in the simulator, so no actual devices are needed to see the problem.

package dtest.boardspace;

import com.codename1.ui.Component;
import com.codename1.ui.Container;

import com.codename1.ui.Display;
import com.codename1.ui.Form;
import com.codename1.ui.Graphics;
import com.codename1.ui.geom.Dimension;
import com.codename1.ui.layouts.Layout;
import com.codename1.ui.plaf.UIManager;
import com.codename1.ui.util.Resources;

interface NullLayoutProtocol {
    public void doNullLayout();
}

class NullLayout extends Layout 
{   
    NullLayoutProtocol expectedParent;
    public NullLayout(NullLayoutProtocol parent) { expectedParent = parent; }
    /* Required by LayoutManager. */
    public void addLayoutComponent(String name, Component comp)    {  }

    /* Required by LayoutManager. */
    public void removeLayoutComponent(Component comp)    {  }

    /* Required by LayoutManager. */
    public Dimension preferredLayoutSize(Container parent) {
        Dimension dim = new Dimension(parent.getWidth(), parent.getHeight());
        return dim;
    }

    /* Required by LayoutManager. */
    public Dimension minimumLayoutSize(Container parent) {
        Dimension dim = new Dimension(1, 1);
        return dim;
    }

    public void layoutContainer( Container parent) 
    {   System.out.println("layout "+this);
        if(expectedParent!=null) { expectedParent.doNullLayout(); }
    }
    public Dimension getPreferredSize(Container parent) { return(new Dimension(parent.getWidth(),parent.getHeight())); }

}

class ParentPanel extends Container implements NullLayoutProtocol
{
    public void doNullLayout() {
        setWidth(getParent().getWidth());
        setHeight(getParent().getHeight());
        for(int i=0;i<getComponentCount();i++)
        {
            Component c = getComponentAt(i);
            if(c instanceof NullLayoutProtocol)
            {
                ((NullLayoutProtocol)c).doNullLayout();
            }
        }}

}
class TestWindow extends Container implements NullLayoutProtocol
{
    public boolean laidout = false;
    public int paints = 0;
    public void doNullLayout()
        { 
          System.out.println("layout "+this);
          setWidth(getParent().getWidth());
          setHeight(getParent().getHeight());
          laidout = true; 
        }

    public void paint(Graphics g)
    {   int w = Math.max(500, getWidth());
        int h = Math.max(300, getHeight());
        g.setColor(0x808080);
        g.fillRect(0, 0, w, h);
        g.setColor(0x0);
        paints++;
        if(laidout)
        {
            g.drawString("Laid Out "+w+"x"+h+" :"+paints,0,h/2);
        }
        else
        {
            g.drawString("NOT LAID OUT "+w+"x"+h+" :"+paints,0,h/2);
        }
    }
}
public class Dtest  {

    private Form current;
    @SuppressWarnings("unused")
    private Resources theme;
    public void init(Object context) {
        theme = UIManager.initFirstTheme("/theme");
        // Pro only feature, uncomment if you have a pro subscription
        // Log.bindCrashProtection(true);
    }
    int loops = 0;
    TestWindow content = null;
    public void addContent(Container hi)
    {
        ParentPanel p = new ParentPanel();
        p.setLayout(new NullLayout(null)); 
        // set a default size so the display isn't blank.
        p.setWidth(500);
        p.setHeight(500);
        TestWindow w = content = new TestWindow();
        w.setLayout(new NullLayout(p));
        w.setVisible(true);
        // set a default size so the display isn't blank.
        w.setWidth(500);
        w.setHeight(500);
        hi.add(p);
        p.add(w);
        w.setVisible(true);

    }
    @SuppressWarnings("deprecation")
    public void start() {

        Runnable rr = new Runnable (){
            public void run() {

            if(current != null){
                    current.show();
                    return;
                }
                Form hi = current = new Form("test form"); 
                // adding the content here fixes the problem
                // addContent(hi);
                //
                // curiously, this doesn't help
                hi.setAllowEnableLayoutOnPaint(true);
                //
                //
                hi.show();

            System.out.println("running");
            while(true)
            {
            try {
            Thread.sleep(1000);
            if(content==null)
                {
                addContent(hi);
                }
            content.repaint();

            }

              catch (InterruptedException e) {};
                }}};
            new Thread(rr).start();

    }

    public void stop() {
        current = (Form)Display.getInstance().getCurrent();
    }

    public void destroy() {
    }

}
shannah commented 4 years ago

This test case doesn't run on the EDT. Can you modify it so that it runs on the EDT?

ddyer0 commented 4 years ago

It appears that if the "addContent()" step is run in edt, the layout occurs and there is no problem.