I want to set the component on the screen through the X and Y axis because we want to make a board game. Is there a way to set the control position using X and Y axes? Thanks
Yes, it's possible, but it's not a standard way to code with Codename One, as far as I know. Usually the position of a Component is decided by a Layout manager: manually setting x and y positions make sense for transition effects.
However, you can use a custom layout that allows you to manually choose the x and y position of a Component. For example:
import com.codename1.io.Log;
import com.codename1.ui.Component;
import com.codename1.ui.Container;
import com.codename1.ui.geom.Dimension;
import com.codename1.ui.layouts.Layout;
/**
* This is a special layout that keeps components in invalid positions with
* their preferred size: that means that a revalidate() will not change the
* position of components, that can be set using setX() and setY(); note that
* animateLayout() and animateUnlayout() will not work as expected. Example of
* usage: https://gist.github.com/jsfan3/4ccb8380e43db35f54bcd9960c6d8376
*
*
*/
public class InvalidLayout extends Layout {
private boolean fixedWidth = false;
private int maxWidth = 0;
private int maxHeight = 0;
/**
* The preferred size is calculated automatically, without a minimum width
* or a minimum height
*/
public InvalidLayout() {
}
/**
* The preferred size is fixed to the given values
*
* @param width
* @param height
*/
public InvalidLayout(int width, int height) {
this.fixedWidth = true;
this.maxWidth = width;
this.maxHeight = height;
}
@Override
public void layoutContainer(Container parent) {
for (Component current : parent) {
current.setSize(current.getPreferredSize());
}
}
@Override
public Dimension getPreferredSize(Container parent) {
if (!fixedWidth) {
for (Component current : parent) {
int x = current.getX() + current.getPreferredW();
if (maxWidth < x) {
maxWidth = x;
}
int y = current.getY() + current.getPreferredH();
if (maxHeight < y) {
maxHeight = y;
}
}
}
return new Dimension(maxWidth, maxHeight);
}
}
Example of usage. As you can see by trying the following code, asterisks are added in arbitrary x,y positions (in this case random), the FontImage icon is moved diagonally from top to bottom and the size of the container with InvalidLayout automatically adapts to the position of the elements it contains:
/**
* This code demonstrates that InvalidLayout allows to set its Components
* in the wanted position, that is kept after a revalidate()
*/
public void start() {
if (current != null) {
current.show();
return;
}
Form hi = new Form("Hi World", BoxLayout.y());
hi.add(FlowLayout.encloseCenter(new Label("Test")));
Container invalidCnt = new Container(new InvalidLayout());
Label test = new Label(FontImage.createMaterial(FontImage.MATERIAL_3D_ROTATION, "Button", 5));
invalidCnt.add(test);
hi.add(invalidCnt);
hi.add(FlowLayout.encloseCenter(new Label("Test")));
test.setX(0);
test.setY(0);
hi.show();
hi.revalidate();
UITimer.timer(500, true, () -> {
int max = 60;
int min = 0;
Random rand = new Random();
Label label = new Label("*");
invalidCnt.add(label);
label.setX(Display.getInstance().convertToPixels(rand.nextInt((max - min) + 1) + min));
label.setY(Display.getInstance().convertToPixels(rand.nextInt((max - min) + 1) + min));
test.setX(test.getX() + Display.getInstance().convertToPixels(2));
test.setY(test.getY() + Display.getInstance().convertToPixels(2));
hi.revalidate();
});
}
I hope this can help. However using a custom layout, like in this case, is unusual. Examples of board games made with Codename One are: https://github.com/codenameone/codenameone-demos/blob/master/Solitaire/src/com/codename1/apps/solitaire/Solitaire.java and https://github.com/codenameone/codenameone-demos/blob/master/CN1Poker/src/com/codename1/demo/poker/Poker.java