I am building an app where at some point I use a form with a layeredLayout. In this form I already have 2 labels stacked on top of each other and I want to write a string in a specific area.
The first image (the deepest one) is an image from the device camera and the second image on top of the first one is a png file with transparent background. Both of them have a larger resolution than the screen resolution that's why I am using the following code to display them :
findPhotoBase3().getUnselectedStyle().setBackgroundType(Style.BACKGROUND_IMAGE_SCALED_FIT);
findDecoration3().getUnselectedStyle().setBackgroundType(Style.BACKGROUND_IMAGE_SCALED_FIT);
findPhotoBase3().getUnselectedStyle().setBgImage(montage.getBaseImage());
findDecoration3().getUnselectedStyle().setBgImage(montage.getdecorationImageSelected());
As the 2 images are scaled to fit screen size, in landscape mode both images do not cover the entire width (which is quite normal since the original image ratio is kept). Therefore there are blank columns on part of the stacked images.
I know that my string should start at xx % of the original image width (here decoration) and yy % of the original height. Consequently I first need to know where the (0, 0) point stands.
So if I add a new component to the parent form :
findDecoration3().getParent().add(new Component(){
@Override
public void paint(Graphics g) {
g.drawString(".", 0 , 0 );
}
}
then the point is drawn left of the stacked images and a bit lower than the images upper left corner. I have computed the x and y offsets like this :
int originalImageWidth = findPhotoBase3().getUnselectedStyle().getBgImage().getWidth();
int originalImageHeight = findPhotoBase3().getUnselectedStyle().getBgImage().getHeight();
float ratioOriginal = (float) originalImageWidth / originalImageHeight;
// L'espace disponible dans le containeur parent
int availableWidth = findPhotoBase3().getParent().getWidth();
int availableHeight = findPhotoBase3().getParent().getHeight();
// Landscaped mode assumed
final int displayedImageWidth = (int) (ratioOriginal * availableHeight) ;
final int displayedImageHeight = availableHeight ;
// L'image débute à (coordonnées par rapport au container parent see chapter 9.10 of https://www.codenameone.com/files/developer-guide.pdf )
final int imageStartX0 = (availableWidth - displayedImageWidth) / 2;
// L'image prend toute la hauteur, donc elle commence à 0 dans le container parent
final int imageStartY0 = 0;
However the 0 point (imageStartX/Y0) that is shown does not stand at the right location (ie exactly in the upper left corner of the photoBase image) but with positive offsets on both directions.
The point is drawn as previously shown :
g.drawString(".", imageStartX0 , imageStartY0 );
And here is the result I get (private photo used so only part of it is shown) :
Please note that on the picture a circled check button appears. This button is on container on top of the images. I did not mention it to keep my question as clear as possible.
Consequently if I can't get the 0 point right, there is no way I will be able to write my string at the expected location!
EDIT 1
So I tried to apply the piece of advice Shai gave and also to draw a rectangle around the image area like this :
@Override
public void paint(Graphics g) {
int color = 0xFF0000;
g.setColor(color);
g.drawRect(imageStartX0 + getX(), imageStartY0 + getY(), displayedImageWidth, displayedImageHeight); // This red rectangle is expected to be around the image just on its border
color = 0x0000ff;
g.setColor(color);
g.drawString(".", getX() ,getY() ); // This blue point is expected to be on the upper left corner of the parent container
}
What I get is the following picture . What strikes me is that the blue point does not seem to be exactly on the upper left corner of the parent container (I would say it should be further up). It looks like there is a translation on the Y-axis causing this offset. But applying the following does not make any difference :
g.drawString(".", getX() - g.getTranslateX() ,getY() - g.getTranslateY() );
What strikes me too is that the image starts "above" (north direction) from the blue point which is expected to be on the container's upper left corner. So is it possible that the child gets painted outside of its parent's container ? => see Edit 2 (it does not start above indeed).
On the other hand, it seems that my computation of the displayedImage dimensions has flaws since the rectangle is narrower than the image. Consequently I will have to compute it in a cleanlier fashion. => See Edit 2 (computation is OK but looks like parent container's dimensions have to be computed inside paint method).
EDIT 2
Reading again Shai's answer I tried to draw an rectangle (instead of writing a point character) :
g.fillRect(getX() - g.getTranslateX(), getY() - g.getTranslateY(), 5, 5);
g.drawRect(getX() - g.getTranslateX() ,getY() - g.getTranslateY(), 5, 5 );
And it worked as expected (the blue point being in the upper left corner) :
So this should be related to drawString's JavaDoc which states
The font is drawn from the top position and not the baseline.
and it explains why the point was not at the expected location (my bad!).
And to conclude although it is not clear to me, I could get the expected position just by moving part of the code (namely the part regarding the parent container dimensions) inside the paint method instead of outside. So my paint method now looks like :
@Override
public void paint(Graphics g) {
// L'espace disponible dans le containeur parent
// CAUTION : This has to be done in the paint method not outside
int availableWidth = getWidth();
int availableHeight = getHeight();
// On fait l'hypothèse du mode paysage
int displayedImageWidth = (int) (ratioOriginal * availableHeight) ;
int displayedImageHeight = availableHeight ;
// On récupère les coordonnées de l'image
// L'image débute à (coordonnées par rapport au container parent)
int imageStartX0 = (availableWidth - displayedImageWidth) / 2;
// L'image prend toute la hauteur, donc elle commence à 0 dans le container parent
int imageStartY0 = 0;
int colorNom = 0xFF0000;
g.setColor(colorNom);
g.drawRect(imageStartX0 + getX(), imageStartY0 + getY(), displayedImageWidth, displayedImageHeight);
colorNom = 0x0000ff;
g.setColor(colorNom);
g.drawString(nom, syntheStartX0 , syntheStartY0 - g.getTranslateY());
g.fillRect(getX() - g.getTranslateX(), getY() - g.getTranslateY(), 5, 5);
g.drawRect(getX() - g.getTranslateX() ,getY() - g.getTranslateY(), 5, 5 );
Thanks a lot to anybody that can tell me why I am not getting the expected result (ie the point exactly in the upper left corner) ?
Regards
Components in Codename One are positioned in the X/Y of their parent Container and aren't translated into location. So the 0, 0 position would be
getX(), getY()
.You can obviously use
translate
to make 0,0 work for you too.From the Codename One Developer Guide Graphics section