I ported MigLayout for Lemur over night. Code included

Any ideas why this is happening when panel extends Node?

java.lang.ClassCastException: com.jme3.scene.Node cannot be cast to com.simsilica.lemur.Panel
	at mygame.MigLayout$LemurComponentWrapper.getParent(MigLayout.java:185)
	at net.miginfocom.layout.Grid.getParentSize(Unknown Source)
	at net.miginfocom.layout.Grid.resetLinkValues(Unknown Source)
	at net.miginfocom.layout.Grid.layoutImpl(Unknown Source)
	at net.miginfocom.layout.Grid.checkSizeCalcs(Unknown Source)
	at net.miginfocom.layout.Grid.layoutImpl(Unknown Source)
	at net.miginfocom.layout.Grid.layout(Unknown Source)
	at mygame.MigLayout.reshape(MigLayout.java:622)
	at com.simsilica.lemur.core.GuiControl.setSize(GuiControl.java:316)
	at com.simsilica.lemur.core.GuiControl.revalidate(GuiControl.java:417)
	at com.simsilica.lemur.core.GuiControl.controlUpdate(GuiControl.java:384)
	at com.jme3.scene.control.AbstractControl.update(AbstractControl.java:128)
	at com.jme3.scene.Spatial.runControlUpdate(Spatial.java:737)
	at com.jme3.scene.Spatial.updateLogicalState(Spatial.java:880)
	at com.jme3.scene.Node.updateLogicalState(Node.java:230)
	at com.jme3.scene.Node.updateLogicalState(Node.java:241)
	at com.jme3.app.SimpleApplication.update(SimpleApplication.java:243)
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:151)
	at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:193)
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:232)
	at java.lang.Thread.run(Thread.java:745)

How I implemented this is I have a lemur gradle project. I added MigLayout as a dependency.

I have a global library I created from the jars that are in the lemur project output folder. All the lemur stuff works fine on its own.

I copy and pasted the class you have at the top into my project and use the layout. Doesn’t work.

What version of jme are you guys using?

Im currently using Java 8

So what I did was first create a “root” Lemur Container node, then I added a second Lemur container node with the Miglayout and attach this second Lemur container node to the “root” node. When I attach the “root” to the guiNode I don’t get the java.lang.ClassCastException. Let me know if this helps.

When you say “attach” what do you mean?

You should show the code.

You can also just change the method,

                @Override
		public ContainerWrapper getParent()
		{
			return new LemurContainerWrapper((Panel)component.getParent());
		}

to

                @Override
		public ContainerWrapper getParent()
		{
			return new LemurContainerWrapper(component);
		}

because everything extends panel. Im not sure of the ramifications of doing it like that are though.

I’ve tested both ways and they both work.

He means add addChild.

But creating a root container for every individual lemur element seems overkill and im not sure why its like that.

Ok, I guess you can see his code. I always hate to assume because attachChild() doesn’t play will with containers.

Whats happening is without adding a root container, this method will try to cast the GuiNode to a panel,

                @Override
		public ContainerWrapper getParent()
		{
			return new LemurContainerWrapper((Panel) component.getParent());
		}

Edit:
Which means you have to always use a root container. Not sure why that’s needed though.

You got a point. I shoot from the hip a lot. Sorry for stepping on the question.

@themiddleman Can you please answer @pspeed question.

Sorry, here is the code that I use to add my gui elements:

//my "root" container that is the parent of the miglayout container
Container controlPanelRoot = new Container();
controlPanelRoot.setLocalTranslation(10,Starter.HEIGHT-350,7);
guiNode.attachChild(controlPanelRoot);
        
//This is the actual node where I add all the gui elements, as well as having the miglayout
Container buttonLayout = controlPanelRoot.addChild(new Container());

buttonLayout.setLayout(new MigLayout(""));

This works for me so far.

So what doesn’t work? What does the code look like that doesn’t work?

You understand that showing working code is only tangentially useful to debugging not-working code, right?

I thought this was in reference to the issue that @mitm was having regarding the java.lang.ClassCastException. Maybe I must’ve misread.

No, I think I’m the one who has misread.

 // Create a simple container for our elements
        Container myWindow = new Container();
        ((SimpleApplication) app).getGuiNode().attachChild(myWindow);
        myWindow.setLayout(new MigLayout(""));

The missing root container will cause the method in previous post to try to cast Gui Node to panel.

Adding a child to a root container and attaching root container to the Gui Node, works fine.

Removing the cast to Panel in the method call to getParent works fine but thats wrong since your looking for a parent.

Was trying to figure out why you have to add a parent container when all elements extend Panel.

In essence, if you have 10 separate Containers holding elements, using this layout makes you add 10 more root containers just to hold those containers…

I think you will have to wait until @zissis responds. I can’t really support this code as I’ve never looked at it and don’t know what constraints or assumptions were involved at the time.

Apologies all!!! I found this bug 3 weeks ago and forgot to post it … answer is I accidentally cast things to Panel … the root node is NOT a panel. The latest version is posted below … I will also update it at the top of this post ass well :slight_smile:

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;

import org.lwjgl.opengl.Display;

import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial.CullHint;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Checkbox;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.GuiGlobals;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.ListBox;
import com.simsilica.lemur.Panel;
import com.simsilica.lemur.ProgressBar;
import com.simsilica.lemur.Slider;
import com.simsilica.lemur.TabbedPanel;
import com.simsilica.lemur.TextField;
import com.simsilica.lemur.component.AbstractGuiComponent;
import com.simsilica.lemur.core.GuiControl;
import com.simsilica.lemur.core.GuiLayout;
import net.miginfocom.layout.AC;
import net.miginfocom.layout.CC;
import net.miginfocom.layout.ComponentWrapper;
import net.miginfocom.layout.ConstraintParser;
import net.miginfocom.layout.ContainerWrapper;
import net.miginfocom.layout.Grid;
import net.miginfocom.layout.LC;
import net.miginfocom.layout.LayoutUtil;
import net.miginfocom.layout.PlatformDefaults;

/**
 * @author Zissis Trabaris You have the right to freely use, modify, and
 *         redistribute this code for any purpose royalty free.
 */
public class MigLayout extends AbstractGuiComponent implements GuiLayout, Cloneable
{

	private static class LemurComponentWrapper implements net.miginfocom.layout.ComponentWrapper
	{

		private Node component;

		protected LemurComponentWrapper(Node component)
		{
			this.component = component;
		}

		@Override
		public Object getComponent()
		{
			return component;
		}

		@Override
		public final boolean equals(Object o)
		{
			if(o instanceof LemurComponentWrapper == false)
				return false;

			return component.equals(((LemurComponentWrapper) o).getComponent());
		}

		@Override
		public final int hashCode()
		{
			return component.hashCode();
		}

		@Override
		public int getX()
		{
			return (int) Math.floor(component.getLocalTranslation().x);
		}

		@Override
		public int getY()
		{
			return (int) Math.floor(component.getLocalTranslation().y * -1);
		}

		@Override
		public int getWidth()
		{
			return (int) component.getControl(GuiControl.class).getSize().x;
		}

		@Override
		public int getHeight()
		{
			return (int) component.getControl(GuiControl.class).getSize().y;
		}

		@Override
		public int getScreenLocationX()
		{
			return (int) GuiGlobals.getInstance().getScreenCoordinates(component, component.getLocalTranslation()).x;

		}

		@Override
		public int getScreenLocationY()
		{
			return (int) GuiGlobals.getInstance().getScreenCoordinates(component, component.getLocalTranslation()).y;
		}

		@Override
		public int getMinimumWidth(int hHint)
		{
			return getPreferredWidth(hHint);
		}

		@Override
		public int getMinimumHeight(int wHint)
		{
			return getPreferredHeight(wHint);
		}

		@Override
		public int getPreferredWidth(int hHint)
		{
			return (int) Math.ceil(component.getControl(GuiControl.class).getPreferredSize().x);
		}

		@Override
		public int getPreferredHeight(int wHint)
		{
			return (int) Math.ceil(component.getControl(GuiControl.class).getPreferredSize().y);
		}

		@Override
		public int getMaximumWidth(int hHint)
		{
			return Display.getWidth();
		}

		@Override
		public int getMaximumHeight(int wHint)
		{
			return Display.getHeight();
		}

		@Override
		public void setBounds(int x, int y, int width, int height)
		{
			component.setLocalTranslation(new Vector3f(x, y * -1, component.getLocalTranslation().z));
			Vector3f size = component.getControl(GuiControl.class).getPreferredSize().clone();
			size.set(width < 0 ? (width * -1) + size.getX() : width, height < 0 ? (height * -1) + size.getY() : height, size.z);
			component.getControl(GuiControl.class).setSize(size);

		}

		@Override
		public boolean isVisible()
		{
			return component.getCullHint() != CullHint.Always;
			// return true;
		}

		@Override
		public int getBaseline(int width, int height)
		{

			return -1;
		}

		@Override
		public boolean hasBaseline()
		{
			return false;
		}

		@Override
		public ContainerWrapper getParent()
		{
			return new LemurContainerWrapper(component.getParent());
		}

		@Override
		public float getPixelUnitFactor(boolean isHor)
		{
			return 1;
		}

		@Override
		public int getHorizontalScreenDPI()
		{
			return PlatformDefaults.getDefaultDPI();
		}

		@Override
		public int getVerticalScreenDPI()
		{
			return PlatformDefaults.getDefaultDPI();
		}

		@Override
		public int getScreenWidth()
		{
			return GuiGlobals.getInstance().getCollisionViewPort(component).getCamera().getWidth();
		}

		@Override
		public int getScreenHeight()
		{
			return GuiGlobals.getInstance().getCollisionViewPort(component).getCamera().getHeight();
		}

		@Override
		public String getLinkId()
		{

			return component.getName();
		}

		@Override
		public int getLayoutHashCode()
		{

			int hash = getWidth() + (getHeight() << 5);

			Vector3f size = component.getLocalTranslation();
			hash += (((int) size.x) << 10) + (((int) size.y) << 15);

			if(isVisible())
				hash += 1324511;

			String id = getLinkId();
			if(id != null)
				hash += id.hashCode();

			return hash;
		}

		@Override
		public int[] getVisualPadding()
		{
			return null;
		}

		@Override
		public void paintDebugOutline(boolean showVisualPadding)
		{

		}

		private int compType = TYPE_UNSET;

		@Override
		public int getComponentType(boolean disregardScrollPane)
		{
			if(compType == TYPE_UNSET)
				compType = checkType(disregardScrollPane);

			return compType;
		}

		private int checkType(boolean disregardScrollPane)
		{
			Node c = component;

			if(c instanceof TextField)
			{
				return TYPE_TEXT_FIELD;
			} else if(c instanceof Checkbox)
			{
				return TYPE_CHECK_BOX;
			} else if(c instanceof Button)
			{
				return TYPE_BUTTON;
			} else if(c instanceof Label)
			{
				return TYPE_LABEL;
			} else if(c instanceof ListBox)
			{
				return TYPE_LIST;
			} else if(c instanceof ProgressBar)
			{
				return TYPE_PROGRESS_BAR;
			} else if(c instanceof Slider)
			{
				return TYPE_SCROLL_BAR;
			} else if(c instanceof TabbedPanel)
			{
				return TYPE_TABBED_PANE;
			} else if(c instanceof Container)
			{
				return TYPE_CONTAINER;
			} else if(c instanceof Panel)
			{
				return TYPE_PANEL;
			}
			return TYPE_UNKNOWN;
		}

		@Override
		public int getContentBias()
		{
			return LayoutUtil.HORIZONTAL;
		}

	}

	private static class LemurContainerWrapper extends LemurComponentWrapper implements ContainerWrapper
	{

		protected LemurContainerWrapper(Node component)
		{
			super(component);

		}

		@Override
		public ComponentWrapper[] getComponents()
		{
			Container c = (Container) getComponent();
			Node[] children = c.getLayout().getChildren().toArray(new Node[0]);
			LemurComponentWrapper[] lcw = new LemurComponentWrapper[children.length];
			for(int i = 0; i < lcw.length; i++)
				lcw[i] = new LemurComponentWrapper((Panel) children[i]);
			return lcw;
		}

		@Override
		public int getComponentCount()
		{
			Container c = (Container) getComponent();
			return c.getLayout().getChildren().size();
		}

		@Override
		public Object getLayout()
		{
			return ((Container) getComponent()).getLayout();
		}

		@Override
		public boolean isLeftToRight()
		{
			return true;
		}

		@Override
		public void paintDebugCell(int x, int y, int width, int height)
		{

		}

	}

	private transient LC lc = null;

	private AC colSpecs = null, rowSpecs = null;

	private Grid grid = null;

	private final Map<LemurComponentWrapper, CC> ccMap = new HashMap<LemurComponentWrapper, CC>(8);

	/**
	 * The component to string constraints mappings.
	 */
	private final Map<Panel, Object> scrConstrMap = new IdentityHashMap<Panel, Object>(8);

	/**
	 * Hold the serializable text representation of the constraints.
	 */
	private Object layoutConstraints = "", colConstraints = "", rowConstraints = ""; // Should
																						// never
																						// be
																						// null!

	private GuiControl parent;

	private List<Node> children = new ArrayList<Node>();

	private LemurContainerWrapper containerWrapper = null;

	/**
	 * Constructor.
	 * 
	 * @param layoutConstraints
	 *            The constraints that concern the whole layout.
	 *            <code>null</code> will be treated as "".
	 */
	public MigLayout(String layoutConstraints)
	{
		this(layoutConstraints, "", "");
	}

	/**
	 * Constructor.
	 * 
	 * @param layoutConstraints
	 *            The constraints that concern the whole layout.
	 *            <code>null</code> will be treated as "".
	 * @param colConstraints
	 *            The constraints for the columns in the grid. <code>null</code>
	 *            will be treated as "".
	 */
	public MigLayout(String layoutConstraints, String colConstraints)
	{
		this(layoutConstraints, colConstraints, "");
	}

	/**
	 * Constructor.
	 * 
	 * @param layoutConstraints
	 *            The constraints that concern the whole layout.
	 *            <code>null</code> will be treated as "".
	 * @param colConstraints
	 *            The constraints for the columns in the grid. <code>null</code>
	 *            will be treated as "".
	 * @param rowConstraints
	 *            The constraints for the rows in the grid. <code>null</code>
	 *            will be treated as "".
	 */
	public MigLayout(String layoutConstraints, String colConstraints, String rowConstraints)
	{
		setLayoutConstraints(layoutConstraints);
		setColumnConstraints(colConstraints);
		setRowConstraints(rowConstraints);
	}

	/**
	 * Sets the layout constraints for the layout manager instance as a String.
	 * <p>
	 * See the class JavaDocs for information on how this string is formatted.
	 * 
	 * @param constr
	 *            The layout constraints as a String or
	 *            {@link net.miginfocom.layout.LC} representation.
	 *            <code>null</code> is converted to <code>""</code> for storage.
	 * @throws RuntimeException
	 *             if the constraint was not valid.
	 */
	public void setLayoutConstraints(Object constr)
	{
		if(constr == null || constr instanceof String)
		{
			constr = ConstraintParser.prepare((String) constr);
			lc = ConstraintParser.parseLayoutConstraint((String) constr);
		} else if(constr instanceof LC)
		{
			lc = (LC) constr;
		} else
		{
			throw new IllegalArgumentException("Illegal constraint type: " + constr.getClass().toString());
		}
		layoutConstraints = constr;
		invalidate();
	}

	/**
	 * Returns layout constraints either as a <code>String</code> or
	 * {@link net.miginfocom.layout.LC} depending what was sent in to the
	 * constructor or set with {@link #setLayoutConstraints(Object)}.
	 * 
	 * @return The layout constraints either as a <code>String</code> or
	 *         {@link net.miginfocom.layout.LC} depending what was sent in to
	 *         the constructor or set with
	 *         {@link #setLayoutConstraints(Object)}. Never <code>null</code>.
	 */
	public Object getLayoutConstraints()
	{
		return layoutConstraints;
	}

	/**
	 * Returns the column layout constraints either as a <code>String</code> or
	 * {@link net.miginfocom.layout.AC}.
	 * 
	 * @return The column constraints either as a <code>String</code> or
	 *         {@link net.miginfocom.layout.AC} depending what was sent in to
	 *         the constructor or set with
	 *         {@link #setColumnConstraints(Object)}. Never <code>null</code>.
	 */
	public Object getColumnConstraints()
	{
		return colConstraints;
	}

	/**
	 * Sets the column layout constraints for the layout manager instance as a
	 * String.
	 * <p>
	 * See the class JavaDocs for information on how this string is formatted.
	 * 
	 * @param constr
	 *            The column layout constraints as a String or
	 *            {@link net.miginfocom.layout.AC} representation.
	 *            <code>null</code> is converted to <code>""</code> for storage.
	 * @throws RuntimeException
	 *             if the constraint was not valid.
	 */
	public void setColumnConstraints(Object constr)
	{
		if(constr == null || constr instanceof String)
		{
			constr = ConstraintParser.prepare((String) constr);
			colSpecs = ConstraintParser.parseColumnConstraints((String) constr);
		} else if(constr instanceof AC)
		{
			colSpecs = (AC) constr;
		} else
		{
			throw new IllegalArgumentException("Illegal constraint type: " + constr.getClass().toString());
		}
		colConstraints = constr;
		invalidate();
	}

	/**
	 * Returns the row layout constraints either as a <code>String</code> or
	 * {@link net.miginfocom.layout.AC}.
	 * 
	 * @return The row constraints either as a <code>String</code> or
	 *         {@link net.miginfocom.layout.AC} depending what was sent in to
	 *         the constructor or set with {@link #setRowConstraints(Object)}.
	 *         Never <code>null</code>.
	 */
	public Object getRowConstraints()
	{
		return rowConstraints;
	}

	/**
	 * Sets the row layout constraints for the layout manager instance as a
	 * String.
	 * <p>
	 * See the class JavaDocs for information on how this string is formatted.
	 * 
	 * @param constr
	 *            The row layout constraints as a String or
	 *            {@link net.miginfocom.layout.AC} representation.
	 *            <code>null</code> is converted to <code>""</code> for storage.
	 * @throws RuntimeException
	 *             if the constraint was not valid.
	 */
	public void setRowConstraints(Object constr)
	{
		if(constr == null || constr instanceof String)
		{
			constr = ConstraintParser.prepare((String) constr);
			rowSpecs = ConstraintParser.parseRowConstraints((String) constr);
		} else if(constr instanceof AC)
		{
			rowSpecs = (AC) constr;
		} else
		{
			throw new IllegalArgumentException("Illegal constraint type: " + constr.getClass().toString());
		}
		rowConstraints = constr;
		invalidate();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.simsilica.lemur.core.GuiComponent#calculatePreferredSize(com.jme3.
	 * math.Vector3f)
	 */
	@Override
	public void calculatePreferredSize(Vector3f size)
	{
		if(parent == null)
			return;

		Grid grid = new Grid(containerWrapper, lc, rowSpecs, colSpecs, ccMap, null);
		int[] b = new int[]
		{ 0, 0, (int) parent.getSize().x, (int) parent.getSize().y };

		if(grid.layout(b, lc.getAlignX(), lc.getAlignY(), false))
		{
			grid = new Grid(containerWrapper, lc, rowSpecs, colSpecs, ccMap, null);
			grid.layout(b, lc.getAlignX(), lc.getAlignY(), false);
		}
		int w = LayoutUtil.getSizeSafe(grid.getWidth(), LayoutUtil.PREF);
		int h = LayoutUtil.getSizeSafe(grid.getHeight(), LayoutUtil.PREF);
		size.set(w, h, parent.getSize().z);

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.simsilica.lemur.core.GuiComponent#reshape(com.jme3.math.Vector3f,
	 * com.jme3.math.Vector3f)
	 */
	@Override
	public void reshape(Vector3f pos, Vector3f size)
	{
		if(parent == null)
			return;
		// for(Node n: children)
		// n.getControl(GuiControl.class).getPreferredSize();

		int[] b = new int[]
		{ (int) Math.floor(pos.x), (int) Math.floor(pos.y * -1), (int) Math.ceil(size.x), (int) Math.ceil(size.y) };
		Grid grid = new Grid(containerWrapper, lc, rowSpecs, colSpecs, ccMap, null);
		if(grid.layout(b, lc.getAlignX(), lc.getAlignY(), false))
		{
			grid = new Grid(containerWrapper, lc, rowSpecs, colSpecs, ccMap, null);
			grid.layout(b, lc.getAlignX(), lc.getAlignY(), false);
		}
		for(Node n : children)
			n.setLocalTranslation(n.getLocalTranslation().clone().setZ(pos.z));
		// parent.getNode().setLocalTranslation(pos);

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.simsilica.lemur.core.GuiLayout#addChild(com.jme3.scene.Node,
	 * java.lang.Object[])
	 */
	@Override
	public <T extends Node> T addChild(T n, Object... constraints)
	{
		if(n.getControl(GuiControl.class) == null)
			throw new IllegalArgumentException("Child is not GUI element.");
		LemurComponentWrapper componentWrapper = new LemurComponentWrapper((Panel) n);
		String constraintString = constraints.length > 0 && constraints[0] instanceof String ? (String) constraints[0] : null;
		String cStr = ConstraintParser.prepare(constraintString);

		scrConstrMap.put((Panel) n, constraintString);
		ccMap.put(componentWrapper, ConstraintParser.parseComponentConstraint(cStr));

		children.add(n);

		if(parent != null)
		{
			// We are attached
			parent.getNode().attachChild(n);
		}

		invalidate();
		return n;

	}

	@Override
	protected void invalidate()
	{
		if(parent != null)
		{
			parent.invalidate();
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.simsilica.lemur.core.GuiLayout#removeChild(com.jme3.scene.Node)
	 */
	@Override
	public void removeChild(Node n)
	{
		scrConstrMap.remove(n);
		ccMap.remove(new LemurComponentWrapper((Panel) n));
		grid = null; // To clear references

		if(children.remove(n))
			if(parent != null)
			{
				parent.getNode().detachChild(n);
			}
		invalidate();

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.simsilica.lemur.core.GuiLayout#getChildren()
	 */
	@Override
	public Collection<Node> getChildren()
	{
		return Collections.unmodifiableList(children);
	}

	@Override
	public void attach(GuiControl parent)
	{
		this.parent = parent;
		this.containerWrapper = new LemurContainerWrapper((Panel) parent.getNode());
		Node self = parent.getNode();
		for(Node n : children)
		{
			self.attachChild(n);
		}
	}

	@Override
	public void detach(GuiControl parent)
	{
		this.parent = null;
		this.containerWrapper = null;
		// Have to make a copy to avoid concurrent mod exceptions
		// now that the containers are smart enough to call remove
		// when detachChild() is called. A small side-effect.
		// Possibly a better way to do this? Disable loop-back removal
		// somehow?
		Collection<Node> copy = new ArrayList<Node>(children);
		for(Node n : copy)
		{
			n.removeFromParent();
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.simsilica.lemur.core.GuiLayout#clearChildren()
	 */
	@Override
	public void clearChildren()
	{

		for(Node n : children.toArray(new Node[children.size()]))
			removeChild(n);
		invalidate();

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.simsilica.lemur.core.GuiLayout#clone()
	 */
	@Override
	public GuiLayout clone()
	{
		// TODO Auto-generated method stub
		return null;
	}

}

Nope … with the updated code a mig layout container can hold another mig layout container … and so on without extra containers. I fixed the bug in the code and posted it above this comment

Seem to have found a small issue using MigLayout with hidemode when using the Lemur method:

xxx.setOutputTransform(TextFilters.constantTransform('*'));

If you use this method with the TextFilters.constantTransform on TextField (password also since it uses this) and then set the component cull hint to CullHint.Always, thereby utilizing this MigLayout argument, when you make the component visible again, you will be blocked from entering text into the textField unless you call getFocus() to do so. Mouse events no longer work in other words.

Does not happen if I use Lemurs SpringGridLayout. Mouse events always work.

Edit:
Wrap the TextField in a container using SpringGridLayout and add that container to the container using MigLayout to remedy. You can then just add/remove the textfields to the parent container.