Fish Eye effect on a JLabel - java

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).

Related

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?

JLabel graphic changes at wrong time

I have a slot machine program with some graphics, and the graphic is supposed to change when you pull the lever and for some reason it changes the graphic after it goes through all of the other code first. Have a look:
Declare images:
static ImageIcon jImage = new ImageIcon("C:\\Users\\Harry\\Desktop\\jackpotLeverNotPulled.png");
static ImageIcon jackpot1 = new ImageIcon("C:\\Users\\Harry\\Desktop\\jackpotimage1.png");
static ImageIcon jackpotPulled = new ImageIcon("C:\\Users\\Harry\\Desktop\\jackpotLeverPulled.png");
Now I add to panel:
static JLabel jlb = new JLabel(jImage);
Now I want the image to change when a certain area is clicked on my panel but the main jackpot code runs first and then the image changes:
public void mousePressed(MouseEvent e) {
// Returns the X coordinate of where the mouse was click on the panel
System.out.println("X Coordinate: " + e.getX() );
// Returns the Y coordinate of where the mouse was click on the panel
System.out.println("Y Coordinate: " + e.getY() );
System.out.println();
Scanner ansr = new Scanner(System.in);
String yesno;
int random = (int)(Math.random() * 21 );
int percentCheck = (int)(Math.random() * 10 );
if (e.getX ()>975 && e.getX ()<1159 && e.getY ()>82 && e.getY ()<218){
jlb.setIcon(jackpotPulled);
if (cashMoneyz<1) {
System.out.println("Insufficient funds");
image1.setIcon(jackpot1);
} else {
System.out.println("One dollar has been removed from you slot machine balance");
cashMoneyz--;
try {
System.out.println("Spinning...");
Thread.sleep(1000);
System.out.println("Spinning...");
Thread.sleep(1000);
System.out.println("SPINNINGGGGG...OMG SOOO INTENSE");
Thread.sleep(1000);
} catch (InterruptedException ie)
{
}
}
System.out.println("You have this much money (in dollars) left in your slot machine balance: " + cashMoneyz);
System.out.println("");
System.out.println("----------------------------------------------------------------------------------");
}
It does the if statements and try catches and only changes the graphic to jackpotPulled at the end of everything.
Thanks in advance :)
There are basically 2 problems in your code:
1)
A call to label.setImage() won't update immediately, as this is true for everything in AWT and Swing. Any time a repaint request is fired, it is simply added to a repaint queue, that will wait patiently for all other tasks done in the EDT (Event Dispatching Thread) to finish. But since you do other things in the mousePressed(), they will run first. A simple solution for this would be to do the computing in mouseReleased(). But a bigger problem exists.
2)
What you are currently doing is "starving" the EDT - a bad programming practice - as all screen related invocations must be executed immediately. Sleeping the EDT won't allow any repaints to take place while running. This is true for any long running tasks as well.
Its solution is to run the non-painting calls in a different thread:
private volatile boolean isComputing = false;
public void mousePressed(MouseEvent evt) {
if(isComputing)
return;
isComputing = true;
// .
// .
// .
// change icon here, or any
// other swing related change.
// .
// .
// run game
new Thread(){
public void run(){
// all non-swing computations
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// change back icons,
// and some other swing updates
}
}
isComputing = false;
}
}.start();
}
An event handler (mousePressed) souldn't take a long time to complete, there should be no sleeps in it. As long as it runs (or sleeps), nothing else can happen. The runtime is waiting for the handler to return and displays the image after that. I would move most of the code to a function called by a timer, and use a state variable to keep track of how intensely the wheels are spinning.

Displaying JLabel movement

I am attempting to create a simple animation in which a series of bubble rotate around a centre point. I have one version of animation where the bubbles spread from the centrepoint before they begin to rotate, which works fine, but as soon as I click one of the images (which sparks the animation) the screen freezes for a moment and then the bubbles appear in their end position, rather than showing each step they made.
What I have so far is:
while(bubble[1].getDegree() != 270)
{
long time = System.currentTimeMillis();
//the below if statement contains the function calls for
//the rotating bubble animations.
next();
draw();
// delay for each frame - time it took for one frame
time = (1000 / fps) - (System.currentTimeMillis() - time);
if (time > 0)
{
try
{
Thread.sleep(time);
}
catch(Exception e){}
}
}
public void draw()
{
for(int i = 1; i < bubble.length; i++)
{
iconLabel[i].setLocation(bubble[i].getX(), bubble[i].getY());
textLabel[i].setLocation((bubble[i].getX()+10),(bubble[i].getY()+10));
}
}
For clarity, the method "next()" merely changes the position of the bubble to the appropriate place, I know this to be functioning as I have had the animation work before but once I implemented the animation to JLabels it stopped working.
Any help would be appreciated.
The drawing is frozen because you block the event dispatch thread. Drawing is done in the same thread as the while loop, and since the loop prevents anything else happening while it's running, swing can get to drawing only after the loop is finished, so only the last position is drawn.
Use a swing Timer instead:
timer = new Timer(delay, new ActionListener() {
public void actionPerformed(ActionEvent e) {
// whatever you need for the animation
updatePositions();
repaint();
}
});
timer.start();
And then call timer.stop() when all the frames you need have been processed.

Java .drawImage : How do I "unDraw" or delete a image?

I need a certain image to be redrawn at different locations constantly as the program runs. So I set up a while loop that should move an image across the screen, but it just redraws the image on top of itself over and over again. What am I doing wrong? Is there a way to delete the old image before drawing it in a new location?
JFrame frame = buildFrame();
final BufferedImage image = ImageIO.read(new File("BeachRoad_double_size.png"));
JPanel pane = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int num = 0;
boolean fluff = true;
while (fluff == true) {
num = num + 1;
g.drawImage(image, num, 0, null);
if (num == 105) {
fluff = false;
}
}
}
};
frame.add(pane);
You can't code a loop in the paintComponent() method. The code will execute so fast that the image will only be painted in the final position, which in your case should be with an x position of 105.
Instead you need to use a Swing Timer to schedule the animation every 100 milliseconds or so. Then when the timer fires you update the x position and invoke repaint() on the panel. Read the Swing tutorial on Using Swing Timers for more information.
Putting a while loop inside a paintComponent method is not the way to do it. Instead, there should be some setup like the following:
...
final int num = 0;
final JPanel pane;
Timer timer = new Timer(10, new ActionListener() {
public void actionPerformed(ActionEvent e) {
num++;
pane.repaint();
}
});
pane = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, num, 0, null);
}
});
timer.start();
This will move the image ever 10 milliseconds, as specified in the Timer constructor.
This is a common issue people starting out in animation have, as I did. You can't 'remove an image' from the screen. However, you can repaint the entire screen, then redraw your image at a new location.
In psuedocode:
while (condition)
background(white); //or whatever color your background is
drawImage(x,y);
The code above clears the screen so it's safe for you to redraw your image. This effectively 'deletes' your image.
Edit: I didn't read your code, I just addressed your question. So other answers that fix your code are probably better than mine.

JLabel Icon not updating with setIcon (or other redundancies)

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();

Categories

Resources