MAJOR EDIT: I have tried a different approach with 1 class and implementation of Runnable to try and print the "moles". I no longer have a second class. The new issue is making the BufferedImage userInterface print at the desired coordinates, then printing "moles" randomly at the correct coordinates. The mole should disappear when the next mole is drawn.
Current Problems:
If the userInterface is alone (no for-loop that is seen below it in the code) then it will appear. If I change the coordinates from 0,0 then it no longer appears.
When I added the for-loop that prints the "moles" (a.k.a mario, hence Whack-A-Mario) then the userInterface ceases to appear at all even if its coords are still 0,0 AND the moles get printed at the random coordinates. The problem here is that the UI no longer appears and the marios keep being printed without the previous ones disappearing.
I am programming a Whack-A-Mole game for my computer programming class, however, I have been having quite a bit of trouble making the images of "moles" appear and disappear.
First, I do not want to use any sort of JButton system for the moles. I have seen it used but I want to use my .png's if possible.
Second, I have concluded that I do not know what I am doing. A major problem is that I also do not really know how to organize the program. The moles will be appearing at a slowly increasing rate and the character will be clicking on the screen. If the user's mouse click is within the area of one of the moles when they are up, the user's score will increase. I have no idea if I should one class or two classes (I have seen people do it in one). I don't exactly know what I am going to do about the updating score either. I want the score to update independently from the repainting of the moles too.
Note: The BufferedImage mario is called mario because I am making "Wack-A-Mario". The moles are images of Mario I drew and the music/effects will all be from Mario. Also please excuse my horrid imports. They have increased over the past couple hours as I tried various things. I no longer know what does what and they will be cleaned up.
Main Class:
import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import java.awt.Color;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.util.*;
import java.awt.event.*;
import java.lang.reflect.*;
import javax.imageio.*;
import java.io.*;
import java.awt.image.*;
import javax.swing.Timer;
public class WhackAMario extends JFrame implements Runnable
{
int xCoord[] = new int[] {25, 171, 317, 463, 609, 25, 171, 317, 463, 609, 25, 171, 317, 463, 609, 25, 171, 317, 463, 609};
int yCoord[] = new int[] {275, 275, 275, 275, 275, 395, 395, 395, 395, 395, 515, 515, 515, 515, 515, 635, 635, 635, 635, 635,};
Random coordGen = new Random();
int x,y,element;
BufferedImage userInterface, mario;
private Thread thread;
private static JFrame frame = new JFrame();
private static Graphics g;
private static Graphics2D g2;
public void randomCoord()
{
element = coordGen.nextInt(20);
x = xCoord[element];
y = yCoord[element];
}
public void run()
{
g = frame.getGraphics();
try
{
userInterface = ImageIO.read(new File("UserInterface.png"));
}
catch(IOException e)
{
e.printStackTrace();
}
g.drawImage(userInterface, 0, 0, null);
for(int i=0; i<25; i++)
{
randomCoord();
try
{
mario = ImageIO.read(new File("Mario Up.png"));
}
catch(IOException e)
{
e.printStackTrace();
}
g.drawImage(mario, x, y, null);
try
{
Thread.sleep(1000);
repaint();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
public static void main(String[] args)
{
final WhackComponent whackComponent = new WhackComponent();
class Mouse implements MouseListener
{
public void mouseEntered(MouseEvent e)
{
}
public void mouseExited(MouseEvent e)
{
}
public void mousePressed(MouseEvent e)
{
}
public void mouseReleased(MouseEvent e)
{
}
public void mouseClicked(MouseEvent e)
{
}
}
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(796, 818);
frame.setVisible(true);
WhackAMario whack = new WhackAMario();
whack.thread = new Thread(whack);
whack.thread.start();
MouseListener listener = new Mouse();
frame.addMouseListener(listener);
//Timer t = new Timer(100, whackComponent);
//t.start();
//
// ImageIcon img = new ImageIcon("Hole.png");
// JLabel label1 = new JLabel(img);
// JPanel panel = new JPanel();
// panel.setLayout(null);
//
// label1.setLocation(400, 400);
//frame.add(label1);
//frame.setVisible(true);
}
}
Main Class Before "MAJOR EDIT"
import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import java.awt.Color;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.util.*;
import java.awt.event.*;
import java.lang.reflect.*;
import javax.imageio.*;
import java.io.*;
import java.awt.image.*;
import javax.swing.Timer;
public class WhackAMario extends JFrame implements Runnable
{
int xCoord[] = new int[] {25, 171, 317, 463, 609, 25, 171, 317, 463, 609, 25, 171, 317, 463, 609, 25, 171, 317, 463, 609};
int yCoord[] = new int[] {275, 275, 275, 275, 275, 395, 395, 395, 395, 395, 515, 515, 515, 515, 515, 635, 635, 635, 635, 635,};
Random coordGen = new Random();
int x,y,element;
BufferedImage userInterface, mario;
private Thread thread;
private static JFrame frame = new JFrame();
private static Graphics g;
private static Graphics2D g2;
public void randomCoord()
{
element = coordGen.nextInt(20);
x = xCoord[element];
y = yCoord[element];
}
public void run()
{
g = frame.getGraphics();
// try
// {
// userInterface = ImageIO.read(new File("UserInterface.png"));
// }
// catch(IOException e)
// {
// e.printStackTrace();
// }
// g.drawImage(userInterface, 0, 50, null);
// for(int i=0; i<25; i++)
// {
// randomCoord();
// try
// {
// mario = ImageIO.read(new File("Mario Up.png"));
// }
// catch(IOException e)
// {
// e.printStackTrace();
// }
// g.drawImage(mario, x, y, null);
// try
// {
// Thread.sleep(1000);
// repaint();
// }
// catch (InterruptedException e)
// {
// e.printStackTrace();
// }
// }
}
public static void main(String[] args)
{
final WhackComponent whackComponent = new WhackComponent();
class Mouse implements MouseListener
{
public void mouseEntered(MouseEvent e)
{
}
public void mouseExited(MouseEvent e)
{
}
public void mousePressed(MouseEvent e)
{
}
public void mouseReleased(MouseEvent e)
{
}
public void mouseClicked(MouseEvent e)
{
}
}
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(796, 818);
frame.setVisible(true);
frame.add(whackComponent);
// WhackAMario whack = new WhackAMario();
// whack.thread = new Thread(whack);
// whack.thread.start();
MouseListener listener = new Mouse();
frame.addMouseListener(listener);
//Timer t = new Timer(100, whackComponent);
//t.start();
//
// ImageIcon img = new ImageIcon("Hole.png");
// JLabel label1 = new JLabel(img);
// JPanel panel = new JPanel();
// panel.setLayout(null);
//
// label1.setLocation(400, 400);
//frame.add(label1);
//frame.setVisible(true);
}
}
Component Class:
import java.awt.*;
import javax.swing.*;
import java.util.*;
import javax.imageio.*;
import java.io.*;
import java.awt.image.*;
import java.awt.event.*;
import java.util.concurrent.TimeUnit;
public class WhackComponent extends JComponent
{
int xCoord[] = new int[] {25, 171, 317, 463, 609, 25, 171, 317, 463, 609, 25, 171, 317, 463, 609, 25, 171, 317, 463, 609};
int yCoord[] = new int[] {275, 275, 275, 275, 275, 395, 395, 395, 395, 395, 515, 515, 515, 515, 515, 635, 635, 635, 635, 635,};
BufferedImage userInterface, mario;
Random coordGen = new Random();
Thread thread;
int element;
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
try
{
userInterface = ImageIO.read(new File("UserInterface.png"));
}
catch(IOException e)
{
e.printStackTrace();
}
g2.drawImage(userInterface, null, 0, 0);
for(int i=0; i<25; i++)
{
element = coordGen.nextInt(20);
try
{
mario = ImageIO.read(new File("Mario Up.png"));
}
catch(IOException e)
{
e.printStackTrace();
}
g2.drawImage(mario, null, xCoord[element], yCoord[element]);
try
{
Thread.sleep(1);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
public void enterMove()
{
}
public void releaseMove()
{
}
public void actionPerformed(ActionEvent event)
{
}
}
It's supposed to work this way: you provide the drawing logic inside paintComponent(Graphics) and the system will call you back when it detects the screen needs to be refreshed. In Swing applications the trigger is tipically the user interacting with the computer, for example by pressing a key or clicking the mouse, while in your application you need a game engine with its own main loop, that shows/hides moles, interacts with the music engine and processes input events depending on the state of the world. In Swing, layout hierarchies are invalidated with a call to .invalidate().
Note that JButton's and others Swing components are just a convenient way for you to draw things (especially wrt screen size with the help of layout managers) and process events, but you can certainly program a simple game by using a single JComponent like in your example (I think this may help)
Random tip: paintComponent must be fast, and I mean really fast, so you can't read a PNG from the filesystem and convert it to a bitmap. The loading must occur exactly one time when the game is initialized
Related
I am trying to program a basic 2d shooter game, I took the code from an open source project and edited it to fit my criteria but now when I try to run the game from the main menu window, the game screen open but doesn't take any input anymore and the game wont start without pressing a button.
this is the code for the game loop and the home menu:
`
public void gameLoop() {
long lastLoopTime = System.currentTimeMillis();
// keep looping round til the game ends
while (gameRunning) {
// work out how long its been since the last update, this
// will be used to calculate how far the entities should
// move this loop
long delta = System.currentTimeMillis() - lastLoopTime;
lastLoopTime = System.currentTimeMillis();
// Get hold of a graphics context for the accelerated
// surface and blank it out
Graphics2D g = (Graphics2D) strategy.getDrawGraphics();
g.setColor(Color.blue);
g.fillRect(0,0,800,600);
Random rd = new Random(); // creating Random object
boolean dir = rd.nextBoolean();
// cycle round asking each entity to move itself
if (!waitingForKeyPress) {
for (int i=0;i<entities.size();i++) {
Entity entity = (Entity) entities.get(i);
if(entity instanceof AlienEntity) {
if(entity.getX() <= 10 || entity.getY() <= 0 || entity.getX() >= 800) {
removeEntity(entity);
initAliens();
}
}
entity.move(delta,dir);
}
}
// cycle round drawing all the entities we have in the game
for (int i=0;i<entities.size();i++) {
Entity entity = (Entity) entities.get(i);
entity.draw(g);
}
// brute force collisions, compare every entity against
// every other entity. If any of them collide notify
// both entities that the collision has occured
for (int p=0;p<entities.size();p++) {
for (int s=p+1;s<entities.size();s++) {
Entity me = (Entity) entities.get(p);
Entity him = (Entity) entities.get(s);
if (me.collidesWith(him)) {
me.collidedWith(him);
him.collidedWith(me);
initAliens();
score++;
scoreLabel.setText("Score="+Integer.toString(score));
}
}
}
// remove any entity that has been marked for clear up
entities.removeAll(removeList);
removeList.clear();
// if a game event has indicated that game logic should
// be resolved, cycle round every entity requesting that
// their personal logic should be considered.
if (logicRequiredThisLoop) {
for (int i=0;i<entities.size();i++) {
Entity entity = (Entity) entities.get(i);
entity.doLogic();
}
logicRequiredThisLoop = false;
}
// if we're waiting for an "any key" press then draw the
// current message
if (waitingForKeyPress) {
g.setColor(Color.white);
g.drawString(message,(800-g.getFontMetrics().stringWidth(message))/2,250);
g.drawString("Press any key to start, and click X to go back to main menu",(800-g.getFontMetrics().stringWidth("Press any key to start, and click X to go back to main menu"))/2,300);
}
// finally, we've completed drawing so clear up the graphics
// and flip the buffer over
g.dispose();
strategy.show();
// resolve the movement of the ship. First assume the ship
// isn't moving. If either cursor key is pressed then
// update the movement appropraitely
ship.setHorizontalMovement(0);
if ((leftPressed) && (!rightPressed)) {
ship.setHorizontalMovement(-moveSpeed);
} else if ((rightPressed) && (!leftPressed)) {
ship.setHorizontalMovement(moveSpeed);
}
// if we're pressing fire, attempt to fire
if (firePressed) {
tryToFire();
}
// finally pause for a bit. Note: this should run us at about
// 100 fps but on windows this might vary each loop due to
// a bad implementation of timer
try { Thread.sleep(10); } catch (Exception e) {}
}
}
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferStrategy;
import java.nio.channels.IllegalBlockingModeException;
import java.util.ArrayList;
import java.util.Random;
import java.util.Timer;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.security.auth.x500.X500Principal;
import javax.swing.JButton;
import javax.swing.JLabel;
import java.awt.Font;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class Home extends JFrame {
private JPanel contentPane;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Home frame = new Home("ddd",1);
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public Home(String username, int highscore) {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
JButton btnNewButton = new JButton("Play");
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Game game = new Game();
game.main(null);
}
});
btnNewButton.setFont(new Font("Times New Roman", Font.BOLD, 17));
btnNewButton.setBounds(107, 118, 111, 55);
contentPane.add(btnNewButton);
JLabel lblNewLabel = new JLabel(username);
lblNewLabel.setFont(new Font("Times New Roman", Font.BOLD, 15));
lblNewLabel.setBounds(140, 11, 196, 36);
contentPane.add(lblNewLabel);
JLabel lblNewLabel_1 = new JLabel("HighScore = " + Integer.toString(highscore));
lblNewLabel_1.setFont(new Font("Times New Roman", Font.BOLD, 15));
lblNewLabel_1.setBounds(10, 10, 120, 36);
contentPane.add(lblNewLabel_1);
JButton btnNewButton_1 = new JButton("Change Password");
btnNewButton_1.setFont(new Font("Times New Roman", Font.BOLD, 13));
btnNewButton_1.setBounds(228, 118, 141, 55);
contentPane.add(btnNewButton_1);
JButton btnNewButton_2 = new JButton("Quit");
btnNewButton_2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
btnNewButton_2.setBounds(341, 232, 85, 21);
contentPane.add(btnNewButton_2);
}
}
`
I tried creating a new instance of game and calling the main function but it didn't work, I also tried calling a normal function, I tried calling the gameloop itself on the game instance but it didn't work.
The screen renders everything in the right place but the entire screen flickers while it's open. If I don't add "g.drawImage(img,0,0,null);" then it works fine. I know that maybe I have to use double buffering,but I work with Swing first time and don't have any ideas how to use double buffering correctly. "setDoubleBuffered(true)" doesn't work. Thank you in advance.
import java.awt.*;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.*;
public class GraphApp extends JFrame {
int x,y;
int ax,by;
Image img = Toolkit.getDefaultToolkit().getImage("C:\\Users\\User\\IdeaProjects\\vychmat\\images\\Background.png");
public GraphApp(){
setTitle("Лабораторная работа №2");
setSize(900,700);
try{
setIconImage(ImageIO.read(new File("C:\\Users\\User\\IdeaProjects\\vychmat\\images\\icon.png")));
}
catch(Exception e){
e.getMessage();
}
setVisible(true);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void paint(Graphics g){
g.drawImage(img,0,0,null);
g.setColor(Color.BLACK);
g.drawString("Y", 210, 250);
g.drawString("X", 390, 440);
if(x==205&&y==425){
g.drawString("Origin(0,0)", 205, 425);
}
//OY
g.drawLine(200, 250, 200, 600);
//OX
g.drawLine(30,425,380,425);
g.setFont(new Font("Palatino Linotype", Font.BOLD,25));
g.drawString("Решение уравнений с заданной точностью",150,75);
repaint();
}
public static void main(String[] args){
new GraphApp();
}
}
So, I need to make the stick-man movable by a user-input. When the user clicks on a part (Head, hands, feet and posterior) and he should move, and have no idea how to go about this..
If possible, there also needs to be a confine around the character, likely rectangular, so that there is a limit to how far each part can be pulled.
See below for my code;
// Created by Charlie Carr - (28/11/17 - /11/17)
import java.awt.*;
import java.applet.Applet;
import javax.swing.*;
import java.awt.Graphics;
import java.awt.geom.*;
import java.awt.image.BufferedImage;
//Imports complete
//Suppress warning about undeclared static final serialVersionUID field in VS Code
#SuppressWarnings("serial")
public class Animator extends JPanel {
public static class AnimatorWindow extends JPanel {
public void paint(Graphics page) {
setBackground(Color.gray);
setForeground(Color.white);
super.paintComponent(page);
page.drawString("Stickmen Animation Station", 150, 15);
//draw the head
//x1, y1, x2, y2
page.drawOval(90, 60, 20, 20);
// draw the body
page.drawLine(100, 80, 100, 110);
// draw the hands
page.drawLine(100, 90, 80, 105);
page.drawLine(100, 90, 120, 105);
//draw the legs, he hasn't a leg to stand on..
page.drawLine(100, 110, 85, 135);
page.drawLine(100, 110, 115, 135);
}
}
public static void main(String[] args) {
AnimatorWindow displayPanel = new AnimatorWindow();
JPanel content = new JPanel();
content.setLayout(new BorderLayout());
content.add(displayPanel, BorderLayout.CENTER);
//declare window size
int x = 480;
int y = 240;
JFrame window = new JFrame("GUI");
window.setContentPane(content);
window.setSize(x, y);
window.setLocation(101, 101);
window.setVisible(true);
}
}
Use MouseListenerto deal with mouse events.
Also, you should override the paintComponent() method instead of paint(), because paint() also paints the border and other stuff.
public static class AnimatorWindow extends JPanel implements MouseListener{
public AnimatorWindow(){
setBackground(Color.gray);
setForeground(Color.white);
//add the listener
addMouseListener(this);
}
public void paintComponent(Graphics page) {
super.paintComponent(page);
//You should not alter the Graphics object passed in
Graphics2D g = (Graphics2D) page.create();
//draw your stuff with g
g.drawString("Stickmen Animation Station", 150, 15);
.......
//finish
g.dispose();
}
public void mouseEntered(MouseEvent e){}
public void mouseExited(MouseEvent e){}
public void mousePressed(MouseEvent e){}
public void mouseReleased(MouseEvent e){}
public void mouseClicked(MouseEvent e){
//implement your clicking here
//Use e.getX() and e.getY() to get the click position
}
}
For more on swing events, check this site
EDIT: Your problem also includes animation, and you can use a javax.swing.Timer to do that.
I'm making a program where hovering over a grid will place an image into the cell hovered over. Currently I have it working so that only a color is filled in, but I have no idea how to make it so an image is drawn in instead. Here's my program:
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.List;
import javax.swing.*;
public class Test
{
Image img=Toolkit.getDefaultToolkit().getImage("img.gif");
public static void main(String[]args)
{
new Test();
}
public Test()
{
JFrame frame=new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new PixelGrid());
frame.setSize(new Dimension(364,357));
frame.setVisible(true);
}
public class PixelGrid extends JPanel
{
private List<Shape>grid,square;
public PixelGrid()
{
grid=new ArrayList<>();
square=new ArrayList<>();
addMouseMotionListener(new MouseAdapter()
{
public void mouseMoved(MouseEvent e)
{
for(Shape shape:grid)
{
if(shape.contains(e.getPoint()))
square.add(shape);
}
repaint();
}
}
);
for(int row=0;row<5;row++)
{
for(int col=0;col<5;col++)
grid.add(new Rectangle(col*25+112,row*25+50,25,25));
}
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawLine(112,50,237,50);
g.drawLine(112,75,237,75);
g.drawLine(112,100,237,100);
g.drawLine(112,125,237,125);
g.drawLine(112,150,237,150);
g.drawLine(112,175,237,175);
g.drawLine(112,50,112,175);
g.drawLine(137,50,137,175);
g.drawLine(162,50,162,175);
g.drawLine(187,50,187,175);
g.drawLine(212,50,212,175);
g.drawLine(237,50,237,175);
Graphics2D g2=(Graphics2D)g;
for(Shape cell:square)
g2.fill(cell);
}
}
}
I want to make the image "img" become the "pixel" that is filled in. However, I'm confused on how to do this as I don't think I can use for-each loops and Graphics2D. If anyone can help, thanks so much!
Define ImageHolder class which has 2 fields shape and image.
class ImageHolder {
Shape shape;
Image img;
public void paint(Graphics2D g2) {
if (img!=null) {
g2.drawImage(img);
}
else {
g2.fill(shape);
}
}
}
Your grid should be List. On init all the ImageHolders have squares and null images. On click image is assigned to the clicked holder.
In the paintComponent() you just call the holder's paint() method
take a look at this one.
all you need to do is repalce your g2.fill(cell); with g2.drawImage(img,cell.getBounds().x,cell.getBounds().y,null);
read drawimage api here
for (Shape cell : square) {
//g2.fill(cell);
g2.drawImage(img,cell.getBounds().x,cell.getBounds().y,null);
System.out.println(cell.getBounds().x);
}
however use Dimention list or 2D list instead Shape in this case
complete code
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.List;
import javax.swing.*;
public class Test {
Image img = Toolkit.getDefaultToolkit().getImage("img.gif");
public static void main(String[] args) {
new Test();
}
public Test() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new PixelGrid());
frame.setSize(new Dimension(364, 357));
frame.setVisible(true);
}
public class PixelGrid extends JPanel {
int x=0;
int y=0;
private List<Shape> grid, square;
public PixelGrid() {
grid = new ArrayList<>();
square = new ArrayList<>();
addMouseMotionListener(new MouseAdapter() {
public void mouseMoved(MouseEvent e) {
for (Shape shape : grid) {
if (shape.contains(e.getPoint())) {
square.add(shape);
}
}
repaint();
}
}
);
for (int row = 0; row < 5; row++) {
for (int col = 0; col < 5; col++) {
grid.add(new Rectangle(col * 25 + 112, row * 25 + 50, 25, 25));
}
}
}
public void paintComponent(Graphics g) {
System.out.println(x);
g.drawLine(112, 50, 237, 50);
g.drawLine(112, 75, 237, 75);
g.drawLine(112, 100, 237, 100);
g.drawLine(112, 125, 237, 125);
g.drawLine(112, 150, 237, 150);
g.drawLine(112, 175, 237, 175);
g.drawLine(112, 50, 112, 175);
g.drawLine(137, 50, 137, 175);
g.drawLine(162, 50, 162, 175);
g.drawLine(187, 50, 187, 175);
g.drawLine(212, 50, 212, 175);
g.drawLine(237, 50, 237, 175);
Graphics2D g2 = (Graphics2D) g;
//g2.drawImage(img,x,y,null);
for (Shape cell : square) {
//g2.fill(cell);
g2.drawImage(img,cell.getBounds().x,cell.getBounds().y,null);
System.out.println(cell.getBounds().x);
}
}
}
}
output>>
I am currently trying to draw a figure by clicking a button. My problems occurs when I click the button and it does not show up in the panel, but I know it's drawing because it runs through the loop.
The drawing will occur when I request the panel to draw it inside the constructor, but not inside the button, inside the constructor
If i put the code in the method "stuff()" inside the constructor it will draw everything just fine.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MainFrame{
public static void main(String[]args){
MainFrame f = new MainFrame();
}
public JFrame frame = new JFrame();
public JPanel panel = new JPanel(new BorderLayout());
public MainFrame(){
JButton button1 = new JButton("Shweet Button");
button1.setBounds(185, 10, 130, 20);
frame.setBounds(1680/4,1050/4,500, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.add(panel);
panel.setBackground(Color.black);
frame.setVisible(true);
frame.getContentPane().setLayout(null);
frame.add(button1);
button1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
stuff();
}
});
}
public void stuff(){
for(int i = 0;i<1000;i++){
panel.add(new paintComponent());
panel.setBackground(Color.black);
frame.repaint();
try {
Thread.sleep(80);
} catch (InterruptedException e1){e1.printStackTrace();}
}
}
static class paintComponent extends JComponent{
public int options;
public void paint(Graphics g){
Graphics2D g2 = (Graphics2D)g;
g2.setColor(Color.white);
if(options == 0){
options = 1;
g2.drawOval(50, (JFrame.HEIGHT/2)+100, 50, 50);
g2.drawOval(60, (JFrame.HEIGHT/2)+110, 8, 8);
g2.fillOval(60, (JFrame.HEIGHT/2)+110, 8, 8);
g2.drawOval(80, (JFrame.HEIGHT/2)+110, 8, 8);
g2.fillOval(80, (JFrame.HEIGHT/2)+110, 8, 8);
g2.drawArc(65, (JFrame.HEIGHT/2)+130, 100, 0, 140, 30);
g2.drawLine(75, (JFrame.HEIGHT/2)+150, 75, (JFrame.HEIGHT/2)+220);
g2.drawLine(75, (JFrame.HEIGHT/2)+180, 100, (JFrame.HEIGHT/2)+160);
g2.drawLine(75, (JFrame.HEIGHT/2)+180, 65, (JFrame.HEIGHT/2)+210);
g2.drawLine(75, (JFrame.HEIGHT/2)+220, 50, (JFrame.HEIGHT/2)+260);
g2.drawLine(75, (JFrame.HEIGHT/2)+220, 100, (JFrame.HEIGHT/2)+260);
}else if(options == 1){
options = 0;
g2.drawOval(50, (JFrame.HEIGHT/2)+100, 50, 50);
g2.drawOval(60, (JFrame.HEIGHT/2)+110, 8, 8);
g2.fillOval(60, (JFrame.HEIGHT/2)+110, 8, 8);
g2.drawOval(80, (JFrame.HEIGHT/2)+110, 8, 8);
g2.fillOval(80, (JFrame.HEIGHT/2)+110, 8, 8);
g2.drawArc(65, (JFrame.HEIGHT/2)+130, 100, 0, 140, 30);
g2.drawLine(75, (JFrame.HEIGHT/2)+150, 75, (JFrame.HEIGHT/2)+220);
g2.drawLine(75, (JFrame.HEIGHT/2)+180, 100, (JFrame.HEIGHT/2)+180);
g2.drawLine(75, (JFrame.HEIGHT/2)+180, 65, (JFrame.HEIGHT/2)+210);
g2.drawLine(75, (JFrame.HEIGHT/2)+220, 50, (JFrame.HEIGHT/2)+260);
g2.drawLine(75, (JFrame.HEIGHT/2)+220, 100, (JFrame.HEIGHT/2)+260);
}
}
}
}
You are blocking the Event Dispatching Thread, which is responsible for, amongst other things, processing paint requests.
You should never do anything like this...
for(int i = 0;i<1000;i++){
panel.add(new paintComponent());
panel.setBackground(Color.black);
frame.repaint();
try {
Thread.sleep(80);
} catch (InterruptedException e1){e1.printStackTrace();}
}
Within the EDT. Apart from the fact you are adding multiple new components to your UI every 80 milliseconds, you are also blocking the thread that is responsible for updating your screen...
Check out Concurrency in Swing for more details.
Animation of this type should be handled by a javax.swing.Timer.
Custom painting should be performed in the paintComponent method, as a general rule. You should also be calling super.paintXxx first as a matter of course. There's a lot of working going in the background that needs to be taken care of, especially if the component is transparent.
Check out Performing Custom Painting and Painting in AWT and Swing for more details.
Save your sanity and learn how to use layout managers, they will make your life easier in the long run.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class MainFrame {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
MainFrame f = new MainFrame();
}
});
}
public JFrame frame = new JFrame();
public JPanel panel = new JPanel(new BorderLayout());
private WavePane waver;
public MainFrame() {
waver = new WavePane();
JButton button1 = new JButton("Shweet Button");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
panel.setBackground(Color.black);
frame.add(button1, BorderLayout.SOUTH);
button1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
stuff();
}
});
panel.add(waver);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public void stuff() {
// for (int i = 0; i < 1000; i++) {
// panel.add(new paintComponent());
// panel.setBackground(Color.black);
// frame.repaint();
// try {
// Thread.sleep(80);
// } catch (InterruptedException e1) {
// e1.printStackTrace();
// }
// }
waver.walk(!waver.isWaving());
}
public class WavePane extends JComponent {
private int options;
private Timer timer;
public WavePane() {
setOpaque(false);
timer = new Timer(80, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("tick");
options++;
repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
public void walk(boolean walk) {
if (walk) {
timer.start();
} else {
timer.stop();
}
}
public boolean isWaving() {
return timer.isRunning();
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.white);
int height = getHeight();
if (options % 2 == 0) {
g2.drawOval(50, 100, 50, 50);
g2.drawOval(60, 110, 8, 8);
g2.fillOval(60, 110, 8, 8);
g2.drawOval(80, 110, 8, 8);
g2.fillOval(80, 110, 8, 8);
g2.drawArc(65, 130, 100, 0, 140, 30);
g2.drawLine(75, 150, 75, 220);
g2.drawLine(75, 180, 100, 160);
g2.drawLine(75, 180, 65, 210);
g2.drawLine(75, 220, 50, 260);
g2.drawLine(75, 220, 100, 260);
} else {
g2.drawOval(50, 100, 50, 50);
g2.drawOval(60, 110, 8, 8);
g2.fillOval(60, 110, 8, 8);
g2.drawOval(80, 110, 8, 8);
g2.fillOval(80, 110, 8, 8);
g2.drawArc(65, 130, 100, 0, 140, 30);
g2.drawLine(75, 150, 75, 220);
g2.drawLine(75, 180, 100, 180);
g2.drawLine(75, 180, 65, 210);
g2.drawLine(75, 220, 50, 260);
g2.drawLine(75, 220, 100, 260);
}
}
}
}
You shouldn't be using JFrame.HEIGHT this actually has nothing to do with the frames height, but is part of the ImageObserver support... or any type of magic number for that matter