Search code examples
javaswinggraphics2d

Why wont squares show up after repaint()?


I posted this question a bit earlier and was told to make it SSCCE so here goes (if I can make any improvements feel free to let me know): I'm wondering why when my button "confirm" is clicked the old squares disappear and the redrawn squares do not appear on my GUI (made with swing). The Squares class draws 200 spaced out squares with an ID (0, 1, 2, or 3 as String) inside obtained from a different class (for the purpose of this question, let's assume it is always 0 and not include that class). For clarification: Squares draws everything perfectly the first time (also retrieves the correct IDs), but I want it to redraw everything once the button is clicked with new IDs. Code for Squares:

import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import java.util.ArrayList;

public class Squares extends JPanel{

private ArrayList<Rectangle> squares = new ArrayList<Rectangle>();
private String stringID = "0";

public void addSquare(int x, int y, int width, int height, int ID) {
      Rectangle rect = new Rectangle(x, y, width, height);
      squares.add(rect);
      stringID = Integer.toString(ID);
      if(ID == 0){
          stringID = "";
      }
}

   @Override
   protected void paintComponent(Graphics g) {

  super.paintComponent(g);
  Graphics2D g2 = (Graphics2D) g;
  FontMetrics fm = g2.getFontMetrics();
  int fontAscent = fm.getAscent();
  g2.setClip(new Rectangle(0,0,Integer.MAX_VALUE,Integer.MAX_VALUE));
  for (Rectangle rect : squares) {
     g2.drawString(stringID, rect.x + 7, rect.y + 2 + fontAscent);
     g2.draw(rect);
  }
 }
}

Code for GUI:

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

public class GUIReserver extends JFrame implements Runnable{

private int myID;
private JButton confirm = new JButton("Check Availability and Confirm Reservation");    
private JFrame GUI = new JFrame();
private Squares square; 

public GUIReserver(int i) {
    this.myID = i;
}

@Override
public void run() {
    int rows = 50;
    int seatsInRow = 4;
    confirm.addActionListener(new ActionListener() {
        @Override
         public void actionPerformed(ActionEvent evt) {
                GUI.getContentPane().remove(square);
                square = new Squares();
                int spaceNum = 0;
                int rowNum = 0;
                int offsetX = 200;
                int offsetY = 0;
                for(int i = 0; i < rows * seatsInRow; i++){
                    square.addSquare(rowNum * 31 + offsetX,spaceNum * 21 + 50 + offsetY,20,20, 0); //normally the 4th parameter here would retrieve the ID from the main class
                    rowNum++;
                    if(rowNum == 10){
                        rowNum = 0;
                        spaceNum++;
                    }
                    if(spaceNum == 2){
                        spaceNum = 3;
                        rowNum = 0;
                    }
                    if(spaceNum == 5){
                        spaceNum = 0;
                        offsetY += 140;
                    }
                }
                GUI.getContentPane().add(square); //this does not show up at all (could be that it wasn't drawn, could be that it is out of view etc...)
                GUI.repaint(); //the line in question
         }          
    });
    GUI.setLayout(new FlowLayout());
    GUI.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    GUI.setLocation(0,0);
    GUI.setExtendedState(JFrame.MAXIMIZED_BOTH);
    square = new Squares();
    int spaceNum = 0;
    int rowNum = 0;
    int offsetX = 200;
    int offsetY = 0;
    for(int i = 0; i < rows * seatsInRow; i++){
        square.addSquare(rowNum * 31 + offsetX,spaceNum * 21 + 50 + offsetY,20,20, 0); //normally the 4th parameter here would retrieve the ID from the main class
        rowNum++;
        if(rowNum == 10){
            rowNum = 0;
            spaceNum++;
        }
        if(spaceNum == 2){
            spaceNum = 3;
            rowNum = 0;
        }
        if(spaceNum == 5){
            spaceNum = 0;
            offsetY += 140;
        }
    }
    GUI.getContentPane().add(square); //this shows up the way I wish
    GUI.add(confirm);
    GUI.pack();
    GUI.setVisible(true);
}
}

Code for main:

public class AircraftSeatReservation {

static AircraftSeatReservation me = new AircraftSeatReservation();
private final int rows = 50;
private final int seatsInRow = 4;
private int seatsAvailable = rows * seatsInRow;
private Thread t3;

public static void main(String[] args) {
    GUIReserver GR1 = new GUIReserver(3);
    me.t3 = new Thread(GR1);
    me.t3.start();
}
}

Solution

  • One major problem: Your Squares JPanels preferred size is only 20 by 20, and will likely actually be that size since it seems to be added to a FlowLayout-using container. Next you seem to be drawing at locations that are well beyond the bounds of this component, and so the drawings likely will never be seen. Consider allowing your Squares objects to be larger, and make sure to only draw within the bounds of this component.

    Note also there is code that doesn't make sense, including:

    private int myID;
    private JTextField row, column, instru draft saved // ???
    package question2;ction1, instruction2, seatLabel, rowLabel; // ???
    

    I'm guessing that it's

    private int myID;
    private JTextField row, column, instruction1, instruction2, seatLabel, rowLabel;
    

    And this won't compile for us:

    int rows = AircraftSeatReservation.getRows();
    int seatsInRow = AircraftSeatReservation.getSeatsInRow(); // and shouldn't this take an int row parameter?
    

    since we don't have your AircraftSeatReservation class (hopefully you don't really have static methods in that class).

    And we can't compile or run your current code. We don't want to see your whole program, but rather you should condense your code into the smallest bit that still compiles, has no extra code that's not relevant to your problem, but still demonstrates your problem. So as Andrew Thompson recommends, for better help, please create and post your Minimal, Complete, and Verifiable example or Short, Self Contained, Correct Example.


    I would try to OOP-ify your problem as much as possible, to allow you to divide and conquer. This could involve:

    • Creating a SeatClass enum, one with possibly two elements, FIRST and COACH.
    • Creating a non-GUI Seat class, one with several fields including possibly: int row, char seat ( such as A, B, C, D, E, F), a SeatClass field to see if it is a first class seat or coach, and a boolean reserved field that is only true if the seat is reserved.
    • This class would also have a getId() method that returns a String concatenation of the row number and the seat char.
    • Creating a non-GUI Airplane class, one that holds two arrays of Seats, one for SeatClass.FIRST or first-class seats, and one for SeatClass.COACH.
    • It would also have a row count field and a seat count (column count) field.
    • After creating all these, then work on your GUI classes.
    • I'd create a GUI class for Seats, perhaps GuiSeat, have it contain a Seat object, perhaps have it extend JPanel, allow it to display its own id String that it gets from its contained Seat object, have it override getBackground(...) so that it's color will depend on whether the seat is reserved or not.
    • etc.....