JLabel Icon not updating with setIcon (or other redundancies) - java

Two different versions of code I'm using, as noted, the first one works fine, without any problems what so ever, the second one, the only thing that doesn't happen is the updating of the image (have verified through step debugging and debug printing to verify all values and conditionals by hand)
/* properly updates dice[] JLabel icons */
for (int i = 0; i < game.getToRoll(); i ++){
//sets rolled dice to actual values
dice[i].setIcon(dicePic[(game.getDice(i).getFaceValue())]);
}
/* loops properly, generates properly, does not update icons */
Die x = new Die();
int animate = 0;
while(animate < 10){
for (int i = 0; i < 6; i++ ){
x.roll();
if (i <= (game.getToRoll() -1))
dice[i].setIcon(dicePic[x.getFaceValue()]);
else
dice[i].setIcon(dicePic[0]);
}
panel[1].repaint();
panel[1].validate();
animate++;
try{
Thread.sleep(100);
}
catch(Exception e){
e.printStackTrace();
}
}
I've been looking around for some kind of idea of what it is that's causing the problem, and I've not run into anything other than that "sometimes repaint and validate will fix things that don't work."
As stated above, debug is giving me the greenlight on code flow working entirely as expected, just null image icons in the second example.

The problem is the Thread.sleep(100); The icon does change but you don't see the change because you blocked the UI thread.
So the rule is: never sleep the EventDispatchThread!
My advice is to use a Timer:
new javax.swing.Timer(200, new ActionListener() {
#Override
public void actionPerformed(final ActionEvent e) {
//do an icon change
}
}).start();

Related

How to create sequence with thread.sleep in Java

I'm trying to create a simple sequence that basically consists on a JLabel's text being set to a value using an array and a for cycle. However it waits a certain time, before it changes.
My code looks something like this:
private String[] images = {"ball_00.bmp",
"ball_01.bmp",
"ball_02.bmp",
"ball_03.bmp",
"ball_04.bmp",
"ball_05.bmp",
"ball_06.bmp",
"ball_07.bmp",
"ball_08.bmp",
"ball_09.bmp",
"ball_10.bmp"};
public void runGif(){
for(int x = 0; x < this.images.length; x++) {
try {
System.out.println(images[x]);
this.lbl_image.setText(images[x]);
this.panel_CENTER.add(lbl_image);
this.lbl_image.setVisible(false);
this.lbl_image.setVisible(true);
System.out.println("I'm waiting");
Thread.sleep(CurrentSpeed);
System.out.println("I'm back");
}
catch(Exception e) {e.getStackTrace();}
System.out.println(x);
}
}
However I'm getting no output and the only thing I see on my JFrame is the label displaying "GIF", which is the default text that I set it to.
I don't know what migth be causing this issue, and would be very grateful if someone could help me.
Thank you for your attention in advance!

How to "refresh" a JFrame inside an actionperformed method?

I try to design a GUI for a neural network I made recently. I am using the MNIST-dataset and want to display the handwritten digit using JPanels with the brightness-values written inside. By pressing the "train"-button the network gets trained and every new digit is displayed. However this happens in a for loop in the actionperformed method of the button and it seems that I can´t change the background of the labels or the text(at least it doesn´t display the changes) until the last one. I don´t know whether I´m right but it seems that only the last change gets displayed. That´s why my question is whether it is possible to "refresh" the JFrame inside the actionperformed method.
I already have tried revalidate(), invalidate() & validate(), SwingUtilities.updateComponentTreeUI(frame), but none of them worked.
Here is the relevant part of my code:
train.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < iMax; i++) {
...
digitRefresh(reader.getInputs()[i], (int) reader.getInputs()[i][0], 0);
}
}
});
.
public void digitRefresh(double[] pixelValue, int target, int result) {
for (int i = 0; i < 784; i++) {
double value = pixelValue[i + 1];
int brightness = (int) (value * 255);
l_digit[i].setText(String.valueOf(value));
l_digit[i].setBackground(new Color(brightness, brightness, brightness));
}
l_target.setText(String.valueOf(target));
l_result.setText(String.valueOf(result));
this.revalidate();
}
thank you for every awnser and sorry for my bad english.
The simplest thing to do is start a new thread.
#Override
public void actionPerformed(ActionEvent e) {
new Thread( ()->{
for (int i = 0; i < iMax; i++) {
...
final int fi = i;
EventQueue.invokeLater( ()->{
digitRefresh(reader.getInputs()[fi], (int) reader.getInputs()[fi][0], 0);
});
}).start();
}
Now all of the work is being done on a separate thread, then as the ... work finishes, digit refresh method called from the EDT. Notice the final int fi part. There are caveats about going back and forth on threads so it is good to look into better controls than just using thread.
Swing worker for example:
How do I use SwingWorker in Java?

delay doesn`t wotk for java gui(java)

I want to put a delay on a gui. I put 2 for loops, and I repaint a label, but those 2 for loops execute one after one and label is repaint just to the final.
What can I do?
for(int i=0; i<100000; i++){
System.out.println(i);
}
label.setBackground(Color.RED);
for(int i=0; i<100000; i++){
System.out.println(i);
}
label.setBackground(Color.green);
You might want to take a look at
docs.oracle.com/javase/7/docs/api/javax/swing/Timer
It's a link to using timers in Java, which helps to remove the for loops from your program.
You can use this instead:
Timer t = new Timer(2000, YourActionListener);
t.start();
}//End of method
public void paintComponent()
{
super.paintComponent(g);
if(c%2==0)
{
label.setBackground(Color.RED);
}
else
{
label.setBackground(Color.GREEN);
}
c++;
}
...
public void actionPerformed(ActionEvent) // How your YourActionListener method looks like
{
repaint();
}
There are several ways to do a delay in a Java program. Simplest option is to do
Thread.sleep(2000);
Which simply puts the current thread to sleep for 2 seconds. Depending on what you are trying to accomplish though you may need to consider some more complex options.
This option makes your program unresponsive for the sleep time. As you have a (I assume) swing application you can use a Timer instead.

JavaFX Assigning action to all buttons in an array of arrays using for-loop

We have this warm up exercise where we're supposed to create this reallllly simple game which's UI is pretty much set up
.
I got the error "Local variable i defined in an enclosing scope must be final or effectively final".
I didn't understand it, so I googled it, but most of the problems are different.
While typing this question I found this in the stackoverflow suggestions:
Assigning an action to each button, in an array of buttons in JavaFX
But I simply don't understand. I'm learning programming/java from scratch. I hope JavaFX/GuI stuff isn't a hindrance?
The code below only includes my attempt to assign the actions. I separated it from the creation of the buttons for the time being to figure out what the problem is. The problem is only in the if and else conditions.
for(int i=0; i<=4; i++) {
for(int j=0; j<=4; j++) {
buttonGrid[i][j].setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
if (buttonGrid[i][j].getText() == "X") {
buttonGrid[i][j].setText("O");
} else {
buttonGrid[i][j].setText("X");
}
}
});
}
}
For now I just want the button's labels to change from X to O and from O to X as you click them. Btw. If I learn JavaFX and GUI, does it mean I HAVE to learn css? (Not that I don't want to, just.. not now)
If there is a need for the rest of the code to figure the problem:
http://textuploader.com/5b1kh
I'd also appreciate if someone could tell me how to do the Scenes in a more efficent way. (Btw, can I somehow lock the aspect ratio of the sides of all cells of a gridpane?)
I think that the answer in this question explains your problem very well and how to solve it Problems with local variable scope. How to solve it? You can not use i and j inside the Action handler.
Try this. [Notice that I've also changed the string comparison*]
for(int i=0; i<=4; i++) {
for(int j=0; j<=4; j++) {
final Button myButton = buttonGrid[i][j];
myButton.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
if ("X".equals(myButton.getText())) {
myButton.setText("O");
} else {
myButton.setText("X");
}
}
});
}
}
[*] How do I compare strings in Java?

Fish Eye effect on a JLabel

I am trying to implement a Fish Eye Image Menu in a JavaBean. As a start, I created a JLabel and put this code on the mouseEntered event. But when I run this, the output is shaky and doesn't re-size the JLabel.
This is my code.
new Thread() {
public void run() {
for (int i = 0; i < 30; i++) {
int x = imgLabel.getWidth()+1;
int y = imgLabel.getHeight()+1;
imgLabel.setSize(x , y );
// sets the icon to the label
imgLabel.setIcon(new ImageIcon(new ImageIcon(getClass().getResource("/pics/icon.png")).getImage().getScaledInstance(x , y, Image.SCALE_DEFAULT)));
repaint();
try {
Thread.sleep(10);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
}.start();
If I comment that line where I set the image to the JLabel, the label gets re-sized perfectly.
Where has this gone wrong?
The problem is that getScaledInstance() together with resource loading is slow. Do these calculations once and cache them (in an array of 30 items). Not every time in the for loop.
Another thing: make sure you use a Swingworker for your animation, that helps in the timing and avoids setting icons outside the Event Dispatch Thread (EDT).

Categories

Resources