Stuck on Design - java

I have a small GUI java program I'm working on but designing how the pieces should work together is frustrating me. Basically what I need to do is draw a "car" on a panel and attach that panel to a frame. Then animate the panel to give the illusion of movement.
My problem is that I don't understand how to move the code that does the animation to its own class. When I started working on this I made the UI elements first. Then I came across the Timer class and used that class in what was supposed to be just a UI element class (CarBody). The way my code works now is that as soon as I run the program the "car" starts moving because I don't have it set up to be triggered by a button press. I don't understand how to move the animation code to its on class and trigger it with a button press.
I could solve this in two seconds IF I could call repaint() in the performAction() method. The problem is I can't do that! It wont compile that way.
What I have done is
class CarBody extends JPanel {
private int xCoordinate = 0;
CarBody(){
Timer timer = new Timer(1000,new TimerListener());
timer.start();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
//g.fillRect(10, 10, 60, 50);
if(xCoordinate > getWidth()){
xCoordinate = -20;
}
xCoordinate +=100;
g.fillRect(xCoordinate,10,60,50);
}
class TimerListener implements ActionListener{
public void actionPerformed(ActionEvent e){
repaint();
}
}
}

I could solve this in two seconds IF I could call repaint() in the performAction() method.
You should not be changing the car coordinates in the paintComponent() method. You should have a method that sets the coordinates and then repaints the car.
When you create the ActionListener class then pass in the panel you want to repaint as a parameter to the class. Then you can invoke the "changeLocation" method which will update the location of the car and then invoke repaint() on itself.
For another approach you can add an Icon to a label and just change the location of the label and it will repaint itself automatically. Here is a simple example:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TimerAnimation extends JLabel implements ActionListener
{
int deltaX = 2;
int deltaY = 3;
int directionX = 1;
int directionY = 1;
public TimerAnimation(
int startX, int startY,
int deltaX, int deltaY,
int directionX, int directionY,
int delay)
{
this.deltaX = deltaX;
this.deltaY = deltaY;
this.directionX = directionX;
this.directionY = directionY;
setIcon( new ImageIcon("dukewavered.gif") );
// setIcon( new ImageIcon("copy16.gif") );
setSize( getPreferredSize() );
setLocation(startX, startY);
new javax.swing.Timer(delay, this).start();
}
public void actionPerformed(ActionEvent e)
{
Container parent = getParent();
// Determine next X position
int nextX = getLocation().x + (deltaX * directionX);
if (nextX < 0)
{
nextX = 0;
directionX *= -1;
}
if ( nextX + getSize().width > parent.getSize().width)
{
nextX = parent.getSize().width - getSize().width;
directionX *= -1;
}
// Determine next Y position
int nextY = getLocation().y + (deltaY * directionY);
if (nextY < 0)
{
nextY = 0;
directionY *= -1;
}
if ( nextY + getSize().height > parent.getSize().height)
{
nextY = parent.getSize().height - getSize().height;
directionY *= -1;
}
// Move the label
setLocation(nextX, nextY);
}
public static void main(String[] args)
{
JPanel panel = new JPanel();
JFrame frame = new JFrame();
frame.setContentPane(panel);
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.getContentPane().setLayout(null);
// frame.getContentPane().add( new TimerAnimation(10, 10, 2, 3, 1, 1, 10) );
frame.getContentPane().add( new TimerAnimation(300, 100, 3, 2, -1, 1, 20) );
// frame.getContentPane().add( new TimerAnimation(0, 000, 5, 0, 1, 1, 20) );
frame.getContentPane().add( new TimerAnimation(0, 200, 5, 0, 1, 1, 80) );
frame.setSize(400, 400);
frame.setLocationRelativeTo( null );
frame.setVisible(true);
// frame.getContentPane().add( new TimerAnimation(10, 10, 2, 3, 1, 1, 10) );
// frame.getContentPane().add( new TimerAnimation(10, 10, 3, 0, 1, 1, 10) );
}
}
This example, doesn't do custom painting and the animation is done by invoking the setlocation(...) method on the label which will cause a repaint() so the solution is slightly different than yours, but the key point is NOT to change the location values in the paintComponent() method.

Related

How to prevent my KeyEvent from repainting both objects?

I am working on a simple game which requires 1 player (the square) and some enemies that spawn randomly inside the play-area. I am running into an issue currently, because when I run my program, pressing any arrow key will repaint not only the player's new location, but it will also re-spawn all the enemies into the new locations.
I have gone through my code a few times and I am still stumped as to why this is happening. Any help would be greatly appreciated.
P.S. I am not a very experienced programmer, so some of this code may not be as efficient as possible and some things may be incorrect; feel free to point out any errors besides the issue at hand. Thanks!
Main Class
public class Eat {
public static void main(String[] args) {
// Creating the main frame
JFrame main = new JFrame("Eat 'Em All - Version 1.0.2");
main.setSize(497, 599);
main.setLocationRelativeTo(null);
main.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
main.setResizable(false);
// Colours and borders
Border areaBorder = new LineBorder(Color.LIGHT_GRAY, 3);
// Creating main JPanel
JPanel area = new JPanel();
area.setLayout(new BoxLayout(area, BoxLayout.PAGE_AXIS));
area.setBackground(Color.WHITE);
main.setContentPane(area);
// Creating the drawing/image/player
DrawPlayer player = new DrawPlayer();
player.setPreferredSize(new Dimension(497, 539));
player.setOpaque(false);
// Enemies
DrawEnemy enemy = new DrawEnemy();
enemy.setPreferredSize(new Dimension(497, 539));
enemy.setBackground(Color.WHITE);
// Creating the control panel for buttons, etc
JPanel control = new JPanel();
control.setPreferredSize(new Dimension(497, 60));
control.setLayout(new GridLayout(1, 2, 0, 0));
control.setBorder(areaBorder);
JLabel welcome = new JLabel(" Welcome to Eat 'Em All |--| Press 'Start'");
JButton start = new JButton("Start");
// Adding it all to the frame
main.add(enemy);
enemy.add(player);
control.add(welcome);
control.add(start);
area.add(control);
// Adding keylistener and making button false
player.addKeyListener(player);
player.setFocusable(true);
start.setFocusable(false);
enemy.setFocusable(false);
// Bring frame to front and visible
main.toFront();
main.setVisible(true);
System.out.println(player.getWidth() / 2);
System.out.println(player.getHeight() / 2);
}
}
Drawing Player Class
public class DrawPlayer extends JPanel implements KeyListener {
long xPosition = 0;
long yPosition = 0;
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Making loop to get points and move it
// Center of area is x: 245 y: 255
int xPoints[] = {235, 255, 255, 235, 235, 255};
int yPoints[] = {265, 265, 245, 245, 265, 245};
for (int i = 0; i < xPoints.length; i++) {
xPoints[i] += xPosition;
yPoints[i] += yPosition;
}
g.setColor(Color.BLUE);
g.drawPolygon(xPoints, yPoints, xPoints.length);
}
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_DOWN:
if (yPosition == 245) {
yPosition -= 5;
} else {
yPosition += 5;
}
break;
case KeyEvent.VK_UP:
if (yPosition == -245) {
yPosition += 5;
} else {
yPosition -= 5;
}
break;
case KeyEvent.VK_LEFT:
if (xPosition == -235) {
xPosition += 5;
} else {
xPosition -= 5;
}
break;
case KeyEvent.VK_RIGHT:
if (xPosition == 235) {
xPosition -= 5;
} else {
xPosition += 5;
}
break;
}
repaint();
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
}
}
Drawing Enemies Class
public class DrawEnemy extends JPanel {
public void paintComponent(Graphics f) {
super.paintComponent(f);
for (int i = 0; i < 10; i++ ){
f.setColor(Color.RED);
f.drawOval((int)(Math.random() * ((440 - 0) + 0) + 0), (int)(Math.random() * ((500 - 0) + 0) + 0), 50, 50);
}
}
}
Your have a problem here:
public void paintComponent(Graphics f) {
super.paintComponent(f);
for (int i = 0; i < 10; i++ ){
f.setColor(Color.RED);
f.drawOval((int)(Math.random() * ((440 - 0) + 0) + 0), (int)(Math.random() * ((500 - 0) + 0) + 0), 50, 50);
}
}
You've got program logic inside of a painting method, something you should never do, since you never have full control over when or even if a painting method will be called. The solution, get the randomization out of the paintComponent method and into its own separate method, one that you call if and only if you want to randomize the enemies, and not every time you repaint.
Other issues:
Separate your program logic from your GUI.
For instance you should have a non-GUI Enemy class, one that has fields for its own position, its size, its movement, perhaps a move() method, perhaps a collision(Player p) method.
You should have only one JPanel that does drawing and this should be its only job.
Again, you don't tie movement of anything to the painting method.
You would want a game loop of some sort, perhaps a Swing Timer. This will generate regularly spaced ticks that will prod Enemies and Players to move.
Get rid of KeyListener code and favor Key Bindings. The latter is much less kludgy when it comes to component focus. Do check the tutorial for this.

Mini Tennis Game using Threads Java

I am having a some difficulty with developing of my code. Since I am not too advanced with Java I need some help. I am trying to develop Mini Tennis game using Threads. The aim of this game is to catch the balls moving on the window with the paddle that can be controlled with the left and right buttons on the keyboard.
Those balls should move diagonally on the window and when they touch to any of the corner (out of bottom) they should change their ways like light reflection. Apart from this, when a ball touches to one of the obstacles they should change their ways as well.
Paddle on the bottom of the window can be controlled with left and right keys.The task of the player is to catch the balls. The number of balls that the user catches will be shown on the Score part with the total number of balls going to the bottom corner.
User may need to save the state of the game. When the user clicks to the “save game” button; ball locations and score should save to the file. And when the user clicks to the open button, the state of game should be reloaded.
My source code files are:
public class BallPanel extends JPanel implements Runnable {
int RED, GREEN, BLUE;
int Xdirection = 1, Ydirection = 1;
boolean pleaseWait = false;
BallPanel(int X, int Y){
locateBall(X, Y, 30, 30);
/* Random r = new Random();
RED = r.nextInt(255);
GREEN = r.nextInt(255);
BLUE = r.nextInt(255);
*/
}
public void paint(Graphics g){
int panelWidth = this.getWidth();
int panelHeight = this.getHeight();
// g.setColor( new Color(RED, GREEN, BLUE ));
g.setColor(Color.ORANGE);
g.fillOval(panelWidth/2, panelHeight/2,panelWidth/2, panelHeight/2);
}
public void locateBall(int x, int y, int width, int height){
setBounds(x, y, width, height);
repaint();
}
public void run() {
int width = this.getWidth();
int height = this.getHeight();
Random r = new Random();
while(true){
if(!pleaseWait){
int lastX = this.getX();
int lastY = this.getY();
if (lastX > 675) Xdirection = -1;
if (lastY > 485) Ydirection = -1;
if (lastX < -5) Xdirection = 1;
if (lastY < -5) Ydirection = 1;
/* if(lastX > 280 && lastY > 170){
Xdirection = -1;
Ydirection = -1;
}
*/
locateBall(lastX + Xdirection*r.nextInt(3),
lastY + Ydirection*r.nextInt(3),
width, height );
}
try{
Thread.sleep(5);
}catch(Exception e){};
}
}
}
public class BallWindow extends JFrame implements ActionListener{
JButton btnStop = new JButton("STOP");
JButton btnSave = new JButton("SAVE");
Vector<BallPanel> ballVector = new Vector<BallPanel>();
JPanel p1 = createPanel(280, 200, 200, 20, Color.gray);
JPanel p2 = createPanel(280, 300, 200, 20, Color.gray);
JPanel bottomp = createPanel(345, 540, 70, 15, Color.black);
JPanel lborder = createPanel(10, 10, 2, 560, Color.black);
JPanel rborder = createPanel(720, 10, 2, 560, Color.black);
JPanel tborder = createPanel(10, 10, 710, 2, Color.black);
public BallWindow() {
setLayout(null);
btnStop.setBounds(12, 15, 100, 30);
btnStop.addActionListener(this);
add(btnStop);
btnSave.setBounds(12, 50, 100, 30);
//btnSave.addActionListener(this);
add(btnSave);
Random r = new Random();
for(int i=0; i<7; i++){
BallPanel bp = new BallPanel(r.nextInt(740), r.nextInt(590));
Thread t = new Thread(bp);
ballVector.add(bp);
t.start();
add(bp);
}
add(p1);
add(p2);
add(bottomp);
add(lborder);
add(rborder);
add(tborder);
setSize(740, 590);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
repaint();
}
JPanel createPanel(int x, int y, int width, int height, Color pColor){
JPanel temp = new JPanel();
temp.setBackground(pColor);
temp.setBounds(x, y, width, height);
return temp;
}
public static void main(String[] args) {
new BallWindow();
}
public void actionPerformed(ActionEvent arg0) {
for (BallPanel ball : ballVector) {
ball.pleaseWait = !ball.pleaseWait;
}
if( btnStop.getText().equalsIgnoreCase("STOP"))
btnStop.setText("START");
else
btnStop.setText("STOP");
// if(arg0.getSource())
}
}
I'm stuck with obstacles part and the keylistener. Any type of help will be greatly appreciated.
Hava a look at http://zetcode.com/tutorials/javagamestutorial/
You should especially check out the Basics and the Animation section. It will help clean up the animation and thread stuff you are doing. It also shows a general pattern how one could implement a java game.

Java Key Events and Timer control

Im almost finished with this car project im working on but cant seem to get the key events to work. I think it has to do with my action listener with my timer but im not sure. When I press the up arrow key the timer delay is supposed to decrease and vice versa for the down arrow key. I have the commands written but they are not registering input. If anyone could give me some pointers I'd appreciate it
Code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class RaceCar extends JFrame{
public RaceCar(){
add(new CarPic());
}
public static void main(String[] args){
JFrame frame = new RaceCar();
frame.setTitle("Brady Kedge: Race Car");
frame.setSize(300, 150);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public class CarPic extends JPanel implements KeyListener
{
private int x = 0;
private int y = 150;
private int z = 300;
Timer mytimer = new Timer(50, new ActionListener());
public CarPic()
{
mytimer.start();
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
y = getHeight();
z = getWidth();
g.setColor(Color.WHITE);
g.fillRect(0, 0, z, y);
Polygon polygon = new Polygon();
polygon.addPoint(x + 10, y - 20);
polygon.addPoint(x + 20, y - 30);
polygon.addPoint(x + 30, y - 30);
polygon.addPoint(x + 40, y - 20);
if(x < z - 40)
{
g.setColor(Color.BLACK);
g.fillOval(x + 10, y - 10, 10, 10);
g.fillOval(x + 30, y - 10, 10, 10);
g.setColor(Color.BLUE);
g.fillRect(x, y - 20, 50, 10);
g.setColor(Color.BLUE);
g.fillPolygon(polygon);
}
else
x = 0;
}
public void actionPerformed(ActionEvent e){
x+=10;
repaint();
}
#Override
public void keyTyped(KeyEvent k) {
//Fill
}
#Override
public void keyPressed(KeyEvent k) {
int delay = mytimer.getDelay();
if(k.getKeyCode() == KeyEvent.VK_UP)
mytimer.setDelay(delay > 10 ? delay - 10 : 0);
else if(k.getKeyCode() == KeyEvent.VK_DOWN)
mytimer.setDelay(delay < 5000 ? delay + 10 : 5000);
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
}
}
First of all, you never register a KeyListener with your component (implementing KeyListener isn't enough).
Second of all, KeyListener will only raise KeyEvents if the component it is registered to has focus and is focusable.
A better solution would be to use the key bindings API, which provides you with the means to configure the focus level at which a component will trigger key events.
Also, personally, instead of modifying the Timer delay, I would have use a speed modifier (of type double) which would be percentage of the speed you want. In this way 1 would normal speed, 0.5 half speed and 2 double speed, for example.

Transferring JFrame to JPanel

I created a simple "elevator" program (it's still in the beginning stages) that goes up 1 floor when I click UP and vice versa.
I messed up pretty badly when I drew all my components into JFrame, and as expected, it flickers every time I click the button (repaints). I know the solution to be draw in the JPanel and put the said panel in the JFrame, but I have a problem translating my JFrame components into JPanel. I've tried extending JPanel, creating a JFrame object and then overriding the paintComponent() method and doing my drawing there, but when I compile it does not draw it at all. It only creates the frame.
Can anyone help me or give me tips on how to proceed "transferring" my programming from JFrame based to JPanel based? Thank you in advance!
My code is below:
import java.awt.*;
import javax.swing.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.Timer;
import java.math.*;
public class MyCanvas extends JFrame {
private int up = 0;
private int down = 0;
private int movefloorup = 0;
private int buildingType;//type of building (1 = Residential, 2 = Commercial)
private int totnumoffloors; //for the total number of floors
private int numofelevators; //for the number of elevators to be generated
private int floorlimit = 0; //to determine up until where the elevator will be moving
private int currenttime; //determine the time of the day the elevator is operating (1 = Morning, 2 = Lunch, 3 = Afternooon)
//For elevator resetting to bottom
private int rectX = 190;
private int switchmarker = 0;
//Lines and stuff
private int horizborder = 0;
private int bordercount = 0;
private class UpAction implements ActionListener //move the elevator up
{
public void actionPerformed(ActionEvent e)
{
if(movefloorup<780){
repaint();
up++;
movefloorup = movefloorup + 130;
//repaint();
}
else
{
switchmarker = 1;
movefloorup = 0;
repaint();
}
}
}
private class DownAction implements ActionListener //move the elevator down
{
public void actionPerformed(ActionEvent e)
{
if(movefloorup>0){
repaint();
down++;
movefloorup = movefloorup - 130;
//repaint();
}
else
{
switchmarker = 0;
movefloorup = 780;
repaint();
}
}
}
public MyCanvas(int buildingType, int totnumoffloors, int numofelevators, int currenttime){
this.buildingType = buildingType;
this.totnumoffloors = totnumoffloors;
this.numofelevators = numofelevators;
this.currenttime = currenttime;
String title;
if(this.buildingType == 1)
{
title = "Residential Building";
}
else
{
title = "Commercial Building";
}
setLayout(null);
horizborder = 500*((int)Math.ceil((double)totnumoffloors/7)); //calculating how wide the window should be
bordercount = ((int)Math.ceil((double)totnumoffloors/7)); //counts how many borders there will be
//NOTES
//A floor is 130 units in the Y-Direction
//Drawing the bulding layout
if(totnumoffloors>7)
{
setSize(horizborder, 1000);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle(title);
setLayout(new BorderLayout());
getContentPane().setBackground(Color.WHITE);
}
else{
setSize(500, 1000); //suitable for 7 floors
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle(title);
setLayout(new BorderLayout());
getContentPane().setBackground(Color.WHITE);
}
JButton upButton = new JButton("UP");
upButton.addActionListener(new UpAction());
add(upButton, BorderLayout.NORTH);
JButton downButton = new JButton("DOWN");
//downButton.setBounds(0, 0, 220, 30);
//downButton.setLocation(100, 100);
downButton.addActionListener(new DownAction());
add(downButton, BorderLayout.SOUTH);
}
public void paint(Graphics graphics){ //this is where you draw shit
super.paint(graphics);
//Floors
graphics.setColor(Color.RED);
int numoffloorsY = 830;
int numoffloorsX = 830;
int floorbeginning = 0;
int floorcounter = 1;
int floorflag = 0;
int rightedge = 500;
if(this.totnumoffloors>7) //drawing the floors
{
//Default number of floors -> 7
for(int i = 0;i<totnumoffloors;i++)
{
graphics.setColor(Color.RED);
graphics.drawLine(floorbeginning,numoffloorsX,rightedge,numoffloorsY); //FLOORS
graphics.setColor(Color.DARK_GRAY);
graphics.setFont(new Font("TimesRoman", Font.PLAIN, 15));
graphics.drawString(" "+floorcounter, floorbeginning+10, numoffloorsY+20); //SAVE THIS FOR DRAWING FLOORS
numoffloorsY = numoffloorsY - 130;
numoffloorsX = numoffloorsX - 130;
floorcounter++;
floorflag++;
if(floorflag==7)
{
floorbeginning = floorbeginning + 500;
rightedge = rightedge+500;
numoffloorsY = 830;
numoffloorsX = 830;
floorflag = 0;
}
}
//Every other floor past 7 will be added here.
/*for(int i = 0;i<totnumoffloors-7;i++)
{
//System.out.println("LOLOOLO");
graphics.setColor(Color.RED);
graphics.drawLine(floorbeginning,numoffloorsX,horizborder,numoffloorsY);
graphics.setColor(Color.DARK_GRAY);
graphics.setFont(new Font("TimesRoman", Font.PLAIN, 15));
graphics.drawString(" "+floorcounter, floorbeginning, numoffloorsY+20);
//graphics.setColor(Color.DARK_GRAY);
//graphics.drawLine(500,0,500,1000);
floorcounter++;
numoffloorsY = numoffloorsY - 130;
numoffloorsX = numoffloorsX - 130;
}*/
//DIVIDING LINE -> to determine the first 7 floors from the ones higher up.
for(int i=0;i<bordercount;i++)
{
graphics.setColor(Color.DARK_GRAY);
graphics.drawLine(500*i,0,500*i,1000);
}
}
else{
for(int i = 0;i<this.totnumoffloors;i++)
{
graphics.setColor(Color.RED);
graphics.drawLine(0,numoffloorsX,500,numoffloorsY);
graphics.setColor(Color.DARK_GRAY);
graphics.setFont(new Font("TimesRoman", Font.PLAIN, 15));
graphics.drawString(" "+floorcounter, floorbeginning+10, numoffloorsY+20); //SAVE THIS FOR DRAWING FLOOR
numoffloorsY = numoffloorsY - 130;
numoffloorsX = numoffloorsX - 130;
floorcounter++;
}
}
//Drawing the elevators
if(up>0 && movefloorup<1000){
graphics.setColor(Color.GRAY);
if(switchmarker==1)
{
System.out.println("ELSA");
rectX = 690;
//rectX = rectX + 190;
}
else
{
rectX = 190;
}
System.out.println(rectX);
graphics.fillRect(rectX, 850-movefloorup, 100, 100); //this needs to match the stats of the rectangle to fill it properly
graphics.drawRect(rectX, 850-movefloorup, 100, 100);
//Line for the door
graphics.setColor(Color.BLACK);
graphics.drawLine(rectX+50, 850-movefloorup, rectX+50, 950-movefloorup); //match the y-coordinate for the rectangle, add 100 for the y-coordinate of the other end
System.out.println(movefloorup);
System.out.println(switchmarker);
//drawLine(x1, y1, x2, y2); --From (x1,y1) to (x2,y2)
}
else if(down>0 && movefloorup>0)
{
graphics.setColor(Color.GRAY);
if(switchmarker==1) //This determines when the elevator should move to the next column of higher floors.
{
System.out.println("ELSA");
rectX = 500;
}
System.out.println(rectX);
graphics.fillRect(rectX, 850-movefloorup, 100, 100); //this needs to match the stats of the rectangle to fill it properly
//graphics.drawRect(190, 850 + movefloorup, 100, 100); //FIRST FLOOR
graphics.drawRect(rectX, 850-movefloorup, 100, 100); //SECOND FLOOR (135 units difference in Y-axis between floors)
//x-coordinate, y-coordinate, width, height
//Line for the door
graphics.setColor(Color.BLACK);
graphics.drawLine(rectX+50, 850-movefloorup, rectX+50, 950-movefloorup); //match the y-coordinate for the rectangle, add 100 for the y-coordinate of the other end
System.out.println(movefloorup);
System.out.println(switchmarker);
}
else
{
graphics.setColor(Color.GRAY);
graphics.fillRect(190, 850, 100, 100); //this needs to match the stats of the rectangle to fill it properly
graphics.drawRect(190, 850, 100, 100); //FIRST FLOOR
graphics.drawRect(190, 850, 100, 100); //SECOND FLOOR (135 units difference in Y-axis between floors)
//x-coordinate, y-coordinate, width, height
//Line for the door
graphics.setColor(Color.BLACK);
graphics.drawLine(240, 850, 240, 950); //match the y-coordinate for the rectangle, add 100 for the y-coordinate of the other end
//System.out.println("In else!");
}
}
}
The main class just gets input from the user, such as the number of floors, time of day, etc.
This is going to be a little messy.
Start by creating a custom component that extends from JPanel (I'll call it ElevatorPane).
Take the contents of the current paint method and place them within this components paintComponent method. This will involve moving the instance variables that the paintComponent method will need including, totnumoffloors, bordercount, up, down, movefloorup, switchmarker, rectX
This is where it gets a little messy...
You need to take the contents of your ActionListeners and translate these into methods within the ElevatorPane, this way you expose the functionality without exposing the details...
Create a constructor within ElevatorPane that takes the number of floors.
Override the getPrefferedSize method of ElevatorPane and return the size that the component needs to be to satisfy your needs...
Create an instance field of ElevatorPane in MyCanvas, instantiate it and add it to the frame.
Clean, build, run...

Zooming In On a Java Graphic

I am making a graph of a sound speed profile with java graphics. I have the static graph drawn (the one that pops up when you run the program), but I am trying to implement it such that if the user clicks on either the x or y axis, then it will zoom in so you can look at the sound speed profile more closely. I don't have the sound speed profile in the graph yet (I already know how to do that, I'm just saving the effort of drawing it until I have the zoom feature figured out). Does anyone have any ideas as to how to make this work? I have seen people trying to use the Affine Transform for similar tasks, but I am not sure that's the right thing to do or if I'm even doing this correctly. The particular code to look at is the paint(), zoomIn(), and mouseClicked() method. Ideas would be much apprecaited!
public class SoundSpeedProfile extends JPanel implements MouseListener, ActionListener {
private String title;
private String subTitle;
private JFrame frame;
private Graphics g;
.
.
.
/**Draws the sound speed profile and surrounding graphics
* #param Graphics g - graphics object
*/
public void paint(Graphics g){
this.g = g;
super.paint(g); //the super knows how to draw "standard" components like squares, rectangles, circles, etc
g.setColor(Color.DARK_GRAY);
//1) Set up the graph the sound speed profile lives in
//X-Axis for Speeds
g.drawLine(100, 150, 450, 150);//the graphics display has 0,0 in the upper left corner versus the lower left corner
int i = 120;
int k = 1460;
while (i<440){
g.drawString("|", i, 155);
g.drawString("" + k + "", i-2, 140);
k = k + 20;
i = i + 60;
}
//Y-Axis
g.drawLine(100, 500, 100, 150);
k= 7000;
int j = 500;
while (j>160){
g.drawString("" + k, 60, j);
g.drawString("--", 94, j);
k = k - 1000;
j = j - 50;
}
Font f1 = new Font("Serif", 4, 15);
g.setFont(f1);
g.drawString(this.title, 200,30);//Graph Title
g.drawString(this.subTitle, 225, 50);
Font f2 = new Font("Serif", 2, 15);
g.setFont(f2);
g.drawString("Sound Speed ", 200, 110);//x-axis label
g.drawString("(" + spdUnits + ")", 290, 110); //Units label--taken from input array
g.drawString("Depth", 10, 180); //y-axis label
g.drawString("(" + depUnits + ")", 07, 200); //Units label--taken from input array
//((Graphics2D)g).scale(20, 20);
}
/**Creates and shows the GUI drawing of the sound speed profile in a JFrame
*/
private void createAndShowGUI(){
frame = new JFrame("Sound Speed Profile");
canvas = new Canvas();
frame.add(canvas);
frame.addMouseListener(this);
frame.setBackground(Color.cyan);
frame.setSize(600,800);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLayout(new BorderLayout());
frame.add(this, BorderLayout.CENTER);//add the sound speed profile graphic and set a Border Layout
//frame.pack();
frame.setVisible(true);
}
/**
* Runs test cases
* #param args
*/
public static void main (String [] args){
ssp.setTitle("Sound Speed Profile 1");
ssp.setSubtitle("June 1, 2012");
ssp.createAndShowGUI();
ssp.repaint(); //necessary?
}
#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseClicked(MouseEvent arg0) {
int x = arg0.getX();
//System.out.println("x: " + x);
int xMin = x - 50;
int xMax = x + 50;
int y = arg0.getY();
//System.out.println("y: " + y);
int yMin = y-50;
int yMax = y + 50;
//If the user clicked on the x-axis
if ( 160<y && y<180 && 100<x && x<450){
System.out.println("About to zoom in on the x-axis");
zoomIn(x, y);
//System.out.println("zooming in on the x-axis");
}
//If the user clicked on the y-axis
if (90<x && x<110 && 150 <y && y<500){
//System.out.println("zooming in on the y-axis");
}
}
public void zoomIn(int x, int y){
AffineTransform old = ((Graphics2D) g).getTransform();
for (double zoom = 1; zoom >=0.1; zoom=-0.1){
AffineTransform tr2 =AffineTransform.getTranslateInstance(-x, -y);
AffineTransform tr= AffineTransform.getScaleInstance(zoom,zoom);
tr.concatenate(tr2); tr2=tr;
tr =AffineTransform.getTranslateInstance(x, y);
tr.concatenate(tr2); tr2=tr;
tr= new AffineTransform(old);
tr.concatenate(tr2); tr2=tr;
((Graphics2D)g).setTransform(tr2);
((Graphics2D)g).drawRect(x, y, 10, 10);
((Graphics2D)g).setTransform(old);
}
}

Categories

Resources