Search code examples
javalinescalegraphics2dpaintcomponent

Graphics2D Scaling twice in PaintComponent()


Why does this code output two lines that are the same size?

import java.awt.*;
import javax.swing.*;


public class G2Scale extends JPanel{
    public static void main(String args[]) {
        G2Scale g = new G2Scale();
        g.setPreferredSize(new Dimension(200, 200));

        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setContentPane(g);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        Graphics2D g2 = (Graphics2D) g;

        g2.setColor(Color.BLUE);
        g2.scale(0.5, 1.0);
        g2.drawLine(5, 50, 100, 50);

        g2.setColor(Color.GREEN);
        g2.scale(1.0, 1.0);
        g2.drawLine(5, 100, 100, 100);

    }
}

I would expect these lines to be different sizes because they are scaled differently. From what I am seeing I am thinking that the scale is based off of the previous scale. Am I right about this?

If this is true, how would I get the second line to be scaled to what I thought it should be?

Thanks


Solution

  • All methods you call on a Graphics object that don't output something but instead change a property of it (like setColor, setFont, and so on), are stored in the context of the graphics object. Actually, you should think of a Graphics instance as a graphics context that contains and abstract all the information you need to draw into the screen.

    So basically, yes, your second scale is based on the first, since the first one changes the graphics context and the second one acts on top of it.

    There're two ways to change this behavior:

    1. Reset the state your Graphics instance by aplying the opposite of your first change (in this case, the inverse scalling).
    2. Make a copy of the Graphics object before applying any context change.

    I'm more inclined to the second option, but here're some examples of both:

    Graphics2D g2 = (Graphics2D) g;
    
    // resetting the context state
    g2.scale(0.5, 1.0);
    g2.drawLine(5, 50, 100, 50);
    g2.scale(2, 1.0);
    
    // using a copy of the context
    // note: casting is mandatory since 'create' returns a Graphics object
    Graphics2D g2copy = (Graphics2D)g2.create(); 
    g2copy.scale(1.0, 1.0);
    g2copy.drawLine(5, 100, 100, 100);
    
    // this one doesn't have any scale applied
    g2.drawLine(5, 150, 100, 150);