1

In the following program I'm putting some images in a panel and performing transformations on them relative to that panel. However, when the gui is first drawn it performs the initial paint operation relative to the coordinates of the window, rather than the panel. in addition to being in the wrong place, all images are stacked on top of each other. How do I avoid this? All subsequent repaints are correct but not the initial setting.

I've already tried repainting the panels in the main method after setting the window visible.

I'm attempting to jerry-rig a solution by creating a boolean flag that will change when the ActionListener is triggered. This will allow me to change the behaviour of the paintComponent() method when initially run and I can just use the window coordinate system, but this is incredibly inelegant and I suspect there is a better solution.

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.AffineTransform;
import java.awt.image.*;
import javax.swing.*;
public class GraphicsCreation extends JFrame {
  static int frame;
  static JPanel images;
  static final BufferedImage[] IMAGE = {Image.getImage(Image.imageArr1), Image.getImage(Image.imageArr2), Image.getImage(Image.imageArr3)};
  boolean built = false;
  public GraphicsCreation() {
    final int MAXFRAMES = 5;
    JPanel navBar = new JPanel();
    navBar.setLayout(new BorderLayout());
    JButton next = new JButton("NEXT >>");
    JLabel label = new JLabel(" ", SwingConstants.CENTER);
    frame = 1;
    ActionListener listener = new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        frame++;
        for (Component image : images.getComponents()) {
          image.repaint();
        }
      }
    };
    next.addActionListener(listener);
    images = new JPanel();
    images.setLayout(new GridLayout(0, 2));
    JPanel imagePanel1 = new ImagePanel(0);
    JPanel imagePanel2 = new ImagePanel(1);
    images.add(imagePanel1);
    images.add(imagePanel2);
    images.validate();
    this.setLayout(new BorderLayout());
    this.add(next, BorderLayout.NORTH);
    this.add(images, BorderLayout.CENTER);
  }

  public static void main(String args[]) {
    GraphicsCreation gc = new GraphicsCreation();
    gc.setMinimumSize(new Dimension(400, 300));
    gc.setLocationRelativeTo(null);
    gc.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    gc.setResizable(false);
    gc.setVisible(true);
  }

  class ImagePanel extends JPanel {

    AffineTransform currentTransform;
    int img;

    public ImagePanel(int img) {
      super();
      this.img = img;
    }

    @Override
    protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      Graphics2D g2 = (Graphics2D) g.create();
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
      g2.setPaint(Color.BLACK);
      g2.fillRect(0, 0, getWidth(), getHeight());
      //applyWindowToViewportTransformation(g2, -75, 75, -75, 75, true);
      double width = getWidth();
      double height = getHeight();
      switch (frame) {
        case 1:
          currentTransform = new AffineTransform();
          g2.setTransform(currentTransform);
          break;
        case 2:
          g2.setTransform(currentTransform);
          g2.translate((-5), 7);
          break;
        case 3:
          g2.setTransform(currentTransform);
          g2.rotate(Math.toRadians(-45), width / 2, height / 2);
          break;
        case 4:
          g2.setTransform(currentTransform);
          g2.rotate(Math.toRadians(90), width / 2, height / 2);
          break;
        case 5:
          g2.setTransform(currentTransform);
          g2.translate((width - width * 2) / 2, (height - height * 0.5) / 2);
          g2.scale(2, 0.5);
          break;
      }
      currentTransform = g2.getTransform();
      g2.translate(width / 2 - (IMAGE[img].getWidth() / 2), height / 2 - (IMAGE[img].getHeight() / 2));
      System.out.print(g2.getTransform().getTranslateX() + " ");
      System.out.println(g2.getTransform().getTranslateY());
      g2.drawImage(IMAGE[img], 0, 0, this);
    }

  }
}

How the program looks when initially run:

enter image description here

How the program SHOULD look when run:

enter image description here

The correct look can be reach by hitting the next button 5 times.

Here's the Image class if you want it, but it should only be relevant in creating a buffered image to work with.

import java.awt.Color;
import java.awt.image.BufferedImage;

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author Dylan Veraart
 */
public class Image {
    private static int bg = Color.WHITE.getRGB();
    private static int fg1 = Color.MAGENTA.getRGB();
    static String name1 = "Rectangle";
    static int[][] imageArr1 = {
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,fg1,fg1,fg1,fg1,fg1,fg1,fg1,fg1,fg1,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,fg1,fg1,fg1,fg1,fg1,fg1,fg1,fg1,fg1,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,fg1,fg1,fg1,fg1,fg1,fg1,fg1,fg1,fg1,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,fg1,fg1,fg1,fg1,fg1,fg1,fg1,fg1,fg1,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,fg1,fg1,fg1,fg1,fg1,fg1,fg1,fg1,fg1,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,fg1,fg1,fg1,fg1,fg1,fg1,fg1,fg1,fg1,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg}
    };
    private static int fg2=Color.BLACK.getRGB();
    static String name2 = "lowercaseF";
    static int[][] imageArr2 = {
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,fg2,fg2,fg2,fg2,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,fg2,fg2,fg2,fg2,fg2,fg2,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,fg2,fg2,fg2,fg2,fg2,fg2,fg2,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,fg2,fg2,fg2,fg2,bg,bg,fg2,fg2,fg2,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,fg2,fg2,fg2,bg,bg,bg,bg,fg2,fg2,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,fg2,fg2,fg2,bg,bg,bg,bg,fg2,fg2,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,fg2,fg2,fg2,bg,bg,bg,bg,fg2,fg2,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,fg2,fg2,fg2,bg,bg,bg,fg2,fg2,fg2,fg2,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,fg2,fg2,fg2,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,fg2,fg2,fg2,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,fg2,bg,fg2,fg2,fg2,bg,bg,fg2,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,fg2,fg2,fg2,fg2,fg2,fg2,fg2,fg2,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,fg2,fg2,fg2,fg2,fg2,fg2,fg2,fg2,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,fg2,fg2,fg2,fg2,fg2,fg2,fg2,fg2,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,fg2,bg,fg2,fg2,fg2,bg,bg,fg2,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,fg2,fg2,fg2,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,fg2,fg2,fg2,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,fg2,fg2,fg2,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,fg2,fg2,fg2,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,fg2,fg2,fg2,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,fg2,fg2,fg2,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,fg2,fg2,fg2,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,fg2,fg2,fg2,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,fg2,fg2,fg2,fg2,fg2,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg}
    };
    private static int fg3=Color.GREEN.getRGB();
    static String name3 = "circles";
    static int[][] imageArr3 = {
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,fg3,fg3,fg3,fg3,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,fg3,fg3,fg3,fg3,fg3,fg3,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,fg3,fg3,fg3,fg3,fg3,fg3,fg3,fg3,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,fg3,fg3,fg3,fg3,fg3,fg3,fg3,fg3,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,fg3,fg3,fg3,fg3,fg3,fg3,fg3,fg3,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,fg3,fg3,fg3,fg3,fg3,fg3,fg3,fg3,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,fg3,fg3,fg3,fg3,fg3,fg3,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,fg3,fg3,fg3,fg3,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,fg3,fg3,fg3,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,fg3,fg3,fg3,fg3,fg3,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,fg3,fg3,fg3,fg3,fg3,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,fg3,fg3,fg3,fg3,fg3,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,fg3,fg3,fg3,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg},
    {bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg,bg}
    };
    public static BufferedImage getImage(int[][] arr){
    BufferedImage image = new BufferedImage(25, 25, BufferedImage.TYPE_INT_RGB);
      for (int x = 0; x < 25; x++) {
           for (int y = 0; y < 25; y++) {
                image.setRGB(x, y, arr[y][x]);
            } // End for y.
      } // End for x.
        return image;
  }
}
c0der
  • 18,467
  • 6
  • 33
  • 65
  • This "might" be related to [this question](https://stackoverflow.com/questions/23507422/graphics-context-misaligned-on-first-paint) – MadProgrammer Mar 28 '19 at 00:40
  • If it is related, I don't have the slightest clue how. – Dylan Veraart Mar 28 '19 at 01:02
  • As you stated the *"when the gui is first drawn it performs the initial paint operation relative to the coordinates of the window, rather than the panel"* which is a similar issue I had, where the "origin" was not correct when using `AffineTransform` – MadProgrammer Mar 28 '19 at 01:05
  • I think it is indeed related. I sort of fixed the problem by initializing frame at 0 which skips the switch statement in paintComponent() during initialization. When the program runs, the first frame repeats twice but every frame is correct. I'm not really sure where the hell to go from there but...at least we've further diagnosed the problem here – Dylan Veraart Mar 28 '19 at 01:35
  • @DylanVeraart I did not dive into the solution linked by @MadProgrammer but I see that it uses `currentTransform = g2.getTransform();` instead of `currentTransform = new AffineTransform();` – c0der Mar 28 '19 at 06:40
  • That DOES give me the correct first frame, however it creates other problems. the transform that I pass on to new frames is incorrect as it's been adjusted to world coordinates. I've managed to fix it by implementing your suggestion and then in `case 2` of `paintComponent()` adding `currentTransform = new AffineTransform();`. Technically this goes outside my project specifications as it doesn't build on the previous frame but at this point as long as it looks right I'm 1000% done. Thanks for your help everyone. – Dylan Veraart Mar 29 '19 at 05:32

0 Answers0