Java apps (based on JSwing) performance consuming? - java

I'm new to Java Programming. Recently I'm developing a mini game with JSWing. However, after coding for awhile the in-game FPS dropped terribly. When I tracked it on Task Manager I had result like this:
Can someone tell me what's wrong? I only used loops, JLabel with icons, Paint Graphics methods, mouseMotionEvent in my code.
Here is the code in the main game
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Game extends JPanel {
int numb = 2;
int pts = 5;
Kitty[] Kitties = new Kitty[4];
public Game() {
for (int i = 0; i < Kitties.length; i++)
Kitties[i] = new Kitty();
}
#Override
public void paint(Graphics graphics) {
BufferedImage img = null;
try {
img = ImageIO.read(getClass().getResourceAsStream("city.jpg"));
} catch (IOException e) {
System.out.println("java io");
}
graphics.drawImage(img, 0, 0, null);
//paints square objects to the screen
for (int i = 0; i < numb;i++) {
Kitties[i].paint(graphics);
}
}
public void update(TheJPanel frame) {
if (frame.a >= 0 && frame.a < 500) numb = 2;
if (frame.a>= 500) numb = 3;
for (int i = 0; i< numb; i++) {
int disty = 500 - Kitties[i].squareYLocation;
int distx = Kitties[i].squareXLocation - frame.x;
if ( Kitties[i].squareYLocation < 600 && disty <= 5 && disty >= -80 && distx < 260 && distx > -100){
frame.a +=pts;
if (Kitties[i].kittype == 6) frame.a += pts;
if (frame.a >= 500) {
Kitties[i].fallSpeed = Kitties[i].FallSpeedlvl2();
pts = 10;
}
Kitties[i].squareYLocation = -200;
Kitties[i].generateKittype();
Kitties[i].generateRandomXLocation();
Kitties[i].generateRandomFallSpeed();
frame.point.setText("Point:" + String.valueOf(frame.a));
frame.lives.setText("Lives:" + String.valueOf(frame.count));
}
if(Kitties[i].squareYLocation > 610){
frame.count--;
Kitties[i].generateKittype();
Kitties[i].generateRandomXLocation();
Kitties[i].generateRandomFallSpeed();
Kitties[i].squareYLocation = -200;
}
if (Kitties[i].squareYLocation >=605) frame.catFall(Kitties[i].squareXLocation);
if(Kitties[i].squareYLocation <= 610){
Kitties[i].squareYLocation += Kitties[i].fallSpeed;
}
}
}
public static void main(String[] args) throws InterruptedException {
Game game = new Game();
TheJPanel frame = new TheJPanel();
frame.add(game);
frame.setVisible(true);
frame.setSize(1000, 1000);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setTitle("Saving kitties");
frame.setResizable(false);
frame.setLocationRelativeTo(null);
while (frame.count>0) {
game.update(frame);
game.repaint();
Thread.sleep(4);
}
if (frame.count == 0) {
JOptionPane.showMessageDialog(null, "You lost!", "Game over!", JOptionPane.ERROR_MESSAGE);
game.setVisible(false);
frame.getContentPane().removeAll();
frame.getContentPane().repaint();
frame.bask.setVisible(false);
frame.background.setVisible(false);
}
}
}
Here is the code for the main Jframe
package game;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
/**
*
* #author Imba Store
*/
public class TheJPanel extends JFrame implements MouseMotionListener {
protected int x;
protected int a = 0;
protected int count = 20;
protected JLabel bask = new JLabel();
protected JLabel background = new JLabel();
protected JLabel point = new JLabel();
protected JLabel lives = new JLabel();
Timer fall;
protected int time =0;
public TheJPanel() {
this.addMouseMotionListener(this);
InitContent();
}
protected void InitContent() {
Icon img = new ImageIcon(getClass().getResource("basket.png"));
bask.setIcon(img);
Icon themes = new ImageIcon(getClass().getResource("city2.png"));
background.setIcon(themes);
background.setBounds(0, 699, 1000, 300);
point.setFont(new java.awt.Font("Trebuchet MS", 1, 35));
point.setText("Point:" + String.valueOf(a));
point.setBounds(20,908,240,50);
point.setForeground(Color.white);
lives.setBounds(800, 908,200,50);
lives.setFont(new java.awt.Font("Trebuchet MS", 1, 35));
lives.setForeground(Color.white);
lives.setText("Point:" + String.valueOf(count));
point.setOpaque(false);
add(point);
add(lives);
add(bask);
add(background);
bask.setSize(400,148);
}
#Override
public void mouseMoved (MouseEvent me)
{
x = me.getX();
background.setBounds(0, 699, 1000, 300);
bask.setBounds(x, 700, 400, 148);
}
#Override
public void mouseDragged (MouseEvent me)
{
}
public void catFall(int getX){
Icon fell = new ImageIcon(getClass().getResource("kitty-fall.png"));
JLabel fellcat = new JLabel();
fellcat.setIcon(fell);
fellcat.setBounds(getX, 760, 220, 220);
add(fellcat);
add(background);
fall = new Timer(1500, new ActionListener(){
#Override
public void actionPerformed(ActionEvent ae) {
getContentPane().remove(fellcat);
}
});
fall.setRepeats(false);
fall.start();
}
}
And this is the class for the falling cats
package game;
/**
*
* #author Imba Store
*/
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;
public final class Kitty extends JLabel {
protected int squareXLocation;
protected int squareYLocation = -200;
protected int fallSpeed = 1;
protected int kittype;
Random rand = new Random();
public int generateRandomXLocation(){
return squareXLocation = rand.nextInt(800);
}
public int generateRandomFallSpeed(){
return fallSpeed = rand.ints(3, 4).findFirst().getAsInt();
}
public int FallSpeedlvl2() {
return fallSpeed = rand.ints(3,7).findFirst().getAsInt();
}
public int generateKittype() {
return kittype = rand.ints(1,8).findFirst().getAsInt();
}
#Override
public void paint(Graphics g) {
BufferedImage img = null;
BufferedImage thugcat = null;
try {
img = ImageIO.read(getClass().getResourceAsStream("kitty.png"));
thugcat = ImageIO.read(getClass().getResourceAsStream("thug-kitty.png"));
} catch (IOException e) {
System.out.println("Java IO");
}
if (kittype == 6) {
g.drawImage(thugcat, squareXLocation, squareYLocation, null);
}
else g.drawImage(img, squareXLocation,squareYLocation,null);
}
public Kitty(){
generateRandomXLocation();
generateRandomFallSpeed();
generateKittype();
}

public void paint(Graphics graphics) {
BufferedImage img = null;
try {
img = ImageIO.read(getClass().getResourceAsStream("city.jpg"));
Custom painting is done by overriding paintComponent(...) not paint(). The first statement should then be super.paintComponent().
A painting method is for painting only. Don't do I/O in the painting method. This will cause the image to be read every time you repaint the panel.
Thread.sleep(4);
Sleeping for 4ms is not enough. That will attempt to repaint 250 times a second which is too often. There is no need for the frame rate to be that fast.
Kitty[] Kitties = new Kitty[4];
Variable names should not start with an upper case character. Most of your names are correct. Be consistent!
point.setBounds(20,908,240,50);
Don't use setBounds(). Swing was designed to be used with layout managers. Set a layout manager for you background and then add the components.
public int FallSpeedlvl2() {
Methods should NOT start with an upper case character. Again, most are correct. Be Consistent!!!

Related

How to Change the Size of Several JPanels at Runtime

I have a GUI set up like this:
JFrame
JScrollPane, in the CENTER of the JFrame's default BorderLayout
Vertical Box, as in Box.getVerticalBox()
A bunch of JPanels
In response to KeyEvents, the program should zoom in or out. I am attempting to do this by calling
setPreferredSize() on the JPanels, but it doesn't "take." What happens is that the contents of each JPanel is zoomed in or out as they should be, but the overall layout doesn't change. That is, if a JPanel was 100x100 before the zoom, and it was to have zoomed out to be 50x50, then the contents will be drawn half as large (correctly), but the area of the JPanel taken is still 100x100. The other JPanels aren't "pushed up."
Oddly, if I manually resize the window, then things settle to what they should be. I thought the problem might be that I need to call some combination of invalidate(), validate(), revalidate(), pack(), doLayout(), etc., but none of these seem to have any effect.
I've looked and there are plenty of questions like this, and some answers, but nothing that seems to help. It's probably something obvious, but I am at a loss.
Here is a minimal example.
import javax.swing.SwingUtilities;
public class Main {
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
MainWindow mWindow = new MainWindow();
}
});
}
}
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.KeyListener;
import java.awt.event.KeyEvent;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JComponent;
import javax.swing.Box;
public class MainWindow extends JFrame implements KeyListener {
public static int numPages = 4;
public static float[] zoomOptions = {
18, 27, 36, 54, 72, 96, 120, 144,
180, 216,252, 288, 360, 432, 504, 576
};
public static int zoomIndex = 4;
private PagePanel[] pagePanels = null;
private JScrollPane scroller = null;
public MainWindow() {
this.setBackground(Color.WHITE);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.addKeyListener(this);
this.pagePanels = new PagePanel[numPages];
for (int i = 0; i < this.numPages; i++)
{
pagePanels[i] = new PagePanel(i);
pagePanels[i].setReferenceSize(300,200);
pagePanels[i].resizeTo();
}
JComponent vbox = Box.createVerticalBox();
for (int i = 0; i < pagePanels.length; i++)
vbox.add(pagePanels[i]);
this.scroller = new JScrollPane(vbox);
this.add(scroller);
this.setPreferredSize(new Dimension(500,500));
this.pack();
this.setVisible(true);
this.setFocusable(true);
}
private void resizeAllSubPanels() {
for (int i = 0; i < this.pagePanels.length; i++)
pagePanels[i].resizeTo();
// Tried various things here to force adjustment of layout.
}
public void keyReleased(KeyEvent e) { }
public void keyTyped(KeyEvent e) { }
public void keyPressed(KeyEvent e) {
char c = e.getKeyChar();
if ((c == '-') || (c == '_'))
{
if (this.zoomIndex > 0)
--zoomIndex;
resizeAllSubPanels();
this.repaint();
}
else if ((c == '+') || (c == '='))
{
if (this.zoomIndex + 1 < this.zoomOptions.length)
++zoomIndex;
resizeAllSubPanels();
this.repaint();
}
}
}
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Dimension;
import javax.swing.JPanel;
public class PagePanel extends JPanel {
private int referenceHeight = -1;
private int referenceWidth = -1;
public PagePanel(int pageNum) {
// Will be using absolute positioning. Could this be the problem?
this.setLayout(null);
}
public void setReferenceSize(int h,int w) {
this.referenceHeight = h;
this.referenceWidth = w;
}
public void resizeTo() {
float zoomRatio = MainWindow.zoomOptions[MainWindow.zoomIndex] / 72.0f;
int w = (int) (referenceWidth * zoomRatio);
int h = (int) (referenceHeight * zoomRatio);
this.setPreferredSize(new Dimension(w,h));
this.repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.clearRect(0,0,this.getSize().width,this.getSize().height);
float zoomRatio = MainWindow.zoomOptions[MainWindow.zoomIndex] / 72.0f;
g.fillOval(
(int) (10 * zoomRatio),
(int) (10 * zoomRatio),
(int) (100 * zoomRatio),
(int) (100 * zoomRatio));
Rectangle r = this.getVisibleRect();
g.drawRect(r.x,r.y,r.width,r.height);
}
}

Java catch the ball Game

I am having trouble with my Java project for school.
The plan was to make a simple game where you need to catch the ball and if you catch the ball you will get points.
At the moment I have 2 problems:
I have no idea how I make the balls appear at a random width and make it stay at that width (cause random value is constantly changing ).
How can I make a statement that checks if the catcher caught the ball?
This is my current code:
import instruct.*;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.imageio.ImageIO;
import javax.swing.Timer;
public class opdracht extends WindowPanel implements MouseMotionListener {
List<comet> comets;
Image afb1;
Image afb2;
Image comet;
int xmuis;
int score;
int random;
int h;
int plaats;
static int randomNum;
private static final int D_W = 700;
private static final int X_INC = 10;
public opdracht() throws IOException {
score = 0;
h = -100;
afb1 = ImageIO.read(new File("afb/space.jpg"));
afb2 = ImageIO.read(new File("afb/pipe.png"));
BufferedImage cometbuf = ImageIO.read(new File("afb/comet.png"));
File output = new File("comet.png");
ImageIO.write(cometbuf, "png", output);
comet = ImageIO.read(new File("comet.png"));
addMouseMotionListener(this);
try {
drawcomet();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
plaats = randomNum;
comets = new LinkedList<>();
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Iterator<comet> it = comets.iterator();
while (it.hasNext()) {
comet ball = it.next();
if (ball.h > D_W) {
it.remove();
System.out.println(comets.size());
} else {
ball.h += X_INC;
repaint();
}
}
}
});
timer.start();
}
public void paintComponent(Graphics g) {
g.drawImage(afb1, 0, 0, 1200, 800, this);
g.setColor(Color.yellow);
g.setFont(new Font("TimesRoman", Font.PLAIN, 30));
g.drawString("score = " + score, 1020, 30);
for (comet ball : comets) {
ball.drawcomet(g);
}
g.drawImage(afb2, xmuis, 730, 70, 75, this);
}
public static void randInt(int min, int max) {
// NOTE: Usually this should be a field rather than a method
// variable so that it is not re-seeded every call.
Random rand = new Random();
// nextInt is normally exclusive of the top value,
// so add 1 to make it inclusive
randomNum = rand.nextInt((max - min) + 1) + min;
System.out.print(randomNum);
}
public void drawcomet() throws InterruptedException {
ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
exec.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
comets.add(new comet(comet));
}
}, 0, 2, TimeUnit.SECONDS);
}
public class comet {
protected int h;
Image comet;
public comet(Image image) {
comet = image;
}
public void drawcomet(Graphics g) {
g.drawImage(comet, plaats, h, 75, 50, null);
}
}
public void mouseMoved(MouseEvent e) {
xmuis = e.getX();
repaint();
}
public void mouseDragged(MouseEvent e) {
// do something
}
public static void main(String[] a) throws IOException {
new opdracht().createGUI();
}
}
package instruct;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class WindowPanel extends JPanel {
JFrame frame;
public WindowPanel() {
this.setPreferredSize(new Dimension(1200, 800));
this.setFocusable(true);
this.requestFocusInWindow();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
// System.out.println( "class: "+ getClass().getName() );
frame.setTitle("Space Game");
}
protected void createAndShowGUI() {
frame = new JFrame();
frame.setSize(1200, 800);
frame.setLocation(300, 100);
frame.setResizable(false);
frame.add(this);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
BufferedImage cursorImg = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
// Create a new blank cursor.
Cursor blankCursor =
Toolkit.getDefaultToolkit().createCustomCursor(cursorImg, new Point(0, 0),
"blank cursor");
// Set the blank cursor to the JFrame.
frame.getContentPane().setCursor(blankCursor);
}
public void createGUI() {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
public JFrame getFrame() {
return frame;
}
}
First question: "I have no idea how i make the ball's appear at a random width."
I assume you want to give the ball (= an instance of the comet class) a random x position (= the plaats field)? You could make the following changes (which make the randomNum field no longer required, this could now be a local variable):
//plaats = randomNum;
plaats = randInt(0, 1200);
// more code...
//public static void randInt(int min, int max) {
public static int randInt(int min, int max) {
// more code...
return randomNum;
}
Second question: "And how can make a statement that checks if catcher cached ball."
To determine whether the ball is catched, you could compare xmuis to plaats when the y coordinate of the ball (the h field?) is equal to the top of the pipe (around 730).

Java JApplet render issues

I have a problem with JApplet. The code was working just fine, but when I converted it from JFrame to JApplet, the render part stopped working properly. Basicly what I'm trying to do is simplistic draw app. When launching applet, half of time repaint() is not working (There is no gray background; you have to put mouse over button for it to update its color etc), furtheremore the pixel rendering part is not shown up at all. Here's the code:
The Frame class (JApplet)
package painter;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Frame extends JApplet {
public JPanel panel;
private JButton plus, minus, buttonColor;
private int scaleSize;
private JLabel labelScale;
private final Timer updateTimer;
private static boolean painting = false;
public static Color currentColor;
public static int mode = 0;
// 0 = draw; 1 = setcolor; 2 = erase
private ArrayList<Pixel> pixelArray;
public Frame() {
pixelArray = new ArrayList<>();
for (int i = 1; i <= 8; i++) {
for (int j = 1; j <= 8; j++) {
pixelArray.add(new Pixel(i, j));
}
}
setLayout(new BorderLayout());
panel = new JPanel() {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
//g.fillRect(10, 10, 100, 100); <- test if fillRect works at all. Yus it does.
for (int i = 0; i < pixelArray.size(); i++) {
pixelArray.get(i).render(g);
}
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
};
//panel.setBounds(0, 0, 800, 800);
//add(panel);
getContentPane().add(panel);
//panel.setLayout(null);
//panel.setOpaque(true);
//panel.setDoubleBuffered(true);
currentColor = Color.yellow;
buttonColor = new JButton("Choose color");
buttonColor.setBounds(10, 10, 128, 64);
buttonColor.setBackground(currentColor);
buttonColor.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
currentColor = JColorChooser.showDialog(null, "JColorChooser Sample", Color.gray);
}
});
updateTimer = new Timer(20, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
buttonColor.setBackground(currentColor);
repaint();
}
});
updateTimer.start();
addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
painting = true;
}
});
addMouseListener(new MouseAdapter() {
#Override
public void mouseReleased(MouseEvent e) {
painting = false;
}
});
panel.add(buttonColor);
repaint();
}
public static boolean getPaint() {
return painting;
}
public static void main(String[] args) {
new Frame();
}
}
And here is the Pixel class:
package painter;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.MouseInfo;
import java.awt.Point;
public class Pixel {
private Color color;
private int size;
private int x, y, relativex, relativey;
public Pixel(int relx, int rely) {
color = new Color(0x999999, false);
size = 32;
x = relx * size + 64;
y = rely * size + 64;
}
public boolean mouseOver() {
Point pos, mousepos;
pos = new Point(x, y);
mousepos = MouseInfo.getPointerInfo().getLocation();
if ((mousepos.x > pos.x)
&& (mousepos.x < pos.x + size)
&& (mousepos.y > pos.y)
&& (mousepos.y < pos.y + size)) {
return true;
} else {
return false;
}
}
public void render(Graphics g) {
g.setColor(color);
if (mouseOver() && Frame.getPaint()) {
if (Frame.mode == 0) {
color = Frame.currentColor;
}
if (Frame.mode == 1) {
Frame.currentColor = color;
}
if (Frame.mode == 2) {
color = new Color(0xffffffff, true);
}
}
g.fillRect(x, y, size, size);
if (mouseOver()) {
g.setColor(Color.black);
g.drawRect(x, y, size - 1, size - 1);
g.setColor(Color.yellow);
g.drawRect(x + 1, y + 1, size - 3, size - 3);
}
//g.fillRect(10, 10, 250, 250);
}
}
As a stab in the dark, don't call Graphics#dipose on a Graphics context you did not create yourself explicitly
Apart from the fact the the Graphics context is a shared resource, used by all the components that might need to be painted within a given paint cycle, it can also prevent what ever was painted to it to be displayed on some platforms
In 15 years of professional development, I've never had reason to call Toolkit.getDefaultToolkit().sync();. I doubt it'll make that big a difference, I'm just saying
Java applets provide us with these methods
[here] http://docs.oracle.com/javase/tutorial/deployment/applet/appletMethods.html
the method
public void paint(Graphics g){}
is used as alternative of
public void paintComponent(Graphics g){}
of swing.
Check out http://docs.oracle.com/javase/tutorial/uiswing/painting/index.html for the recommended way to perform custom painting of swing components

SwingWorker, Thread.sleep(), or javax.swing.timer? I need to "insert a pause"

I'm working on a memory game and I want to set it up so I click the first "card", then the second and if they are not the same the second card shows for a few seconds then they return to the "non-flipped" position.
I tried using SwingWorker, Thread.sleep and SwingTimer but I cant get it to work. With Thread.sleep the second card wont "flip" if it's a duplicate it waits the amount of sleep time and disappears. If its not a match it waits "face down" and after the sleep timer the first card does flip back. This happens regardless of where I place the Thread.sleep.
With Swing Timer it only appears to "change the timer" while I'm interacting with the cards so I end up flipping 8 cards before it activates.
I've had no luck with SwingWorker and I'm not even sure it will work for what I'm looking for.
This is the code I have:
class ButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
for(int index = 0; index < arraySize; index++)
{
if(button[index] == e.getSource())
{
button[index].setText(String.valueOf(cards.get(index)));
button[index].setEnabled(false);
number[counter]=cards.get(index);
if (counter == 0)
{
counter++;
}
else if (counter == 1)
{
if (number[0] == number[1])
{
for(int i = 0; i < arraySize; i++)
{
if(!button[i].isEnabled())
{
button[i].setVisible(false);
}
}
}
else
{
for(int i = 0; i < arraySize; i++)
{
if(!button[i].isEnabled())
{
button[i].setEnabled(true);
button[i].setText("Card");
}
}
}
counter = 0;
}
}
}
}
}
Basically what I need is for this code to execute when the counter == 1, and the card is not a match:
button[index].setText(String.valueOf(cards.get(index)));
button[index].setEnabled(false);
Then a pause so the card is revealed for that time, and finally it resumes to returning the card to its face down position.
This is what I tried with Thread.sleep():
class ButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
for(int index = 0; index < arraySize; index++)
{
if(button[index] == e.getSource())
{
button[index].setText(String.valueOf(cards.get(index)));
button[index].setEnabled(false);
number[counter]=cards.get(index);
if (counter == 0)
{
counter++;
}
else if (counter == 1)
{
if (number[0] == number[1])
{
for(int i = 0; i < arraySize; i++)
{
if(!button[i].isEnabled())
{
button[i].setVisible(false);
}
}
}
else
{
try
{
Thread.sleep(800);
}
catch (InterruptedException e1)
{
e1.printStackTrace();
}
for(int i = 0; i < arraySize; i++)
{
if(!button[i].isEnabled())
{
button[i].setEnabled(true);
button[i].setText("Card");
}
}
}
counter = 0;
}
}
}
}
}
Thanks in advance for any advice
Use javax.swing.Timer to schedule a future event to trigger. This will allow you to make changes to the UI safely, as the timer is triggered within the context of the Event Dispatching Thread.
The problem with been able to flip multiple cards simultaneously has more to do with you not setting up a state that prevents the user from flipping cards then the use of timers.
The following example basically only allows one card to be flipped per group at a time.
Once a card has been flipped in both groups, the timer is started. When it is triggered, the cards are reset.
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.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.LinearGradientPaint;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;
public class FlipCards {
public static void main(String[] args) {
new FlipCards();
}
public FlipCards() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class Card extends JPanel {
private BufferedImage image;
private boolean flipped = false;
private Dimension prefSize;
public Card(BufferedImage image, Dimension prefSize) {
setBorder(new LineBorder(Color.DARK_GRAY));
this.image = image;
this.prefSize = prefSize;
}
#Override
public Dimension getPreferredSize() {
return prefSize;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
LinearGradientPaint lgp = new LinearGradientPaint(
new Point(0, 0),
new Point(0, getHeight()),
new float[]{0f, 1f},
new Color[]{Color.WHITE, Color.GRAY});
g2d.setPaint(lgp);
g2d.fill(new Rectangle(0, 0, getWidth(), getHeight()));
if (flipped && image != null) {
int x = (getWidth() - image.getWidth()) / 2;
int y = (getHeight() - image.getHeight()) / 2;
g2d.drawImage(image, x, y, this);
}
g2d.dispose();
}
public void setFlipped(boolean flipped) {
this.flipped = flipped;
repaint();
}
}
public class CardsPane extends JPanel {
private Card flippedCard = null;
public CardsPane(List<BufferedImage> images, Dimension prefSize) {
setLayout(new GridBagLayout());
MouseAdapter mouseHandler = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if (flippedCard == null) {
Card card = (Card) e.getComponent();
card.setFlipped(true);
flippedCard = card;
firePropertyChange("flippedCard", null, card);
}
}
};
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(4, 4, 4, 4);
gbc.fill = GridBagConstraints.BOTH;
gbc.weightx = 0.25f;
for (BufferedImage img : images) {
Card card = new Card(img, prefSize);
card.addMouseListener(mouseHandler);
add(card, gbc);
}
}
public Card getFlippedCard() {
return flippedCard;
}
public void reset() {
if (flippedCard != null) {
flippedCard.setFlipped(false);
flippedCard = null;
}
}
}
public class TestPane extends JPanel {
private CardsPane topCards;
private CardsPane bottomCards;
private Timer resetTimer;
public TestPane() {
resetTimer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
topCards.reset();
bottomCards.reset();
}
});
resetTimer.setRepeats(false);
resetTimer.setCoalesce(true);
PropertyChangeListener propertyChangeHandler = new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
Card top = topCards.getFlippedCard();
Card bottom = bottomCards.getFlippedCard();
if (top != null && bottom != null) {
resetTimer.start();
}
}
};
BufferedImage[] images = new BufferedImage[4];
try {
images[0] = ImageIO.read(new File("./Card01.png"));
images[1] = ImageIO.read(new File("./Card02.jpg"));
images[2] = ImageIO.read(new File("./Card03.jpg"));
images[3] = ImageIO.read(new File("./Card04.png"));
Dimension prefSize = getMaxBounds(images);
List<BufferedImage> topImages = new ArrayList<>(Arrays.asList(images));
Random rnd = new Random(System.currentTimeMillis());
int rotate = (int) Math.round((rnd.nextFloat() * 200) - 50);
Collections.rotate(topImages, rotate);
topCards = new CardsPane(topImages, prefSize);
topCards.addPropertyChangeListener("flippedCard", propertyChangeHandler);
List<BufferedImage> botImages = new ArrayList<>(Arrays.asList(images));
int botRotate = (int) Math.round((rnd.nextFloat() * 200) - 50);
Collections.rotate(botImages, botRotate);
bottomCards = new CardsPane(botImages, prefSize);
bottomCards.addPropertyChangeListener("flippedCard", propertyChangeHandler);
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(4, 4, 4, 4);
gbc.gridwidth = GridBagConstraints.REMAINDER;
add(topCards, gbc);
add(bottomCards, gbc);
} catch (Exception e) {
e.printStackTrace();
}
}
protected Dimension getMaxBounds(BufferedImage[] images) {
int width = 0;
int height = 0;
for (BufferedImage img : images) {
width = Math.max(width, img.getWidth());
height = Math.max(height, img.getHeight());
}
return new Dimension(width, height);
}
}
}

adding background pic to JFrame

I'm trying to follow this answer to add a background picture to a JFrame and I'm getting a weird error. While debugging my url is coming back null and I get a window that pops up saying "Class File Editor" source not found the source attachment does not contain the source for the file Launcher.class you can change the source attachment by clicking Chang Attached Source below. What does that mean?
here's the code that I have so far:
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class DeluxKenoMainWindow extends JFrame
{
public DeluxKenoMainWindow()
{
initUI();
}
public final void initUI()
{
setLayout(null);
getContentPane().add(new BackgroundImage());
int xCoord = 10;
int yCoord = 10;
Button[] button = new Button[80];
for(int i = 0; i<80; i++)
{
String buttonName = "button" + i;
if(i % 10 == 0)
{
xCoord = 10;
yCoord +=40;
}
xCoord += 40;
if(i % 40 == 0)
yCoord += 8;
button[i] = new Button(buttonName, xCoord, yCoord, i+1);
getContentPane().add(button[i]);
}
setTitle("Delux Keno");
setSize(500,500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
System.setProperty("DEBUG_UI", "true");
DeluxKenoMainWindow ex = new DeluxKenoMainWindow();
ex.setVisible(true);
}
});
}
}
import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import java.io.*;
public class Button extends JButton {
private String name;
private int xCoord;
private int yCoord;
private final int xSize = 40;
private final int ySize = 40;
private int buttonNumber;
private String picture;
public Button(String inName, int inXCoord, int inYCoord, int inButtonNumber)
{
xCoord = inXCoord;
yCoord = inYCoord;
buttonNumber = inButtonNumber;
picture = "graphics\\" + buttonNumber + "normal.png";
super.setName(name);
super.setIcon(new ImageIcon(picture));
super.setBounds(xCoord, yCoord, xSize, ySize);
}
}
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
public class BackgroundImage extends JPanel{
private BufferedImage img;
private URL rUrl;
public BackgroundImage()
{
super();
try{
rUrl = getClass().getResource("formBackground.png");
img = ImageIO.read(rUrl);
}
catch(IOException ex)
{
ex.printStackTrace();
}
}
#Override
protected void paintComponent(Graphics g)
{
//super.paintComponent(g);
g.drawImage(img, 0, 0, getWidth(), getHeight(), this);
}
}
any sugesstions will be appriciated!!
set classpath by #Gagandeep Bali
don't perform any FileIO in paintComponent, load this image one time as local variable, pass variable in paintComponent
for Bingo, Minesweaper to use JToggleButton instead of JButton
went at it a different way, using a JLabel. Here's my final code:
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
public class DeluxKenoMainWindow extends JFrame
{
public DeluxKenoMainWindow()
{
initUI();
}
public final void initUI()
{
setLayout(null);
JLabel background = new JLabel(new ImageIcon ("graphics\\formBackground.png"));
background.setBounds(0,0,600,600);
//getContentPane().add(new BackgroundImage());
int xCoord = 85;
int yCoord = 84;
Button[] button = new Button[80];
for(int i = 0; i<80; i++)
{
String buttonName = "button" + i;
if(i % 10 == 0)
{
xCoord = 12;
yCoord +=44;
}
if(i % 40 == 0)
yCoord += 10;
button[i] = new Button(buttonName, xCoord, yCoord, i+1);
xCoord += 42;
getContentPane().add(button[i]);
}
add(background);
setTitle("Delux Keno");
setSize(600,600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
System.setProperty("DEBUG_UI", "true");
DeluxKenoMainWindow ex = new DeluxKenoMainWindow();
ex.setVisible(true);
}
});
}
}
another problem I found is that you need to use setBounds() for the JPanel for it to have any size. To do it the first way I tried this is the updated BackgroundImage class:
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
public class BackgroundImage extends JPanel{
private BufferedImage img;
private URL rUrl;
public BackgroundImage()
{
super();
try{
rUrl = getClass().getResource("formBackground.png");
img = ImageIO.read(rUrl);
}
catch(IOException ex)
{
ex.printStackTrace();
}
super.setBounds(0,0,600,600);
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(img, 0, 0, getWidth(), getHeight(), this);
}
}

Categories