Hi all,
I'm doing a elevator simulation project but i met some issues.
First, I wish to align my buttons on the left to the horizontal lines. I tried to setting setMinimumSize, setMaximumSize, setPreferredSize but it didn't help.
Second, if I re-size the window, the buttons on the left seems unable to cope with the re-size. Is there anyway to make the button re-size together?
Third, simulation of the elevator works perfectly only when the moving interval, dy0 equals 1. When it's greater than 1, some floor fails.
Fourth, the elevator class background overshot the last horizontal line. I tried setting setSize for elevator class but if I were to resize the window, the background just overshot.
The codes:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
// The Main class
public class Elevator_Simulation extends JFrame {
// Declaration of variables
public JLabel state; // Display the state of the elevator
private JLabel id; // My name and group
public ButtonPanel control; // Button control panel
private Elevator elevator; // Elevator area
// Constructor
public Elevator_Simulation() {
// Create GUI
getContentPane().setLayout(new BorderLayout(0, 0));
// Display title
id = new JLabel("Name: Lim Xin Wei Group: SS2", JLabel.CENTER);
getContentPane().add(id, BorderLayout.NORTH);
// Display button panel
control = new ButtonPanel();
getContentPane().add(control, BorderLayout.WEST);
// Display elevator & lines
elevator = new Elevator(this);
getContentPane().add(elevator, BorderLayout.CENTER);
// Display dynamic text
state = new JLabel("The elevator is moving up", JLabel.CENTER);
getContentPane().add(state, BorderLayout.SOUTH);
}
// Main method
public static void main(String[] args) {
// Create a frame and display it
Elevator_Simulation frame = new Elevator_Simulation();
frame.setSize(400, 500);
frame.setLocationRelativeTo(null);
frame.setTitle("Elevator Simulation");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
} // The end of Elevator_Simulation class
// The ButtonPanel class receives and handles button pressing events
class ButtonPanel extends JPanel implements ActionListener {
// Declaration of variables
public JButton b[] = new JButton[8]; // 8 Buttons
public boolean bp[] = new boolean[8]; // State of each button, pressed or not
// Constructor
public ButtonPanel() {
// Create GUI
setLayout(new GridLayout(8, 1, 0, 0));
for (int i = 0; i < b.length; i++) {
b[i] = new JButton("F" + (b.length - i));
b[i].setBackground(Color.CYAN);
b[i].addActionListener(this);
bp[i] = false;
add(b[i]);
}
}
public void actionPerformed(ActionEvent e) {
// Handle the button pressing events
for (int i = 0; i < b.length; i++) {
if (e.getSource() == b[i]) {
b[i].setBackground(Color.RED);
bp[i] = true;
}
}
}
} // The end of ButtonPanel class
// The elevator class draws the elevator area and simulates elevator movement
class Elevator extends JPanel implements ActionListener {
// Declaration of variables
private Elevator_Simulation app; // Elevator Simulation frame
private boolean up; // Elevator is moving up or down
private boolean firstRun; // Elevator initial position flag
private int width; // Elevator's width
private int height; // Elevator's height
private int xco; // X coordinate of the elevator's upper left corner
private int yco; // Y coordinate of the elevator's upper left corner
private int dy0; // Moving interval
private int topy; // Y coordinate of the top level
private int bottomy; // Y coordinate of the bottom level
private Timer tm; // Timer to drive the elevator movement
final int MoveDelay = 40; // Time between moves
final int LoadTime = 99000; // Time to wait while loading
// Constructor
public Elevator(Elevator_Simulation app) {
// Initialization of variables
setBackground(Color.YELLOW);
this.app = app;
up = true;
firstRun = true;
dy0 = 3;
tm = new Timer(MoveDelay, this);
}
// Paint elevator area
public void paintComponent(Graphics g) {
// Obtain geometric values of components for drawing the elevator area
width = app.control.b[0].getWidth();
height = app.control.b[0].getHeight();
// Place elevator in middle
xco = (getWidth() - width) / 2;
if (firstRun) {
yco = getHeight() - height;
firstRun = false;
}
topy = 0;
// Resize the window will make bottomy value inaccruate
bottomy = this.getHeight() - height;
// Clear the painting canvas
super.paintComponent(g);
// Start the Timer if not started elsewhere
if (!tm.isRunning()) {
tm = new Timer(MoveDelay, this);
tm.setInitialDelay(1000);
tm.start();
}
// Draw horizontal lines
for (int i = 0; i <= 9; i++) {
g.setColor(Color.GRAY);
g.drawLine(0, height * i, getWidth(), height * i);
}
// Draw elevator
g.setColor(Color.LIGHT_GRAY);
g.fillRect(xco, yco, width, height);
// Draw vertical line striking through elevator
g.setColor(Color.DARK_GRAY);
g.drawLine(xco + (width / 2), yco, xco + (width / 2), (yco + height));
}
// Handle the timer events
public void actionPerformed(ActionEvent e) {
int current = (yco / height);
if (up) {
app.state.setText("The elevator is moving up");
yco -= dy0;
if (app.control.bp[current]) {
if ((yco + height) >= (height * current) && (yco + height) <= (height * (current + 1))) {
tm.stop();
app.control.bp[current] = false;
app.control.b[current].setBackground(Color.CYAN);
app.state.setText("The elevator is picking up passengers at floor " + (8 - current));
}
}
if (yco <= topy) {
up = false;
}
} else {
app.state.setText("The elevator is moving down");
yco += dy0;
if (app.control.bp[current]) {
if ((yco) >= (height * current) && (yco) <= (height * (current + 1))) {
tm.stop();
app.control.bp[current] = false;
app.control.b[current].setBackground(Color.CYAN);
app.state.setText("The elevator is picking up passengers at floor " + (8 - current));
}
}
if (yco >= bottomy) {
up = true;
}
}
// Repaint the panel
repaint();
}
} // The end of Elevator class
Guidance required ! Thanks in advanced
I did not have a problem with the first two issues.
Can you be more specific about the other two issues?
The value of dy0 is 3 in the posted code. What is different about how the posted code runs when you change dy0 to 1?
You need to try debugging the code by adding printlns to show the values of the controlling variables so you can see where your logic is wrong. If the y value for where the elevator stops doesn't align with the y value of the top of the elevator, you need to print out there values to see what the problem is.
Sorry, I think I fail to give a proper thought to my questions that I'm asking.
For the 1st and 2nd issue, the first button "F8" is slightly off align with the first line. If you re-size the window, it is possible to make the button align with the first line. I do not know if its my laptop issue, i do know that some people doesn't have my alignment issue.
Ignore the 3rd issue.
4th issue, my idea was that the lines are being drawn according to the height of the button on the left, thus the last line should be at the end of the panel. But when i setBackground(Color.YELLOW), it is obvious that the yellow overshot the last line. When you re-size the window, the yellow background just overshot even more.
5th issue, the vertical line draw at the middle of the elevator overshot the elevator area. I had to add "+ 1" at line 146 g.drawLine(xco + (width / 2), yco, xco + (width / 2), (yco + height) + 1) to remove the overshot. Can explain to me why is it so ?
6th issue, when the elevator is coming down example, from level 4 to level 3, when the elevator if halfway between level 4 n level 3, press the "F4" button, and the elevator stops.
My suggestion is to add printlns to display the values of the variables as they change to see why your logic is not working the way you want.
For the yellow to not extend past the bottom of the buttons on the left, try changing the layout manager so the buttons are in the same container with the yellow object so their bottoms are on the same horizontal line.
How about the alignment issue ? yours fit in perfectly ? is there any explanations to the off alignment I'm facing ?
The alignment issue i facing :

If i change the layout for the button , how do i make the button vertically place? actually i'm only allow to use what's has been taught to us, which is grid, flow, border. Grid layout is the best way to do it. is there other alternatives ?
just as @NormR1 suggested debug alighment to the FloorsLines by using System.out.println(someValue);
1/ still you have problem with TOP & BOTTOM, where elevator JUMP-OUT (2-3 pixels)
2/ same for each FLOOR
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
// The Main class, The ButtonPanel class receives and handles button pressing events
public class Elevator_Simulation extends JFrame {
private static final long serialVersionUID = 1L;// Declaration of variables
public JLabel state; // Display the state of the elevator
private JLabel id; // My name and group
public ButtonPanel control; // Button control panel
private Elevator elevator; // Elevator area
private JFrame frame = new JFrame();
public Elevator_Simulation() {// Constructor
id = new JLabel("Name: Lim Xin Wei Group: SS2", JLabel.CENTER); // Display title
control = new ButtonPanel(); // Display button panel
elevator = new Elevator(this);// Display elevator & lines
state = new JLabel("The elevator is moving up", JLabel.CENTER);// Display dynamic text
frame.setLayout(new BorderLayout(0, 0)); // Create GUI
frame.add(id, BorderLayout.NORTH);
frame.add(control, BorderLayout.WEST);
frame.add(elevator, BorderLayout.CENTER);
frame.add(state, BorderLayout.SOUTH);
frame.setLocationRelativeTo(null);
frame.setPreferredSize(new Dimension(400, 500));
frame.setTitle("Elevator Simulation");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {// Main method
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
Elevator_Simulation frame = new Elevator_Simulation();// Create a frame and display it
}
});
}
} // The end of Elevator_Simulation class
class ButtonPanel extends JPanel implements ActionListener {
private static final long serialVersionUID = 1L;// Declaration of variables
public JButton b[] = new JButton[8]; // 8 Buttons
public boolean bp[] = new boolean[8]; // State of each button, pressed or not
ButtonPanel() {// Constructor
setLayout(new GridLayout(8, 1)); // Create GUI
for (int i = 0; i < b.length; i++) {
b[i] = new JButton("F" + (b.length - i));
b[i].setBackground(Color.CYAN);
b[i].addActionListener(this);
bp[i] = false;
add(b[i]);
}
}
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < b.length; i++) { // Handle the button pressing events
if (e.getSource() == b[i]) {
b[i].setBackground(Color.RED);
bp[i] = true;
}
}
}
} // The end of ButtonPanel class
class Elevator extends JPanel implements ActionListener {// The elevator class draws the elevator area and simulates elevator movement
private static final long serialVersionUID = 1L; // Declaration of variables
private Elevator_Simulation app; // Elevator Simulation frame
private boolean up; // Elevator is moving up or down
private boolean firstRun; // Elevator initial position flag
private int width; // Elevator's width
private int height; // Elevator's height
private int xco; // X coordinate of the elevator's upper left corner
private int yco; // Y coordinate of the elevator's upper left corner
private int dy0; // Moving interval
private int topy; // Y coordinate of the top level
private int bottomy; // Y coordinate of the bottom level
private Timer tm; // Timer to drive the elevator movement
final int MoveDelay = 40; // Time between moves
final int LoadTime = 99000; // Time to wait while loading
Elevator(Elevator_Simulation app) { // Constructor
setBackground(Color.YELLOW); // Initialization of variables
this.app = app;
up = true;
firstRun = true;
dy0 = 3;
tm = new Timer(MoveDelay, this);
}
@Override
public void paintComponent(Graphics g) { // Paint elevator area
width = app.control.b[0].getWidth(); // Obtain geometric values of components for drawing the elevator area
height = app.control.b[0].getHeight();
xco = (getWidth() - width) / 2; // Place elevator in middle
if (firstRun) {
yco = getHeight() - height;
firstRun = false;
}
topy = 0;
bottomy = this.getHeight() - height; // Resize the window will make bottomy value inaccruate
super.paintComponent(g); // Clear the painting canvas
if (!tm.isRunning()) { // Start the Timer if not started elsewhere
tm = new Timer(MoveDelay, this);
tm.setInitialDelay(1000);
tm.start();
}
for (int i = 0; i <= 9; i++) { // Draw horizontal lines
g.setColor(Color.GRAY);
g.drawLine(0, height * i, getWidth(), height * i);
}
g.setColor(Color.LIGHT_GRAY);// Draw elevator
g.fillRect(xco, yco, width, height);
g.setColor(Color.DARK_GRAY); // Draw vertical line striking through elevator
g.drawLine(xco + (width / 2), yco, xco + (width / 2), (yco + height));
}
public void actionPerformed(ActionEvent e) {// Handle the timer events
int current = (yco / height);
if (up) {
app.state.setText("The elevator is moving up");
yco -= dy0;
if (app.control.bp[current]) {
if ((yco + height) >= (height * current) && (yco + height) <= (height * (current + 1))) {
tm.stop();
app.control.bp[current] = false;
app.control.b[current].setBackground(Color.CYAN);
app.state.setText("The elevator is picking up passengers at floor " + (8 - current));
}
}
if (yco <= topy) {
up = false;
}
} else {
app.state.setText("The elevator is moving down");
yco += dy0;
if (app.control.bp[current]) {
if ((yco) >= (height * current) && (yco) <= (height * (current + 1))) {
tm.stop();
app.control.bp[current] = false;
app.control.b[current].setBackground(Color.CYAN);
app.state.setText("The elevator is picking up passengers at floor " + (8 - current));
}
}
if (yco >= bottomy) {
up = true;
}
}
repaint(); // Repaint the panel
}
} // The end of Elevator classTo get data on the problem, print out the bounds of the elevator, control and the bottom button. The size of the elevator is not an even multiple of the size of a button.
Have you tried making the floors with the elevator separate components that correspond to the buttons instead of having it be one large component that you draw lines on?
The trick would be drawing the elevator over the top of the floors as it went from floor to floor. Don't know how to do that.
1st and 2nd issue has been resolved. I believe I fail to install my IDE correctly which cause this issue, I went to re-install and the alignment now went back to normal.
4th, I remove setBackground instead I use fillRect to draw my background and set to yellow. Now my last line and background is tie together, just that the buttons panel is 1 pixel shorter than my elevator panel.
I'm still working on the 5th and 6th issue.
I did printout the bounds of the components. the height is 53 and width is 47.
But i don't get it why the vertical line is 1 pixel longer than the elevator itself.
As for the algorithm for the elevator simulation, I still have no clue on solving the halfway stopping
i don't get what you meant.
the vertical line and elevator rectangle is drawn based on the size of the button, but now the vertical line is 1 pixel longer than the elevator rectangle.
unless there are codes disturbing the size, i don't see why the vertical line is not on par with the height of the elevator rectangle.