javagraphicscodenameone

Flipping (inverts) Y axis in a Codename One


Here's the code that inverts the y axis to draw from bottom to top (rather than top to bottom as usual).

import javax.swing.*;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;

public class InvertedYAxisSquare extends JPanel {

    public static void main(String[] args) {
        JFrame frame = new JFrame("Inverted Y-Axis Square");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new InvertedYAxisSquare());
        frame.setSize(400, 400);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g.create();
        g2d.setColor(Color.BLUE);
        AffineTransform at = new AffineTransform();
        at.scale(1, -1);
        at.translate(0, -getHeight());
        g2d.transform(at);
        g2d.fillRect(50, 0, 100, 111);
        g2d.dispose();
    }
}

Please provide similar code using transform and the codename one library. My attempts were not successful, e.g. this:

---------
@Override
public void paint(Graphics g) {
    super.paint(g);
    int height = getHeight();
    Transform t = Transform.makeIdentity();
    t.scale(1, -1);
    t.translate(0, -height);
    g.setTransform(t);
    g.setColor(0x0000ff);
    g.fillRect(50, 0, 100, 100);
    g.resetAffine();
}
--------

enter image description here

The square is somewhere higher than in the middle, and not at the very bottom, as it should be.


Solution

  • Something like this is what you want:

    final Form f = new Form(new BorderLayout());
            Component custom = new Component() {
                @Override
                public void paint(Graphics g) {
                    int height = getHeight();
                    Transform t = Transform.makeIdentity();
                    t.translate(getAbsoluteX(), height + getAbsoluteY());
                    t.scale(1, -1);
                    t.translate(-getAbsoluteX(), -getAbsoluteY());
                    g.setTransform(t);
                    g.setColor(0x0000ff);
                    g.fillRect(50, 0, 100, 111);
                    g.resetAffine();
                }
            };
            f.add(BorderLayout.CENTER, custom);
            f.show();
    

    Modified this answer after I saw that there was a problem with the original answer.

    The key is to first translate the component to the screen origin. Then scale it. Then translate it back.