I need a simple do loop for my game but don't know how to create one.
I have a simple maze game.
I still need to add more walls
I was thinking of creating an array and calling the index of the array in the do loop to call the wall but i dont now how to do it
I was thinking that I could create a do loop instead of copying and pastinn the collision code 30 times.
My player needs to be reset to the beginning when it touches a wall
The player is s simple JLabel.My walls are also a JLabel.I'm using swing components for my game.
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.HashSet;
import java.util.Set;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
/**
* This class Holds the game pane that has the moving player. It also contains
* the GamePane
*
* #author 602052004
*
*/
public class GamePane extends JPanel implements ActionListener, KeyListener {// *change GamePane to GamePane
// This is where the game screen is made and the player is created.
private static final long serialVersionUID = 1L;
JLabel player = new JLabel();
//This is were the Jlabels for the walls are created
JLabel wall1 = new JLabel();
JLabel wall2 = new JLabel();
JLabel wall3 = new JLabel();
JLabel wall4 = new JLabel();
JLabel wall5 = new JLabel();
int playerSpeed = 5;
int FPS = 40;
private final Set<Integer> keys = new HashSet<>();
// The keys set holds the keys being pressed
public static void main(String[] args) {
// Open the GUI window
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
// Create a new object and
// run its go() method
new GamePane().go();
}
});
}
GamePane() {
// Run the parent class constructor
super();
// Allow the panel to get focus
setFocusable(true);
// Don't let keys change the focus
}
/**
* The frame that shows my game. It contains the game frame which holds my
* JPanel GameStage and ButtonPane.
*/
protected void go() {
setLayout(new CardLayout());
// Setup the window
JFrame GameFrame = new JFrame();
// Add this panel to the window
GameFrame.setLayout(new CardLayout());
GameFrame.add(this, "main");
GameFrame.setContentPane(this);
// Set's the window properties
GameFrame.setTitle("main");
GameFrame.setSize(800, 600);
GameFrame.setLocationRelativeTo(null);
GameFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
GameFrame.setVisible(true);
GameFrame.add(new ButtonPane(GameFrame), "buttons");
// Creates the new JPanel that will hold the game.
JPanel gamestage = new JPanel();
gamestage.setBackground(Color.darkGray);
GameFrame.add(gamestage, "game");
gamestage.setLayout(null);
// *Move the setup of the player and the timer under the walls
// Get a sample of collisions going so that i can do it over the weekend
// Setup the movable box
player.setBounds(25, 25, 20, 20);
player.setVisible(true);
player.setBackground(Color.cyan);
// Opaque makes the background visible
player.setOpaque(true);
// Setup the key listener
addKeyListener(this);
// Null layout allows moving objects!!!
gamestage.add(player);
// Set the timer
Timer tm = new Timer(1000 / FPS, this);
tm.start();
wall1.setBounds(10, 15, 10, 480);
wall1.setVisible(true);
wall1.setBackground(Color.white);
wall1.setOpaque(true);
gamestage.add(wall1);
wall2.setBounds(10, 10, 755, 10);
wall2.setVisible(true);
wall2.setBackground(Color.white);
wall2.setOpaque(true);
gamestage.add(wall2);
// wall3.setBounds(x, y, width, height);
wall3.setBounds(10, 100, 100, 10);
wall3.setVisible(true);
wall3.setBackground(Color.white);
wall3.setOpaque(true);
gamestage.add(wall3);
wall4.setBounds(100, 60, 10, 40);
wall4.setVisible(true);
wall4.setBackground(Color.white);
wall4.setOpaque(true);
gamestage.add(wall4);
wall5.setBounds(70, 60, 35, 10);
wall5.setVisible(true);
wall5.setBackground(Color.white);
wall5.setOpaque(true);
gamestage.add(wall5);
}
public boolean areColliding(JLabel a, JLabel b) {
return a.getBounds().intersects(b.getBounds());
}
/**
* this method makes the player move. It takes the players speed and subtracts
* or adds the player speed to the current position of the player. It also
* figures out were the player is at currently aswell.
*
* #param arg0
*/
#Override
public void actionPerformed(ActionEvent arg0) {
// Move up if W is pressed
if (keys.contains(KeyEvent.VK_W)) {
player.setLocation(player.getX(), player.getY() - playerSpeed);
}
// Move right if D is pressed
if (keys.contains(KeyEvent.VK_D)) {
player.setLocation(player.getX() + playerSpeed, player.getY());
}
// Move down if S is pressed
if (keys.contains(KeyEvent.VK_S)) {
player.setLocation(player.getX(), player.getY() + playerSpeed);
}
// Move left if A is pressed
if (keys.contains(KeyEvent.VK_A)) {
player.setLocation(player.getX() - playerSpeed, player.getY());
}
// Check for collisions
if (areColliding(wall1, player)) {
// Reposition the target
int newX = (int) (25);
int newY = (int) (25);
player.setLocation(newX, newY);}
}
#Override
public void keyPressed(KeyEvent e) {
// Add the key to the list
// of pressed keys
if (!keys.contains(e.getKeyCode())) {
keys.add(e.getKeyCode());
}
}
#Override
public void keyReleased(KeyEvent e) {
// Remove the key from the
// list of pressed keys
keys.remove((Integer) e.getKeyCode());
}
#Override
public void keyTyped(KeyEvent e) {
}
}
This is just for you to have a running main screen to go to when playing the game
/**
* This pane contains the button and sets up the button pane
*/
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ButtonPane extends JPanel {
private JButton startBTN;// Calls the JButton
JFrame game;
public ButtonPane(JFrame g) {
game = g;
setLayout(new GridBagLayout());
setBackground(Color.gray);// Sets the menu stages color blue
startBTN = new JButton("Start");// Creates a new button
add(startBTN);// Adds the button on the startStage
startBTN.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (game.getContentPane().getLayout() instanceof CardLayout) {
CardLayout layout = (CardLayout) getParent().getLayout();
layout.show(game.getContentPane(), "game");
}
}
});
}
}
The basic idea is to place all the objects that the player can collide with in a List.
On each movement of the player, loop over this list and use the Rectangle#contains and Rectangle#intersects provided by the component's getBounds methods
Which might look something like this...
public class GamePane extends JPanel implements ActionListener, KeyListener {// *change GamePane to GamePane
private List<JComponent> collidableStuff;
public GamePane() {
collidableStuff = new ArrayList<>(25);
//...
wall1 = ...;
wall2 = ...;
wall3 = ...;
wall4 = ...;
wall5 = ...;
// In fact, you could get rid of wall1-5 and just
// use the list instead
collidableStuff.add(wall1);
collidableStuff.add(wall2);
collidableStuff.add(wall3);
collidableStuff.add(wall4);
collidableStuff.add(wall5);
//...
}
#Override
public void actionPerformed(ActionEvent e) {
//...
player.setLocation(newX, newY);
performCollisionDetection();
}
protected void performCollisionDetection() {
Rectangle playerBounds = player.getBounds();
for (JComponent nonPassable : collidableStuff) {
// Because I didn't test the code, I'm covering all bases
Rectangle nonPassableBounds = nonPassable.getBounds();
if (nonPassableBounds.contains(playerBounds) || playerBounds.contains(nonPassableBounds)
|| playerBounds.intersects(nonPassableBounds) || nonPassableBounds.intersects(playerBounds)) {
// Smack, we have a collision
}
}
}
}
This example moves the responsibility of the creation of the objects to the constructor, rather the then the go method, which, frankly shouldn't exist - the GamePane shouldn't care about "how" it's been shown, that's not it's responsibility
Related
I'm making a Java GUI that has a panel where you can scribble on it. I want to save the scribbled image after drawing it. However, my save method only saves the background and not the drawing.
Here is part of the constructor for my GUI. The important part is the scribblePane2 object which is the section of the GUI where the image is drawn.
public GUI(){
// Create the main scribble pane component, give it a border, and
// a background color, and add it to the content pane
scribblePane = new ScribblePane2();
scribblePane.setBorder(new BevelBorder(BevelBorder.LOWERED));
scribblePane.setBackground(Color.black);
contentPane.add(scribblePane, BorderLayout.CENTER);
}
Here is the scribblePane2 class where I take the mouse input to draw the image in the panel. The method "lineto" is where I draw the lines in response to mouse input. I tried drawing to the buffered image, bufferImage, but it did not work for me.
class ScribblePane2 extends JPanel {
BufferedImage bufferImage;
public ScribblePane2() {
// Give the component a preferred size
setPreferredSize(new Dimension(200, 200));
bufferImage = new BufferedImage(200, 200,
BufferedImage.TYPE_INT_ARGB);
Graphics2D bufferGraphics = bufferImage.createGraphics();
}
/** Draw from the last point to this point, then remember new point */
public void lineto(int x, int y) {
Graphics g = getGraphics();
g.setColor(color);
((Graphics2D) g).setStroke(new BasicStroke(10));// Tell it what color to use
g.drawLine(last_x, last_y, x, y);
moveto(x, y);
}
public BufferedImage getImage (){
return bufferImage;
}
}
Here is my method to save the image. I tried by creating a Buffered Image of the scribblePane and a doing the screen capture which is the line commented out. Both have not worked.
public static void saveDrawing(int i) {
BufferedImage imagebuf = null;
//imagebuf = new Robot().createScreenCapture(scribblePane.getBounds());
imagebuf = new BufferedImage(scribblePane.WIDTH, scribblePane.HEIGHT, BufferedImage.TYPE_INT_RGB);
//imagebuf = scribblePane.getImage();
Graphics2D graphics2D = imagebuf.createGraphics();
scribblePane.paint(graphics2D);
try {
ImageIO.write(imagebuf, "png", new File("save" + i +".png"));
System.out.println("image saved");
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println("error");
}
}
For reference, here is all of my code.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.JColorChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JToolBar;
import javax.swing.SwingConstants;
import javax.swing.border.BevelBorder;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import javax.imageio.ImageIO;
public class GUI {
private static int i;
private static JButton button;
private static JButton button2;
private static JLabel label;
private static ScribblePane2 scribblePane;
private static JPanel contentPane;
private Path mPath;
private Paint mBitmapPaint;
private Paint mPaint;
//private Bitmap mBitmap;
private Canvas mCanvas;
BufferedImage bufferImage;
public static void main(String[] args){
new GUI();
setUpButtonListeners();
// Scribble scribble = new Scribble();
//scribble.setSize(500, 300);
//scribble.setVisible(true);
}
public GUI(){
JFrame frame = new JFrame();
frame.setSize(300,300);
GridBagLayout layout = new GridBagLayout();
JPanel panel = new JPanel();
JPanel panel2 = new JPanel();
label = new JLabel("number");
JLabel label2 = new JLabel("Hi I'm contentPane");
contentPane = new JPanel();
contentPane.add(label2);
button = new JButton("Classify Image");
button2 = new JButton("Erase Image");
// Specify a layout manager for the content pane
contentPane.setLayout(new BorderLayout());
// Create the main scribble pane component, give it a border, and
// a background color, and add it to the content pane
scribblePane = new ScribblePane2();
scribblePane.setBorder(new BevelBorder(BevelBorder.LOWERED));
scribblePane.setBackground(Color.black);
contentPane.add(scribblePane, BorderLayout.CENTER);
// Create a menubar and add it to this window. Note that JFrame
// handles menus specially and has a special method for adding them
// outside of the content pane.
JMenuBar menubar = new JMenuBar(); // Create a menubar
//frame.setJMenuBar(menubar); // Display it in the JFrame
// Create menus and add to the menubar
JMenu filemenu = new JMenu("File");
JMenu colormenu = new JMenu("Color");
menubar.add(filemenu);
// menubar.add(colormenu);
// Create some Action objects for use in the menus and toolbars.
// An Action combines a menu title and/or icon with an ActionListener.
// These Action classes are defined as inner classes below.
Action black = new ColorAction(Color.black);
Action red = new ColorAction(Color.red);
Action blue = new ColorAction(Color.blue);
// Populate the menus using Action objects
// colormenu.add(black);
// Now create a toolbar, add actions to it, and add it to the
// top of the frame (where it appears underneath the menubar)
JToolBar toolbar = new JToolBar();
// contentPane.add(toolbar, BorderLayout.NORTH);
// Create another toolbar for use as a color palette and add to
// the left side of the window.
JToolBar palette = new JToolBar();
palette.add(black);
palette.setOrientation(SwingConstants.VERTICAL);
// contentPane.add(palette, BorderLayout.WEST);
panel.setBorder(BorderFactory.createEmptyBorder(30,30,10,30));
panel.setLayout(layout);
panel2.setLayout(new BorderLayout());
panel2.add(label, BorderLayout.WEST);
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.gridx = 0;
gbc.gridy = 0;
panel.add(contentPane, gbc);
gbc.gridx = 1;
gbc.gridy = 0;
panel.add(panel2,gbc);
gbc.gridx = 0;
gbc.gridy = 2;
//gbc.fill = GridBagConstraints.HORIZONTAL;
//gbc.gridwidth = 2;
panel.add(button, gbc);
gbc.gridx = 1;
gbc.gridy = 2;
panel.add(button2, gbc);
//panel.setLayout(new BorderLayout());
//panel.add(button, BorderLayout.WEST);
//panel.add(button2, BorderLayout.EAST);
//panel.add(label, BorderLayout.NORTH);
//panel.add(contentPane, BorderLayout.SOUTH);
frame.add(panel);
frame.setTitle("GUI");
frame.pack();
frame.setVisible(true);
}
public static void setUpButtonListeners(){
ActionListener buttonListener = new ActionListener(){
#Override
public void actionPerformed(ActionEvent e){
System.out.println("save");
int output = 0;
saveDrawing(i);
i++;
label.setText("" + output);
}
};
ActionListener buttonListener2 = new ActionListener(){
#Override
public void actionPerformed(ActionEvent e){
System.out.println("erase");
scribblePane.clear();
label.setText("");
}
};
button.addActionListener(buttonListener);
button2.addActionListener(buttonListener2);
}
public static void saveDrawing(int i) {
//throws AWTException {
BufferedImage imagebuf = null;
//imagebuf = new Robot().createScreenCapture(scribblePane.getBounds());
imagebuf = new BufferedImage(scribblePane.WIDTH, scribblePane.HEIGHT, BufferedImage.TYPE_INT_RGB);
//imagebuf = scribblePane.getImage();
Graphics2D graphics2D = imagebuf.createGraphics();
scribblePane.paint(graphics2D);
try {
ImageIO.write(imagebuf, "png", new File("save" + i +".png"));
System.out.println("image saved");
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println("error");
}
}
private void loadImageFromStorage(String path)
{
System.out.println("load");
//use a fileInputStream to read the file in a try / catch block
// try {
// File f=new File(path, "drawn_image.jpg");
// Bitmap b = BitmapFactory.decodeStream(new FileInputStream(f));
// ImageView img=(ImageView)findViewById(R.id.outputView);
// img.setImageBitmap(b);
// }
// catch (FileNotFoundException e)
// {
/// e.printStackTrace();
// }
}
/** This inner class defines the "clear" action that clears the scribble */
/** This inner class defines the "quit" action to quit the program */
/**
* This inner class defines an Action that sets the current drawing color of
* the ScribblePane2 component. Note that actions of this type have icons
* rather than labels
*/
class ColorAction extends AbstractAction {
Color color;
public ColorAction(Color color) {
this.color = color;
putValue(Action.SMALL_ICON, new ColorIcon(color)); // specify icon
}
public void actionPerformed(ActionEvent e) {
scribblePane.setColor(color); // Set current drawing color
}
}
/**
* This inner class implements Icon to draw a solid 16x16 block of the
* specified color. Most icons are instances of ImageIcon, but since we're
* only using solid colors here, it is easier to implement this custom Icon
* type
*/
static class ColorIcon implements Icon {
Color color;
public ColorIcon(Color color) {
this.color = color;
}
// These two methods specify the size of the icon
public int getIconHeight() {
return 16;
}
public int getIconWidth() {
return 16;
}
// This method draws the icon
public void paintIcon(Component c, Graphics g, int x, int y) {
g.setColor(color);
g.fillRect(x, y, 16, 16);
}
}
}
class ScribblePane2 extends JPanel {
BufferedImage bufferImage;
public ScribblePane2() {
// Give the component a preferred size
setPreferredSize(new Dimension(200, 200));
bufferImage = new BufferedImage(200, 200,
BufferedImage.TYPE_INT_ARGB);
Graphics2D bufferGraphics = bufferImage.createGraphics();
// Register a mouse event handler defined as an inner class
// Note the call to requestFocus(). This is required in order for
// the component to receive key events.
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
moveto(e.getX(), e.getY()); // Move to click position
requestFocus(); // Take keyboard focus
}
});
// Register a mouse motion event handler defined as an inner class
// By subclassing MouseMotionAdapter rather than implementing
// MouseMotionListener, we only override the method we're interested
// in and inherit default (empty) implementations of the other methods.
addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent e) {
lineto(e.getX(), e.getY()); // Draw to mouse position
}
});
// Add a keyboard event handler to clear the screen on key 'C'
addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_C)
clear();
}
});
}
/** These are the coordinates of the the previous mouse position */
protected int last_x, last_y;
/** Remember the specified point */
public void moveto(int x, int y) {
last_x = x;
last_y = y;
}
/** Draw from the last point to this point, then remember new point */
public void lineto(int x, int y) {
Graphics g = getGraphics();
/// BufferedImage newBufferedImage = new BufferedImage(200,200,
//BufferedImage.TYPE_INT_ARGB);
/// Graphics g = newBufferedImage.getGraphics();
// Get the object to draw with
g.setColor(color);
((Graphics2D) g).setStroke(new BasicStroke(10));// Tell it what color to use
g.drawLine(last_x, last_y, x, y); // Tell it what to draw
//g.drawImage(bufferImage, x,y,null);
//bufferImage = newBufferedImage;// Save the current point
moveto(x, y);
}
public BufferedImage getImage (){
return bufferImage;
}
/**
* Clear the drawing area, using the component background color. This method
* works by requesting that the component be redrawn. Since this component
* does not have a paintComponent() method, nothing will be drawn. However,
* other parts of the component, such as borders or sub-components will be
* drawn correctly.
*/
public void clear() {
repaint();
}
/** This field holds the current drawing color property */
Color color = Color.white;
/** This is the property "setter" method for the color property */
public void setColor(Color color) {
this.color = color;
}
/** This is the property "getter" method for the color property */
public Color getColor() {
return color;
}
}
I have made a simple class to practice layouts. most of it is working fine, but my JLabel is not appearing until after I click the button. I had the same info as a JTextField and JTextArea in earlier versions, but really prefer the appearance of the JLabel, but even in the other iterations, it would only appear if I clicked on or tried to select the text from the window. I've tried setting the text variable to visible after generating it, after adding it to the under panel, and setting the whole under panel to visible in addition to the setVisible(true) called for the whole object, and none of those worked.
Here is my code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class LayoutPractice extends JFrame implements ActionListener {
//Set up variables
private JPanel graphic;
private JPanel under;
private JButton button;
private JLabel text;
private int clicks;
/**
* Constructor, sets up GUI
*
*/
public LayoutPractice(){
//Default JFrame setup
super("Layout Practice");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Set up the graphic panel
this.graphic = new JPanel();
graphic.setPreferredSize(new Dimension(500, 500));
//Set up the components that go under the graphic
this.clicks = 0;
this.button = new JButton("Click for dialog");
this.text = new JLabel("No Clicks");
//Set up the under panel, add in the button and label
this.under = new JPanel();
under.setLayout(new FlowLayout());
under.add(button);
under.add(text);
//Tell it to react to the button being pressed
button.addActionListener(this);
//Set the panels onto the JFrame
getContentPane().add(graphic, BorderLayout.CENTER);
getContentPane().add(under, BorderLayout.PAGE_END);
//Pack and set the JFrame to visible
pack();
setVisible(true);
}
/**
* Paints the image displayed on graphic
*
* #param A Graphics object to be worked on
*
*/
public void paint(Graphics g) {
//Assigns which panel to paint
graphic.paint(g);
//Set a color to pains
g.setColor(Color.BLUE);
//Use variables for a pattern
int x = 0;
int y = 0;
//Loop for a pattern
while (x <= 230) {
//Generates a filled rectangle of the correct size
g.fillRect(x, y, (500-(2 * x)), (500-(2 * y)));
//Alternates color
if (g.getColor() == Color.BLUE) {
g.setColor(Color.ORANGE.darker());
}
else {
g.setColor(Color.BLUE);
}
//Increase variables to reduce rectangle size
x += 20;
y += 20;
}
}
/**
* Tells the GUI what to do when the button is pressed
*
* #param An ActionEvent, specifically the buton being pressed
*/
public void actionPerformed(ActionEvent event) {
//Increase the clicks variable
clicks++;
//Change/update the JLabel
text.setText("Clicks: " + clicks);
//Open a dialog using available tools
JOptionPane.showMessageDialog(new JFrame(),
("Clicks: " + clicks),
"Click Count",
JOptionPane.INFORMATION_MESSAGE);
}
/**
* Very simple main, makes a new LayoutPractice
*
* #param args
*/
public static void main(String[] args) {
new LayoutPractice();
}
}
The quick fix is to just call super.paint(g) at the beginning of your overriden paint method, so that the frame ensures its clearing/cleaning/layout correctly.
The best fix takes the following into account :
When overriding a method, add the #Override annotation, so that your IDE will warn you if you incorrectly override .
When overriding a painting method , call its super implementation to ensure that things get correctly cleaned by the parent component.
For custom painting, better use a JComponent (usually a JPanel).
For custom painting, override paintComponent(Graphics) (and call super.paintComponent), don't use paint(Graphics).
You don't need to extend JFrame, just create one JFrame and use it.
In the below example, a custom JPanel class has been added for custom painting, and the application doesn't extend JFrame anymore :
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class LayoutPractice implements ActionListener {
//Set up variables
private final JPanel graphic;
private final JPanel under;
private final JButton button;
private final JLabel text;
private int clicks;
/**
* Constructor, sets up GUI
*
*/
public LayoutPractice() {
//Default JFrame setup
JFrame frame = new JFrame("Layout Practice");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Set up the graphic panel
graphic = new GraphicPanel();
graphic.setPreferredSize(new Dimension(500, 500));
//Set up the components that go under the graphic
clicks = 0;
button = new JButton("Click for dialog");
text = new JLabel("No Clicks");
//Set up the under panel, add in the button and label
under = new JPanel();
under.setLayout(new FlowLayout());
under.add(button);
under.add(text);
//Tell it to react to the button being pressed
button.addActionListener(this);
JPanel mainPanel = new JPanel(new BorderLayout());
//Set the panels onto the JFrame
mainPanel.add(graphic, BorderLayout.CENTER);
mainPanel.add(under, BorderLayout.PAGE_END);
frame.setContentPane(mainPanel);
//Pack and set the JFrame to visible
frame.pack();
frame.setVisible(true);
}
/**
* Tells the GUI what to do when the button is pressed
*
* #param An ActionEvent, specifically the buton being pressed
*/
public void actionPerformed(final ActionEvent event) {
//Increase the clicks variable
clicks++;
//Change/update the JLabel
text.setText("Clicks: " + clicks);
//Open a dialog using available tools
JOptionPane.showMessageDialog(new JFrame(),
("Clicks: " + clicks),
"Click Count",
JOptionPane.INFORMATION_MESSAGE);
}
/**
* Very simple main, makes a new LayoutPractice
*
* #param args
*/
public static void main(final String[] args) {
new LayoutPractice();
}
private class GraphicPanel extends JPanel {
#Override
public void paintComponent(final Graphics g) {
super.paintComponent(g);
//Set a color to pains
g.setColor(Color.BLUE);
//Use variables for a pattern
int x = 0;
int y = 0;
//Loop for a pattern
while (x <= 230) {
//Generates a filled rectangle of the correct size
g.fillRect(x, y, (500 - (2 * x)), (500 - (2 * y)));
//Alternates color
if (g.getColor() == Color.BLUE) {
g.setColor(Color.ORANGE.darker());
} else {
g.setColor(Color.BLUE);
}
//Increase variables to reduce rectangle size
x += 20;
y += 20;
}
}
}
}
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 4 years ago.
I have an issue with the card layout. It sates that (at GameWindow$2.mouseClicked(GameWindow.java:80)) There's an error. My card layout looks like this
((CardLayout) getContentPane().getLayout()).show(getContentPane(), "game");
Can someone please help me figure the issue out. I have two frames one that contains the game and the other contains the button to get the game stage. Can someone please do this one thing for me.
The layout is Null for the card layout
// Import necessary GUI classes
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.HashSet;
import java.util.Set;
import javax.swing.JLabel;
import javax.swing.Timer;
// "Extend" the JFrame class so we can customize it but still keep all its features
public class GameWindow extends JFrame implements ActionListener, KeyListener {
// Serial version UIDs are used to differentiate between different object
// versions--don't worry about it!
private static final long serialVersionUID = 1L;
JLabel Player = new JLabel();
int playerSpeed = 1;
int FPS = 30;
// The keys set holds the keys being pressed
private final Set<Integer> keys = new HashSet<>();
// This main method runs when the program is executed
public static void main(String[] args) {
// This method runs a new "runnable" program after a brief pause that allows the
// main program to exit
EventQueue.invokeLater(new Runnable() {
public void run() {
// The try/catch block prevents errors from crashing the program
try {
GameWindow window = new GameWindow(); // Create and setup the main game window
window.setVisible(true); // show the new window
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Constructor: runs when a GameWindow object is created (instantiated)
*/
public GameWindow() {
// Run the parent class constructor
super();
// Allow the panel to get focus
setFocusable(true);
// Don't let keys change the focus
setFocusTraversalKeysEnabled(false);
setBounds(100, 100, 250, 360); // the window will appear at (100, 100) and 250w by 260h
setTitle("Banana Jumper 1.0"); // the window will have this title
setResizable(false); // the window can't be resized
setLocationRelativeTo(null); // the window will move to the centre of the screen
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // when the window is closed, the program will exit
getContentPane().setLayout(new CardLayout()); // the window can swap between "stages" added as JPanels
// Make a new screen with a button and put it in the window
JPanel startStage = new JPanel(); // Create a new JPanel and add it to the card layout
startStage.setSize(getWidth(), getHeight()); // make the new JPanel fit the window
startStage.setBackground(Color.BLUE); // set the JPanel background to blue
JButton playButton = new JButton("Play"); // Add a button to the panel
playButton.addMouseListener(new MouseAdapter() { // Set the button to switch to the game stage
#Override
public void mouseClicked(MouseEvent arg0) {
((CardLayout) getContentPane().getLayout()).show(getContentPane(), "game");
setLayout(null);
}
});
startStage.add(playButton); // add the button to the stage
add(startStage, "start"); // add the stage to the window
// Create a second JPanel with band add it to the card layout
JPanel gameStage = new JPanel();
gameStage.setSize(getWidth(), getHeight());
gameStage.setVisible(true);
gameStage.setBackground(Color.RED);
// Add a button to the panel
JButton mainButton = new JButton("Back to Main Menu");
// Set the button to switch to the start stage
mainButton.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
((CardLayout) getContentPane().getLayout()).show(getContentPane(), "start");
}
});
gameStage.add(mainButton);
// Put the stages in the window
add(startStage, "start");
add(gameStage, "game"); // put the stage in the window
// Setup the movable box
Player.setBounds(10, 10, 10, 10);
Player.setVisible(true);
Player.setBackground(Color.BLUE);
// Opaque makes the background visible
Player.setOpaque(true);
// Setup the key listener
addKeyListener(this);
// Null layout allows moving objects!!!
setLayout(null);
add(Player);
// Set the timer
Timer tm = new Timer(1000 / FPS, this);
tm.start();
}
#Override
public void actionPerformed(ActionEvent arg0) {
// Move up if W is pressed
if (keys.contains(KeyEvent.VK_W)) {
Player.setLocation(Player.getX(), Player.getY() - playerSpeed);
}
// Move right if D is pressed
if (keys.contains(KeyEvent.VK_D)) {
Player.setLocation(Player.getX() + playerSpeed, Player.getY());
}
// Move down if S is pressed
if (keys.contains(KeyEvent.VK_S)) {
Player.setLocation(Player.getX(), Player.getY() + playerSpeed);
}
// Move left if A is pressed
if (keys.contains(KeyEvent.VK_A)) {
Player.setLocation(Player.getX() - playerSpeed, Player.getY());
}
}
#Override
public void keyPressed(KeyEvent e) {
// Add the key to the list
// of pressed keys
if (!keys.contains(e.getKeyCode())) {
keys.add(e.getKeyCode());
}
}
#Override
public void keyReleased(KeyEvent e) {
// Remove the key from the
// list of pressed keys
keys.remove((Integer) e.getKeyCode());
}
#Override
public void keyTyped(KeyEvent e) {
}
}
You've set the layout to null - setLayout(null);, which is the equivalent of saying getContentPane().setLayout(null)
Observations...
Avoid things like startStage.setSize(getWidth(), getHeight()); // make the new JPanel fit the window - let the layout manager do it's job
startStage.setVisible(true); // show the JPanel is pointless, as Swing components are visible by default
Avoid extending from JFrame. Theres lots of reasons (your problem is a highlight of one), but you're not actually adding a new/re-usable functionality to the class and you're locking your self into a single use case. Better to start with a JPanel and add it to what ever container you want.
Don't use KeyListener, use the Key Bindings API instead. It will solve all the issues related to KeyListener, reliably
I would also avoid using "components" (like JLabel) as a game entity. You will have better luck and greater flexibility following a custom painting route
Ok, so I have this assignment that tells me to make a drawing program with buttons that can draw shape operates like "Painter" drawing program on the computer. The problem is that I can't even make the white board to appear even though I follow the code of a similar java program I found on the internet.
So here's my code:
Main class:
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Toolkit;
import javax.swing.JFrame;
public class Main
{
private static final Toolkit TOOLKIT;
static
{
TOOLKIT = Toolkit.getDefaultToolkit();
}
private Main()
{
}
public static void main(final String[] argv)
{
final ShapeFrame frame;
frame = new ShapeFrame();
position(frame);
frame.init();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
private static void position(final JFrame frame)
{
final Dimension size;
size = calculateScreenArea(0.80f,
0.80f);
frame.setSize(size);
frame.setLocation(centreOnScreen(size));
}
/**
* the amount of center on screen
* #param size space size.
* #return the complete calculated space.
*/
public static Point centreOnScreen(final Dimension size)
{
final Dimension screenSize;
if(size == null)
{
throw new IllegalArgumentException("Size cannot be null");
}
screenSize = TOOLKIT.getScreenSize();
return (new Point((screenSize.width - size.width) / 2,
(screenSize.height - size.height) / 2));
}
/**
* method that calculating screen area.
* #param widthPercent width percentage.
* #param heightPercent height percentage.
* #return dimension the dimension.
*/
public static Dimension calculateScreenArea(final float widthPercent,
final float heightPercent)
{
final Dimension screenSize;
final Dimension area;
final int width;
final int height;
final int size;
if((widthPercent <= 0.0f) || (widthPercent > 100.0f))
{
throw new IllegalArgumentException("widthPercent cannot be " +
"<= 0 or > 100 - got: " +
widthPercent);
}
if((heightPercent <= 0.0f) || (heightPercent > 100.0f))
{
throw new IllegalArgumentException("heightPercent cannot be " +
"<= 0 or > 100 - got: " +
heightPercent);
}
screenSize = TOOLKIT.getScreenSize();
width = (int)(screenSize.width * widthPercent);
height = (int)(screenSize.height * heightPercent);
size = Math.min(width,
height);
area = new Dimension(size,
size);
return (area);
}
}
my JFrame class:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Event;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
/**
* This class creates the painting program's toolbar, buttons and stuffs.
* #author Fu Han
* #version 1.0
*/
public class ShapeFrame extends JFrame implements ActionListener {
private DrawPad drawPad;
/**
* the constant string 'save'.
*/
static final private String SAVE = "Save";
/**
* the constant string 'save as'.
*/
static final private String SAVE_AS = "Save As";
/**
* the constant string 'new'.
*/
static final private String NEW = "New";
/**
* the constant string 'color'.
*/
static final private String color = "Color";
/**
* string oval for easy access for buttons.
*/
static String oval = new String("oval");
/**
* string line for easy access for buttons.
*/
static String line = new String("line");
/**
* string circle for easy access for buttons.
*/
static String circle = new String("circle");
/**
* string rectangle for easy access for buttons.
*/
static String rectangle = new String("rectangle");
/**
* string square for easy access for buttons.
*/
static String square = new String("square");
/**
* ShapeFrame constructor.
*/
public ShapeFrame(){
super();
}
/**
* method that add buttons.
* #param toolBar Jtoolbar.
* #param btn Jbuttons.
*/
protected void addButtons(JToolBar toolBar, JButton btn) {
toolBar.add(btn);
}
/**
* method that add radio buttons.
* #param toolBar Jtoolbar.
* #param btn JRadioButton.
*/
protected void addRadioButtons(JToolBar toolBar, JRadioButton btn) {
toolBar.add(btn);
}
/**
* method that creates button.
* #param btnNam button name.
* #param actionCommand calling from string constant.
* #param toolTipText the message that will appear if cursor was hover over.
* #param altText alternative text.
* #return button Jbutton.
*/
protected JButton btnmaker(String btnNam, String actionCommand, String toolTipText, String altText) {
//Create and initialize the button.
JButton button = new JButton(btnNam);
button.setActionCommand(actionCommand);
button.setToolTipText(toolTipText);
button.addActionListener(this);
return button;
}
/**
* action performed when clicked button.
* #param e mouse click.
*/
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(this, "you have clicked the button");
}
/**
* editlistener for menu bar.
* #author Fu Han
*
*/
private class EditListener implements ActionListener {
/**
* action performed when clicking menu button.
* #param e mouse click.
*/
public void actionPerformed(ActionEvent e) {
System.out.println(e.getActionCommand());
}
}
/**
* radio listener for the radio buttons.
* #author
*
*/
private class RadioListener implements ActionListener{
/**
* action performed when click the button.
* #param e mouse click.
*/
public void actionPerformed(ActionEvent e) {
String factoryName = null;
System.out.print("ActionEvent received: ");
if (e.getActionCommand() == oval) {
System.out.println(oval + " pressed.");
drawPad.setCurrentShape(oval);
}else if(e.getActionCommand() == rectangle){
System.out.println(rectangle + " pressed.");
drawPad.setCurrentShape(rectangle);
}else if(e.getActionCommand() == square){
System.out.println(square + " pressed.");
drawPad.setCurrentShape(square);
}else{
System.out.println(line + " pressed.");}
drawPad.setCurrentShape(line);
}
/**
* method for when changes happened after clicking.
* #param e mouse click.
*/
public void itemStateChanged(ItemEvent e) {
}
}
/**
* method for when changes of states that happened after clicking.
* #param e mouse click.
*/
public void stateChanged(ChangeEvent e) {
}
/**
* method for selecting color.
*/
private void selectColor(){
Color newColor = JColorChooser.showDialog(
ShapeFrame.this,
"Choose New Background Color",
Color.RED);
}
/**
* GUI initialization.
*/
public void init(){
Container content = getContentPane();
//Creates a new container
content.setLayout(new BorderLayout());
//sets the layout
final DrawPad drawPad = new DrawPad();
//creates a new padDraw, which is pretty much the paint program
content.add(drawPad, BorderLayout.CENTER);
JMenuBar menubar = new JMenuBar();
EditListener l = new EditListener();
JMenu filem = new JMenu("File");
JMenuItem mi;
mi = filem.add(new JMenuItem("New", 'n'));
mi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, Event.CTRL_MASK));
mi.addActionListener(l);
mi = filem.add(new JMenuItem("Open", 'o'));
mi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, Event.CTRL_MASK));
mi.addActionListener(l);
mi = filem.add(new JMenuItem("Save", 's'));
mi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, Event.CTRL_MASK));
mi.addActionListener(l);
mi = filem.add(new JMenuItem("Save As", 'a'));
mi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Y, Event.CTRL_MASK));
mi.addActionListener(l);
mi = filem.add(new JMenuItem("Exit", 'e'));
mi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_E, Event.CTRL_MASK));
mi.addActionListener(l);
JMenu shapem = new JMenu("Shape");
JMenuItem smi;
smi = shapem.add(new JMenuItem("Line", 'l'));
smi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z, Event.CTRL_MASK));
smi.addActionListener(l);
smi = shapem.add(new JMenuItem("Circle", 'c'));
smi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, Event.CTRL_MASK));
smi.addActionListener(l);
smi = shapem.add(new JMenuItem("Rectangle", 'r'));
smi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_U, Event.CTRL_MASK));
smi.addActionListener(l);
smi = shapem.add(new JMenuItem("Square", 'q'));
smi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_I, Event.CTRL_MASK));
smi.addActionListener(l);
smi = shapem.add(new JMenuItem("Shape Picker", 'p'));
smi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_L, Event.CTRL_MASK));
smi.addActionListener(l);
menubar.add(filem);
menubar.add(shapem);
menubar.add(Box.createHorizontalGlue());
setJMenuBar(menubar);
//Create the toolbar.
JPanel panel = new JPanel();
JPanel panel2 = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
panel2.setLayout(new BoxLayout(panel2, BoxLayout.Y_AXIS));
JButton saveBtn = btnmaker("Save",SAVE, "save your paint", "Save");
JButton saveAsBtn = btnmaker("Save As",SAVE_AS, "save your paint to?","Save As");
JButton NewBtn = btnmaker("New",NEW,"new paint","New");
JButton colorbtn = btnmaker("Color",color,"choose color","Color");
colorbtn.setToolTipText("Click this button to select colors.");
colorbtn.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent arg) {
selectColor();
}
});
RadioListener myListener = new RadioListener();
JRadioButton ovalShape = new JRadioButton(oval);
ovalShape.addActionListener(myListener);
ovalShape.setMnemonic(KeyEvent.VK_A);
ovalShape.setActionCommand(oval);
ovalShape.setSelected(true);
add(ovalShape);
JRadioButton rectangleShape = new JRadioButton(rectangle);
rectangleShape.addActionListener(myListener);
rectangleShape.setMnemonic(KeyEvent.VK_A);
rectangleShape.setActionCommand(rectangle);
rectangleShape.setSelected(true);
add(rectangleShape);
JRadioButton squareShape = new JRadioButton(square);
squareShape.addActionListener(myListener);
squareShape.setMnemonic(KeyEvent.VK_A);
squareShape.setActionCommand(square);
squareShape.setSelected(true);
add(squareShape);
JRadioButton lineShape = new JRadioButton(line);
lineShape.addActionListener(myListener);
lineShape.setMnemonic(KeyEvent.VK_B);
lineShape.setActionCommand(line);
add(lineShape);
ButtonGroup group = new ButtonGroup();
group.add(ovalShape);
group.add(lineShape);
group.add(rectangleShape);
group.add(squareShape);
JToolBar toolBar = new JToolBar("File");
JToolBar toolBar2 = new JToolBar("Shape",JToolBar.VERTICAL);
JToolBar toolbar3 = new JToolBar("colors",JToolBar.VERTICAL);
addButtons(toolBar,saveBtn);
addButtons(toolBar,saveAsBtn);
addButtons(toolBar,NewBtn);
addRadioButtons(toolBar2,ovalShape);
addRadioButtons(toolBar2,lineShape);
addRadioButtons(toolBar2,rectangleShape);
addRadioButtons(toolBar2,squareShape);
addButtons(toolbar3,colorbtn);
panel.add(toolBar);
panel2.add(toolBar2);
panel2.add(toolbar3);
content.add(panel, BorderLayout.NORTH);
content.add(panel2, BorderLayout.WEST);
}
}
the DrawPad class:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JComponent;
public class DrawPad extends JComponent{
Image image;
//this is gonna be your image that you draw on
Graphics2D graphics2D;
Shape shape;
//this is what we'll be using to draw on
int currentX, currentY, oldX, oldY;
//these are gonna hold our mouse coordinates
String currentShape;
public String getCurrentShape() {
return currentShape;
}
public void setCurrentShape(String currentShape) {
this.currentShape = currentShape;
}
//Now for the constructors
public DrawPad(){
setDoubleBuffered(false);
addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent e){
if(currentShape != null){
if(currentShape == "rectangle"){
shape = new Rectangle();
}else if(currentShape == "oval"){
shape = new Oval();
}else if(currentShape == "line"){
shape = new Line();
}else{
shape = new Square();
}
shape.setPoint1(e.getPoint());
shape.setColor(Color.black);
}
}
});
//if the mouse is pressed it sets the oldX & oldY
//coordinates as the mouses x & y coordinates
addMouseMotionListener(new MouseMotionAdapter(){
public void mouseDragged(MouseEvent e){
shape.setPoint2(e.getPoint());
}
});
}
public void paintComponent(Graphics g){
//shape.Draw(g);
if(image == null){
image = createImage(getSize().width, getSize().height);
graphics2D = (Graphics2D)image.getGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
clear();
}
g.drawImage(image, 0, 0, null);
}
//this is the painting bit
//if it has nothing on it then
//it creates an image the size of the window
//sets the value of Graphics as the image
//sets the rendering
//runs the clear() method
//then it draws the image
public void clear(){
graphics2D.setPaint(Color.white);
graphics2D.fillRect(0, 0, getSize().width, getSize().height);
graphics2D.setPaint(Color.black);
repaint();
}
}
and here is the painter program that I look up to:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JComponent;
class PadDraw extends JComponent{
Image image;
//this is gonna be your image that you draw on
Graphics2D graphics2D;
//this is what we'll be using to draw on
int currentX, currentY, oldX, oldY;
//these are gonna hold our mouse coordinates
//Now for the constructors
public PadDraw(){
setDoubleBuffered(false);
addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent e){
oldX = e.getX();
oldY = e.getY();
}
});
//if the mouse is pressed it sets the oldX & oldY
//coordinates as the mouses x & y coordinates
addMouseMotionListener(new MouseMotionAdapter(){
public void mouseDragged(MouseEvent e){
currentX = e.getX();
currentY = e.getY();
if(graphics2D != null)
graphics2D.drawLine(oldX, oldY, currentX, currentY);
repaint();
oldX = currentX;
oldY = currentY;
}
});
//while the mouse is dragged it sets currentX & currentY as the mouses x and y
//then it draws a line at the coordinates
//it repaints it and sets oldX and oldY as currentX and currentY
}
public void paintComponent(Graphics g){
if(image == null){
image = createImage(getSize().width, getSize().height);
graphics2D = (Graphics2D)image.getGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
clear();
}
g.drawImage(image, 0, 0, null);
}
//this is the painting bit
//if it has nothing on it then
//it creates an image the size of the window
//sets the value of Graphics as the image
//sets the rendering
//runs the clear() method
//then it draws the image
public void clear(){
graphics2D.setPaint(Color.white);
graphics2D.fillRect(0, 0, getSize().width, getSize().height);
graphics2D.setPaint(Color.black);
repaint();
}
//this is the clear
//it sets the colors as white
//then it fills the window with white
//thin it sets the color back to black
public void red(){
graphics2D.setPaint(Color.red);
repaint();
}
//this is the red paint
public void black(){
graphics2D.setPaint(Color.black);
repaint();
}
//black paint
public void magenta(){
graphics2D.setPaint(Color.magenta);
repaint();
}
//magenta paint
public void blue(){
graphics2D.setPaint(Color.blue);
repaint();
}
//blue paint
public void green(){
graphics2D.setPaint(Color.green);
repaint();
}
//green paint
}
main method for the drawing program:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class paint{
public static void main(String[] args){
Icon iconB = new ImageIcon("blue.gif");
//the blue image icon
Icon iconM = new ImageIcon("magenta.gif");
//magenta image icon
Icon iconR = new ImageIcon("red.gif");
//red image icon
Icon iconBl = new ImageIcon("black.gif");
//black image icon
Icon iconG = new ImageIcon("green.gif");
//finally the green image icon
//These will be the images for our colors.
JFrame frame = new JFrame("Paint It");
//Creates a frame with a title of "Paint it"
Container content = frame.getContentPane();
//Creates a new container
content.setLayout(new BorderLayout());
//sets the layout
final PadDraw drawPad = new PadDraw();
//creates a new padDraw, which is pretty much the paint program
content.add(drawPad, BorderLayout.CENTER);
//sets the padDraw in the center
JPanel panel = new JPanel();
//creates a JPanel
panel.setPreferredSize(new Dimension(32, 68));
panel.setMinimumSize(new Dimension(32, 68));
panel.setMaximumSize(new Dimension(32, 68));
//This sets the size of the panel
JButton clearButton = new JButton("Clear");
//creates the clear button and sets the text as "Clear"
clearButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
drawPad.clear();
}
});
//this is the clear button, which clears the screen. This pretty
//much attaches an action listener to the button and when the
//button is pressed it calls the clear() method
JButton redButton = new JButton(iconR);
//creates the red button and sets the icon we created for red
redButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
drawPad.red();
}
});
//when pressed it will call the red() method. So on and so on =]
JButton blackButton = new JButton(iconBl);
//same thing except this is the black button
blackButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
drawPad.black();
}
});
JButton magentaButton = new JButton(iconM);
//magenta button
magentaButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
drawPad.magenta();
}
});
JButton blueButton = new JButton(iconB);
//blue button
blueButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
drawPad.blue();
}
});
JButton greenButton = new JButton(iconG);
//green button
greenButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
drawPad.green();
}
});
blackButton.setPreferredSize(new Dimension(16, 16));
magentaButton.setPreferredSize(new Dimension(16, 16));
redButton.setPreferredSize(new Dimension(16, 16));
blueButton.setPreferredSize(new Dimension(16, 16));
greenButton.setPreferredSize(new Dimension(16,16));
//sets the sizes of the buttons
panel.add(greenButton);
panel.add(blueButton);
panel.add(magentaButton);
panel.add(blackButton);
panel.add(redButton);
panel.add(clearButton);
//adds the buttons to the panel
content.add(panel, BorderLayout.WEST);
//sets the panel to the left
frame.setSize(500, 500);
//sets the size of the frame
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//makes it so you can close
frame.setVisible(true);
//makes it so you can see it
}
}
Problem #1
Maintaining a reference to the Graphics context and painting outside of a paint cycle. Never maintain a reference to a Graphics context that you did not create yourself. Never paint to a component's Graphics context outside of the paintComponent method call. Painting is destructive, anything drawn to the Graphics context outside of the paint cycle will be lost
Problem #2
Breaking the paint chain. Unless you a VERY good reason to do otherwise, you should always call super.paintComponent BEFORE you perform any custom painting. Also paintComponent never needs to be public, no one should ever be calling it...
Problem #3
currentShape == "line" is not how String comparison works. Use "line".equals(currentShape) instead...
Problem #4
setDoubleBuffered(false);...this just means a lot more work for you...paint to the Graphics context which is passed to the paintComponent, WHEN it's passed to the paintComponent method...
Problem #5
Beware of what you are adding what to...
Container content = getContentPane();
content.setLayout(new BorderLayout());
final DrawPad drawPad = new DrawPad();
content.add(drawPad, BorderLayout.CENTER);
//...
//Create the toolbar.
JPanel panel = new JPanel();
JPanel panel2 = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
panel2.setLayout(new BoxLayout(panel2, BoxLayout.Y_AXIS));
//...
// What do you think this is been added to?
add(ovalShape);
//...
// What do you think this is been added to?
add(rectangleShape);
//...
// What do you think this is been added to?
add(squareShape);
//...
// What do you think this is been added to?
add(lineShape);
//...
panel.add(toolBar);
panel2.add(toolBar2);
panel2.add(toolbar3);
content.add(panel, BorderLayout.NORTH);
content.add(panel2, BorderLayout.WEST);
BorderLayout will only show the last item that was added to any of it's five available slots...which would, in this case, lineShape...
Take a look at...
Painting in AWT and Swing
Performing Custom Painting
Recommendations
Prototype small elements of your problem, understand how the work in isolation and then figure out how to plug them into a large set of functionality...
I'm still very new to java programming, so please help me to correct any mistakes I might have overlooked or give tips on how to improve this program.
Okay, so a lot of problems have been solved, and now I have a CardLayout, but I still have questions about how I should make my pipes show inside it.
When I tried to add in my refresh rate timer and my speed timer, I have problems about how I need to declare and initialize boolean variables.
Also, when I compile and run this game, I get files such as Game$1.class. Is there a way for me to clean this up, and could someone explain why this happens? Do these have an affect on the finished product? (When the game is compiled and packaged into a JAR.)
I want to set playerIsReady to true when the play button is clicked. And from there, when the if statement is true, then switch to a panel that displays the pipes, and start moving the pipe across the screen. Preferably 3 instances of that pipe, each starting at different times, but whatever you can help with is fine.
Some of this code needs work, so I have commented some parts out and left notes.
My other questions about this game can be found here.
This is my current code
Game.java
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.border.EmptyBorder;
import javax.swing.SwingUtilities;
public class Game {
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
// the GUI as seen by the user (without frame)
final CardLayout cl = new CardLayout();
final JPanel gui = new JPanel(cl);
// remove if no border is needed
gui.setBorder(new EmptyBorder(10,10,10,10));
JPanel menu = new JPanel(new GridBagLayout());
JButton playGame = new JButton("Play!");
ActionListener playGameListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
cl.show(gui, "game");
}
};
playGame.addActionListener(playGameListener);
Insets margin = new Insets(20, 50, 20, 50);
playGame.setMargin(margin);
menu.add(playGame);
gui.add(menu);
cl.addLayoutComponent(menu, "menu");
final JPanel pipes = new Pipes();
gui.add(pipes);
cl.addLayoutComponent(pipes, "game");
JFrame f = new JFrame("Pipes Game");
f.add(gui);
// Ensures JVM closes after frame(s) closed and
// all non-daemon threads are finished
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
// See https://stackoverflow.com/a/7143398/418556 for demo.
f.setLocationByPlatform(true);
// ensures the frame is the minimum size it needs to be
// in order display the components within it
f.pack();
// should be done last, to avoid flickering, moving,
// resizing artifacts.
f.setVisible(true);
/*if (playerIsReady) {
Timer speed = new Timer(10, new ActionListener() { //pipe speed
#Override
public void actionPerformed(ActionEvent e) {
pipes.move();
}
});
speed.start();
Timer refresh = new Timer(30, new ActionListener() { //refresh rate
#Override
public void actionPerformed(ActionEvent e) {
pipes.repaint();
}
});
refresh.start();
}*/
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency
SwingUtilities.invokeLater(r);
}
}
Pipes.java
// What import(s) do I need for ArrayList?
public class Pipes {
List<Pipe> pipes = new ArrayList<Pipe>();
public Pipes() {
pipes.add(new Pipe(50, 100));
pipes.add(new Pipe(150, 100));
pipes.add(new Pipe(250, 100));
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for ( Pipe pipe : pipes ){
pipe.drawPipe(g);
}
}
}
PipeObject.java
import java.awt.Graphics;
public class PipeObject {
//Declare and initialiaze variables
int x1 = 754; //xVal start
int x2 = 75; //pipe width
//total width is 83
int y1 = -1; //yVal start
int y2 = setHeightVal(); //pipe height
int gap = 130; //gap height
public void drawPipe(Graphics g) {
g.clearRect(0,0,750,500); //Clear screen
g.drawRect(x1,y1,x2,y2); //Draw part 1
g.drawRect(x1-3,y2-1,x2+6,25); //Draw part 2
g.drawRect(x1-3,y2+25+gap,x2+6,25); //Draw part 3
g.drawRect(x1,y2+25+gap+25,x2,500-y2-49-gap); //Draw part 4
}
public void move() {
x1--;
}
public int getMyX() { //To determine where the pipe is horizontally
return x1-3;
}
public int getMyY() { //To determine where the pipe is vertically
return y2+25;
}
public int setHeightVal() { //Get a random number and select a preset height
int num = (int)(9*Math.random() + 1);
int val = 0;
if (num == 9)
{
val = 295;
}
else if (num == 8)
{
val = 246;
}
else if (num == 7)
{
val = 216;
}
else if (num == 6)
{
val = 185;
}
else if (num == 5)
{
val = 156;
}
else if (num == 4)
{
val = 125;
}
else if (num == 3)
{
val = 96;
}
else if (num == 2)
{
val = 66;
}
else
{
val = 25;
}
return val;
}
}
The best way to approach this is using a CardLayout.
Notes
A button with an ActionListener is far better than a MouseListener over a rectangle.
The button will show focus when the mouse is pointed at it, or the component is tabbed to via the keyboard.
The button is keyboard accessible.
The button has facility to support multiple icons built in (e.g. for 'initial look', focused, pressed etc.)
White space in the GUI is provided around the menu panel and game by adding an EmptyBorder
The button is made larger by setting a margin.
Adjust margins, borders and preferred size according to need. These sizes were set by me so as not to make the screenshots too large.
See more tips in the code comments.
Code
Here is the MCTaRE (Minimal Complete Tested and Readable Example) that produced the above screenshots.
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class PipesGame {
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
// the GUI as seen by the user (without frame)
final CardLayout cl = new CardLayout();
final JPanel gui = new JPanel(cl);
// remove if no border is needed
gui.setBorder(new EmptyBorder(10,10,10,10));
JPanel menu = new JPanel(new GridBagLayout());
JButton playGame = new JButton("Play!");
ActionListener playGameListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
cl.show(gui, "game");
}
};
playGame.addActionListener(playGameListener);
Insets margin = new Insets(20, 50, 20, 50);
playGame.setMargin(margin);
menu.add(playGame);
gui.add(menu);
cl.addLayoutComponent(menu, "menu");
JPanel pipes = new Pipes();
gui.add(pipes);
cl.addLayoutComponent(pipes, "game");
JFrame f = new JFrame("Pipes Game");
f.add(gui);
// Ensures JVM closes after frame(s) closed and
// all non-daemon threads are finished
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
// See https://stackoverflow.com/a/7143398/418556 for demo.
f.setLocationByPlatform(true);
// ensures the frame is the minimum size it needs to be
// in order display the components within it
f.pack();
// should be done last, to avoid flickering, moving,
// resizing artifacts.
f.setVisible(true);
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency
SwingUtilities.invokeLater(r);
}
}
class Pipes extends JPanel {
Pipes() {
setBackground(Color.BLACK);
setForeground(Color.WHITE);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawString("Pipes game appears here..", 170, 80);
}
#Override
public Dimension getPreferredSize() {
// adjust to need
return new Dimension(500,150);
}
}
"Is there a way for me to add my GameMenu jpanel to my jframe, and then replace it with the Pipes jpanel?"
As other have suggested, for this you want a CardLayout. It is very simple to you. Personally, I always wrap my CardLayout in a JPanel rather than the JFrame, just force of habit.
What you want to do is have a mainPanel that will have the CardLayout
CardLayout card = new CardLayout();
JPanel mainPanel = new JPanel();
Then you want to add your panels to the mainPanel. What the CardLyaout does is layer the panels, making just one visible at a time. The first one you add, will the in the foreground. Also when you add the panel, you'll also want to issue it a key it can be called from. The key, can be any String you like.
mainPanel.add(gameMenu, "menu");
mainPnael.add(pipes, "pipe");
Now gameMenu is the only panel shown. To show pipes, all you do is use this method
public void show(Container parent, String name) - Flips to the parent that was added to this layout with the specified name, using addLayoutComponent. If no such component exists, then nothing happens.
So you'd use, card.show(mainPanel, "pipes");
Whatever even you want to trigger the showing of pipes, just add that line in that event handler. You could add a button or something to the GameMenu that will allow movement to the Pipes panel.
This works with a mouse click on the menu. You can change it later, to a click on some button or whatever you want.
I added a MouseListener to the Game class. When the user presses the mouse on the menu JPanel, it adds the Pipes JPanel to JFrame and calls the pack method.
Game.java:
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Game {
GameMenu menu = new GameMenu();
Pipes game;
boolean start = false;
JFrame f;
Rectangle2D menuRect = new Rectangle2D.Double(20, 20, 60, 40);
public Game() {
f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(menu);
f.setTitle("Pipe Game");
f.setResizable(false);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
menu.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
Point click = new Point(e.getX(), e.getY());
System.out.println("Clicked on the Panel");
if(menuRect.contains(click))
{
System.out.println("Clicked inside the Rectangle.");
start = true;
menu.setVisible(false);
game = new Pipes();
f.add(game);
f.pack();
Timer timer = new Timer(10, new ActionListener() { //pipe speed
#Override
public void actionPerformed(ActionEvent e) {
game.move();
}
});
timer.start();
Timer refresh = new Timer(30, new ActionListener() { //refresh rate
#Override
public void actionPerformed(ActionEvent e) {
game.repaint();
}
});
refresh.start();
}
}
#Override
public void mouseReleased(MouseEvent e) {
}
});
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Game();
}
});
}
}