jLabel Icon Animation Glictching - java

I'm trying to make the person walk but for some reason when I switch icons the label returns to it's default location for a split second then updates to the where I set the bounds. Extremely annoying, any help is much appreciated. Thank You.
public class Main extends JFrame implements ActionListener{
JLabel x = new JLabel("");
ImageIcon player1 = new ImageIcon("C:\\Users\\Kyle\\Documents\\NetBeansProjects\\Testing52\\src\\testing52\\Player1.png");
ImageIcon player2 = new ImageIcon("C:\\Users\\Kyle\\Documents\\NetBeansProjects\\Testing52\\src\\testing52\\Player2.png");
static int count;
Timer timer;
Main(){
timer = new Timer(100,this);
setVisible(true);
setSize(500,500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setFocusable(false);
add(x);
timer.start();
}
public static void main(String [] args){
Main main = new Main();
}
#Override
public void actionPerformed(ActionEvent e) {
count += 1;
if(count == 10){
x.setIcon(player1);
}
if(count == 20){
x.setIcon(player2);
}
if(count == 30){
count = 0;
}
x.setBounds(0, 0,60,60);
}
}

The setBounds(...) call only works when the layout used is null. Having said that, don't use null layouts (see this), but instead use proper layout managers and component positioning.

Related

Swing going from menu to actual gameplay

So I am making a space invaders clone. Originally I had no problem getting my game to work with a simple main class that created the frame, created the gameplay and started the thread.
But then I tried to implement a start menu and it all went to crap. The menu appears with success but the gameplay does not appear when I press start.
I am running out of ideas and I am completely stumped. I am somewhat new as well to SO, so if there is anything I left out, I appreciate any help.
Here is the original with no menu that worked fine:
public static void main(String[] args) {
JFrame frame = new JFrame("SpaceRaiders");
frame.setSize(600, 600);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Gameplay gameplay = new Gameplay();
frame.add(gameplay);
frame.setVisible(true);
Thread t1 = new Thread(gameplay);
t1.start();
}
However, the moment I tried to implement a menu to then play the game, I am running into all sorts of trouble. I created a UI class as well as an actual "game" class like so:
public class UI {
JFrame frame, f2;
JPanel titrePanel, startButtonPanel, loadButtonPanel, p2;
JLabel nomJeu;
JButton startButton, loadButton;
Font fontTitre, fontStart;
Gameplay gameplay;
public void createUI(ChoixJeu cj) {
frame = new JFrame("SpaceRaiders");
frame.setSize(600, 600);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setLayout(null);
frame.getContentPane().setBackground(Color.black);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//------------------ECRAN MENU---------------------
//Titre
titrePanel = new JPanel();
titrePanel.setBounds(100, 100, 400, 100);
titrePanel.setBackground(Color.BLUE);
Font fontTitre = new Font("Times New Roman", Font.BOLD, 50);
Font fontStart = new Font("Times New Roman", Font.PLAIN, 20);
nomJeu = new JLabel("SpaceRaiders");
nomJeu.setForeground(Color.white);
nomJeu.setFont(fontTitre);
titrePanel.add(nomJeu);
//Start button
startButtonPanel = new JPanel();
startButtonPanel.setBounds(200, 400, 200, 40);
startButtonPanel.setBackground(Color.BLACK);
startButton = new JButton("START");
startButton.setBackground(Color.BLACK);
startButton.setForeground(Color.WHITE);
startButton.setFont(fontStart);
startButton.setFocusPainted(false);
startButton.addActionListener(cj);
startButton.setActionCommand("start");
startButtonPanel.add(startButton);
//Load Button
loadButtonPanel = new JPanel();
loadButtonPanel.setBounds(200, 440, 200, 100);
loadButtonPanel.setBackground(Color.BLACK);
loadButton = new JButton("LOAD");
loadButton.setBackground(Color.BLACK);
loadButton.setForeground(Color.WHITE);
loadButton.setFont(fontStart);
loadButton.setFocusPainted(false);
titrePanel.add(nomJeu);
loadButtonPanel.add(loadButton);
frame.add(startButtonPanel);
frame.add(titrePanel);
//------------------ECRAN MENU FIN---------------------
frame.setVisible(true);
}
And the game class...
public class Jeu {
ChoixJeu cj = new ChoixJeu();
UI ui = new UI();
Ecrans e = new Ecrans(ui);
Gameplay gp;
public static void main(String[] args) {
new Jeu();
}
public Jeu() {
ui.createUI(cj);
Gameplay gameplay = new Gameplay();
this.gp = gameplay;
}
public class ChoixJeu implements ActionListener {
#Override
public void actionPerformed(ActionEvent ae) {
String yourChoice = ae.getActionCommand();
switch (yourChoice) {
case "start":
e.montrerEcranJeu();
new Thread(gp).start();
ui.frame.add(gp);
break;
default:
break;
}
}
}
}
I also tried to make a class/method that hides the menu panels
public void montrerEcranJeu() {
//Cache Menu
ui.titrePanel.setVisible(false);
ui.startButtonPanel.setVisible(false);
//Montre Jeu
// ui.frame.add(gameplay);
}
And just in case the Gameplay class. The run() method is at the bottom
public class Gameplay extends JPanel implements KeyListener, ActionListener, Runnable {
private Ship player = new Ship(new Point(200, 555));
Timer t = new Timer(5, this);
private ArrayList<Laser> lasers = new ArrayList<Laser>();
private int laserNb;
private boolean readytofire;
private boolean shot = false;
private ArrayList<Invader> invaders = new ArrayList<Invader>();
private boolean pause;
public Gameplay() {
super();
t.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
for (int j = 0; j < 80; j += 20) {
for (int i = 0; i < 20; i++) {
invaders.add(new Invader(5 + i * 30, j));
}
}
}
public boolean addLaser(Laser a) {
lasers.add(a);
return true;
}
public boolean addPlayer(Ship p) {
this.player = p;
return true;
}
#Override
public void keyTyped(KeyEvent ke) {
}
public void keyPressed(KeyEvent e) {
if (KeyEvent.VK_RIGHT == e.getKeyCode()) {
moveRight();
}
if (KeyEvent.VK_LEFT == e.getKeyCode()) {
moveLeft();
}
if (KeyEvent.VK_SPACE == e.getKeyCode()) {
shoot();
System.out.println("Space Action from Gameplay is working");
}
}
#Override
public void keyReleased(KeyEvent e) {
}
#Override
public void actionPerformed(ActionEvent ae) {
repaint();
}
public void moveRight() {
if (player.getCentre().getX() >= 580) {
player.setX(580);
} else {
double movement = player.getCentre().getX();
movement += 10;
player.setX(movement);
}
this.repaint();
}
public void moveLeft() {
if (player.getCentre().getX() <= 20) {
player.setX(20);
} else {
double movement = player.getCentre().getX();
movement -= 10;
player.setX(movement);
}
this.repaint();
}
public void shoot() {
shot = true;
if (readytofire) {
Point top = new Point(player.getTopX(), player.getTopY());
Laser laser = new Laser(top);
addLaser(laser);
}
}
public void moveShot() {
if (shot) {
for (Laser l : lasers) {
l.setY(l.getTopLeft().getY() - 1);
}
}
}
#Override
public void paint(Graphics g) {
setBackground(Color.black);
super.paint(g);
player.draw(g);
for (Laser l : lasers) {
l.draw(g);
}
for (Invader i : invaders) {
i.draw(g);
}
}
// public void paintComponent (Graphics g){
// Controle Thread
public void run() {
while (true) {
moveShot();
for (Invader i : invaders) {
i.moveAndUpdate();
}
// for (Invader i : invaders) {
// if (){
// System.out.println("YOU ARE DEAD!");
// }
// }
try {
Thread.sleep(10);
readytofire = true;
} catch (InterruptedException ex) {
Logger.getLogger(Gameplay.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
So, using null layouts is the beginning of your problems. I might recommend using CardLayout which is designed to help you dynamically switch between views. See How to Use CardLayout for more details. I'd also suggest taking the time to read through Laying Out Components Within a Container and finding one or more appropriate layouts to support your menu.
You're also making a lot of fundamental mistakes. Swing is not thread safe, so you should avoid updating the UI (or something the UI depends on) from outside the context of the EDT - see Concurrency in Swing for more information and How to Use Swing Timers for a possible solution.
As a general recommendation, you should avoid overriding paint and, in the case of classes which extend from JComponent, prefer paintComponent instead. You should also avoid call methods which might change the state of the component during a paint cycle, this can increase the number of repaint requests and degrade the performance of your program (ie, don't call setBackground inside paint).
Have a look at Performing Custom Painting and Painting in AWT and Swing for more details about how the paint system works and how best you can work with it.
You should also avoid KeyListener, this is likely to cause you issues when you introduce other, focusable, components into the picture. Instead, you should favour the Key bindings API instead
I've read through [insert link or tutorial], but it still doesn't help...
And forgive me if this doesn't happen all the time.
The point of providing you the tutorial links is to encourage you to learn something;
Learn where to find answers to your questions
Learn how the APIs work
Expand your knowledge and understanding of how the APIs work
Having said that, they're not always "obvious" as to the solution. What I do when I'm in this situation is start with one or more new projects, dedicated to just working on that aspect of the API I'm trying to understand. For here I can explore the concepts in isolation and when I "think" I understand them, try and implement them into the project I'm working on. This might take a number of iterations, but once it works, I have gained a much deeper understanding and appreciation of the API then I would have gained from a simple "copy-n-paste" solution

Every time I pressed Roll(JButton) it left a picture of roll button on

I'm trying to make a snakes and ladders game. It doesn't done yet(no swap turn, no use of ladder and snake) and have so many bug.
But My point is that
I found a problem that make me very curious(Picture Below). It about making a token move. My strategy is that I add a[10][10] array of JPanal(I named it class as Cell) on a big JPanel(I named it class as Board) whose I set its bg as a picture of snakes and ladders game from google and set the layout to gridlayout(10,10). And on every Cell there's one token which is hiding and will only reveal when press the roll button and the output point to that Cell.
This is where the problem happened.
Image of the program when execute
When I press roll button for sometimes
There's a button appear every time I press!(They are not clickable though.)
I know that my start point doesn't even on the left bottom square but where is all that jbutton came from!
This is my main class
public class Main extends JFrame {
TextField text = new TextField();
Dice dice = new Dice();
int tempi = -1, tempj = -1,sum =0;
//Main Method
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
Main mPage = new Main();
mPage.setVisible(true);
}
});
}
//Constructor
public Main(){
super("Snakes and Ladders");
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setSize(1280,768);
setLocation(400,150);
setLayout(new FlowLayout(FlowLayout.LEFT,30,100));
Board board = new Board();
getContentPane().add(board);
getContentPane().add(dice);
getContentPane().add(text);
//my problem is here.
dice.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int score = Dice.rollDice();
text.setText(String.valueOf(score));
if (tempi != -1 || tempj != -1){
board.cell[9-tempi][9-tempj].fade();
}
if (tempi == -1 && tempj == -1){
sum = sum + score - 1;
}
else sum = sum + score;
tempj = sum%10;
tempi = (sum - tempj)/10;
board.cell[9-tempi][9-tempj].reveal();
}
});
pack();
setMinimumSize(this.getSize());
}
}
This is Cell class
public class Cell extends JPanel implements Cloneable {
private Token pl1 = new Token();
//constructor
public Cell(){
setOpaque(true);
setBackground(new Color(0,0,0,0));
setLayout(new GridLayout(2,2));
this.fade();
this.add(pl1);
}
public void fade(){
pl1.setVisible(false);
}
public void reveal(){
pl1.setVisible(true);
}
}
This is Token class
public class Token extends JLabel {
private BufferedImage image = null;
public Token(){
try {
image = ImageIO.read(new File("C:\\Users\\myacc\\IdeaProjects\\Snakes and Ladders\\src\\Token.png"));
} catch (IOException e) {
e.printStackTrace();
}
Image player = image.getScaledInstance(20,20,Image.SCALE_SMOOTH);
this.setIcon(new ImageIcon(player));
}
}
setBackground(new Color(0,0,0,0));
Don't use backgrounds with transparency. Swing does not know how to paint transparent backgrounds properly.
For full transparency you just make the component non-opaque:
//setOpaque(true);
//setBackground(new Color(0,0,0,0));
setOpaque(false);
If you need semi-transparency, then you need to do custom painting yourself. Check out Background With Transparency for more information on this topic.
Also don't use a TextField. That is an AWT component. Use a JTextField which is the Swing component.

Using a Timer within a while loop

I want to use a Timer in a while loop. That is, I want to run the body of a while loop multiple times when it includes a timer within it. However, whenever I do this, the body of the while loop seems to execute and increment before the timer has fired the required amount of times. It is supposed to fire 15 times before the while loop increments, but it seems to be running through the while loop immediately before the timer fires the required amount of times, which I do not understand.
I know it isn't a problem with anything else because when I just run the code through once (i.e., without a while loop), it runs fine. The idea is that a JLabel is supposed to be removed and replaced every 1300ms until 15 images are displayed. Once it displays the 15 images, it moves onto the next row of the 2D array, of which there are 60 rows in total.
Any help would be appreciated. I have put the code below.
public class Game implements KeyListener, ActionListener{
private Preparation prep;
private Window window;
private JLabel earthLabel;
private JPanel panel;
private Timer timer;
private JLabel[] arrayOfAllSpaceshipsLabels;
private int[] arrayOfAllSpaceshipsIndexes;
private JLabel currentShipLabel;
private int numberOfBlocks;
private int firings;
private int[][] blocks = new int[60][15] //the values in this array have been initalized in another class that is too big and not relevant to my problem
public Game(){
window = new Window("Space Game");
runBlock();
}
private void runBlock() {
int blocksLength = blocks.length;
numberOfBlocks = 0;
while(numberOfBlocks < blocksLength){
firings = 0;
timer = new Timer(1333, new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
if (firings == 15){
panel.removeAll();
panel.revalidate();
panel.repaint();
timer.stop();
System.out.println("Block finished");
return;
}
panel.removeAll(); /*(currentShipLabel);*/
panel.revalidate();
panel.repaint();
currentShipLabel = arrayOfAllSpaceshipsLabels[blocks[numberOfBlocks][firings]];
panel.add(currentShipLabel);
panel.validate();
firings++;
}
});
timer.start();
}
numberOfBlocks++;
}
}
public class Window extends JFrame{
private JPanel panel;
public Window(String title){
SwingUtilities.isEventDispatchThread();
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//this.setBackground(Color.BLACK);
panel = new JPanel();
this.add(panel);
this.pack();
this.setSize(500,500); //my edit
panel.setBackground(Color.BLACK);
this.setVisible(true);
}
public JPanel getPanel() {
// TODO Auto-generated method stub
return panel;
}
}
As you have noticed, creating and starting a Timer does not prevent your loop from continuing.
To solve your problem you have to "move" your while loop into the timer action:
private void runBlock() {
int blocksLength = blocks.length;
numberOfBlocks = 0;
timer = new Timer(1333, new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
if (firings == 15){
if (numberOfBlocks == blocksLength)
panel.removeAll();
panel.revalidate();
panel.repaint();
timer.stop();
System.out.println("Block finished");
return;
} else {
firings = 0;
numberOfBlocks++;
}
}
panel.removeAll(); /*(currentShipLabel);*/
panel.revalidate();
panel.repaint();
currentShipLabel = arrayOfAllSpaceshipsLabels[blocks[numberOfBlocks][firings]];
panel.add(currentShipLabel);
panel.revalidate();
firings++;
}
});
timer.start();
}

Changing JLabels between classes

My first post, so forgive any incorrect etiquette. I'm currently doing my year end project for school and I need a bit of help. I am making a GUI java app in Netbeans. I have two classes. One is a class that controls a timer, the other is a class that is a scoreboard screen. I need to update the scoreboard timerLabel with the time that is being counted down in the timerClass. Its quite messy as there is another timer label in the Timer class which does update. My problem is that I cannot get timerLabel in MatchScreen() to update. Here is my code :
Timer Class
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
public class TimerClass extends JFrame {
Timer timer;
JLabel promptLabel, timerLabel;
int counter;
JTextField tf;
JButton button;
MatchScreen call = null;
public TimerClass() {
call = new MatchScreen();
setLayout(new GridLayout(4, 4, 7, 7));
promptLabel = new JLabel(""
+ "Enter number of seconds for the timer",
SwingConstants.CENTER);
add(promptLabel);
tf = new JTextField(5);
add(tf);
button = new JButton("Start");
add(button);
timerLabel = new JLabel("waiting...",
SwingConstants.CENTER);
add(timerLabel);
event e = new event();
button.addActionListener(e);
System.out.println("Button pressed");
}
public class event implements ActionListener {
public void actionPerformed(ActionEvent e) {
System.out.println("Action performed");
int count = (int) (Double.parseDouble(tf.getText()));
timerLabel.setText("Time left: " + count);
call.setTimerLabel(count);
System.out.println("Passed count to tc");
TimeClass tc = new TimeClass(count);
timer = new Timer(1000, tc);
System.out.println("Timer.start");
timer.start();
//throw new UnsupportedOperationException("Not supported yet.");
}
/*public void actionPerformed(ActionEvent e) {
throw new UnsupportedOperationException("Not supported yet.");
}*/
}
public class TimeClass implements ActionListener {
int counter;
public TimeClass(int counter) {
this.counter = counter;
}
public void actionPerformed(ActionEvent e) {
counter--;
if (counter >= 1) {
call.setTimerLabel(counter);
} else {
timerLabel.setText("END");
timer.stop();
Toolkit.getDefaultToolkit().beep();
}
}
}
public static void main(String args[]) {
TimerClass gui = new TimerClass();
gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gui.setSize(250, 150);
gui.setTitle("Time Setup");
gui.setVisible(true);
}
}
And now the ScoreBoard Screen
public class MatchScreen extends javax.swing.JFrame {
int redScore = 0, blueScore = 0, blueCat1 = 0,
blueCat2 = 0, redCat1 = 0, redCat2 = 0, winner = 0;
public MatchScreen() {
initComponents();
}
//Determine Winner of the match
public int getWinner() {
if (redScore > blueScore) {
winner = 1;
} else {
winner = 2;
}
return winner;
}
public void setTimerLabel(int a) {
int time = a;
while (time >= 1) {
timerLabel.setText("" + time);
}
if (time < 1) {
timerLabel.setText("End");
}
}
private void jButton13ActionPerformed(java.awt.event.ActionEvent evt) {
//Creates an object of the timerClass
TimerClass gui = new TimerClass();
gui.setSize(300, 175);
gui.setTitle("Time Setup");
gui.setVisible(true);
}
}
Some code that I felt is irrelevant was left out from the MatchScreen().
Many thanks
Managed to solve the general problem. I put all the code into one class. Not ideal, but it works :/ Anyway, deadlines are looming.
Sincere thanks.
You have a while loop in the setTimerLabel method, which I don't think you intended to put there. Also, you take the parameter a and assign it to time and then never use a again, why not just rename your parameter to time and bypass that additional variable?
EDIT
Sorry, I forgot to explain what I'm seeing :P If you say call.setTimerLabel(10) then you hit that while loop (while(time >= 1) which is essentially running while(10 >= 1) which is an infinite loop. Your program is never leaving the method setTimerLabel the first time you call it with a value >= 1.

JLabel wont change color twice

I have the following code:
public class Test extends JFrame implements ActionListener{
private static final Color TRANSP_WHITE = new Color(new Float(1), new Float(1), new Float(1), new Float(0.5));
private static final Color TRANSP_RED = new Color(new Float(1), new Float(0), new Float(0), new Float(0.1));
private static final Color[] COLORS = new Color[]{ TRANSP_RED, TRANSP_WHITE};
private int index = 0;
private JLabel label;
private JButton button;
public Test(){
super();
setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
label = new JLabel("hello world");
label.setOpaque(true);
label.setBackground(TRANSP_WHITE);
getContentPane().add(label);
button = new JButton("Click Me");
button.addActionListener(this);
getContentPane().add(button);
pack();
setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource().equals(button)){
label.setBackground(COLORS[index % (COLORS.length - 1)]);
index++;
}
}
public static void main(String[] args) {
new Test();
}
}
When I run it I get the label with the TRANSP_WHITE background and then when I click the button this color changes to TRANSP_RED but when I click it again I see no change in color. Does anyone know why?
Thanks
Well, what were you expecting to happen?
label.setBackground(COLORS[index % (COLORS.length - 1)]);
The index variable is hard coded to 0. and COLORS.length -1 is essentially a constant. So every time you click your setting the background to COLORS[0];
If you change your action method to the following you'll get the results you are looking for:
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource().equals(button)){
label.setBackground(COLORS[index % COLORS.length]);
index++;
}
}
First: The modulo operator will always return a value between 0 and one less than the value passed to it. So
index % COLORS.length
Will always return a value between 0 and COLORS.length -1.
Second: You were forgetting to increment index after every call.
Hey! You forgot to increment index. In this expression:
label.setBackground(COLORS[index % (COLORS.length - 1)]);
index % (COLORS.length - 1) is always 0.
BTW. you don't have to use new Float(1) when creating Color. 1F should work too.
Here is the code you have to use
label.setBackground(COLORS[index % (COLORS.length)]);
index++;
You are doing it wrong. It should be done like that
label = new JLabel("hello world"){
public void paintComponent(Graphics g)
{
//draw background
Color old=g.getColor();
g.setColor(getBackground());
g.fillRect(0,0,getWidth(),getHeight());
g.setColor(old);
super.paintComponent(g);
}
};
label.setOpaque(false); // your component is not opaque!

Categories