Calling the same animation with different values when it's completed - java

I want to do different manipulations on Label inside Table in libGDX.
in my Table class I create a Label and scale\move\rotate it, I'm trying to call to this actions every time the actions is finishes so each time It will run on different string, but I got a crash because of calling to my self every time (i think).
a= new Label("", mLabelStyleAmount);
addActor(a); // in a Table class
action = Actions.run(new Runnable() {
#Override
public void run() {
lunchText(i);
}
});
private void lunchText (int i) {
a.setText(strings[i]);
ScaleToAction up = Actions.scaleBy(30, 20, 5)
a.setPosition(a.getWidth() * 0.2f, 50);
a.addAction(Actions.sequence(up, action));
i++;
}
Is this is the right way to call the same method each time I finished?

The exception you've got is being caused by infinite recurrence that being caused by adding action in method that is being fired by action :) It means that every time you add the action to your action you add action again and so on and so on...
Second thing is that when you are adding many action by using addAction method these actions are parallel not sequential!
The resolution is to use libGDX SequenceAction and to generate all action at the beginning. It should like:
SequenceAction sequence = Actions.sequence();
for(int i = 0; i < string.length; i++) {
sequence.addAction(Actions.run(new Runnable() {
#Override
public void run() {
a.setText(strings[i]);
a.setPosition(a.getWidth() * 0.2f, 50);
}
}, Actions.scaleBy(30, 20, 5)));
Another way is to check in render() method if a do not have any actions (what means that last actions is finished) and then add new action
//render()
if(a.getActions.size == 0)
addActionToA();

Related

How to fill the second progress bar after the first one is done?

I have a problem with the progress bar, I have created several progress bars and I want to fill the first one with a specific time interval then after it done the second one start filling, I've done the first one like this
final ProgressBar pb_first = findViewById(R.id.Progressbar_first);
*
*
*
pb_first.setMax(10);
pb_first.setProgress(0);
final int[] currentProgress1 = {0};
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
currentProgress1[0] += 1;
pb_first.setProgress(currentProgress1[0]);
if(currentProgress1[0] != 10){
new Handler().postDelayed(this,1000);
}
else{
Toast.makeText(MainActivity.this, "The first step is OVER!!", Toast.LENGTH_LONG).show();
}
}
}, 1000);
but when I try to make the second one inside the else statement it won't work, I even tried to create an integer that changes when the above code is finished "in the else statement", and create an if-statement if(index == 2){} but it did not work as well, the app just stucks when starting it. Anyway to fix this?

The game of life recurrent function probelm

I have a problem with implementation of my Game of Life in Java.
In GUI I have buttons which decide of inicial state of the game (oscilator, glider etc), then using Action Listener I set the first board and show it.
Then I have a function that count neighbours of my cell and set colors of my cells.
But I have a problem when I want to repeat game n times, because I don't know how to set time interval.
At this moment I don't see every step of game, but just the last one.
Below is my ActionListener:
private ActionListener buttonsListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if (source == button1)area = setButton1(getBoardWidth(), getBoardHeight());
if (source == glider) area = setGlider(getBoardWidth(), getBoardHeight());
if (source == oscilator) area = setOscilator(getBoardWidth(), getBoardHeight());
setBoard(area, board);
}
};
Function setBoard() takes array of ints with 0 and 1, and convert it to JButton[][] array with colors.
I tried to use Overrided method run() that include startTheGame() function, which checks neighbourhood and set array of ints. I need to do this multiple times but I can't set time intervals.
#Override
public void run() {
startTheGame(area);
setBoard(area, board);
}
You should use this timer schedule.
So you have to define a custom TimerTask like this:
import java.util.TimerTask;
public class UserTimerTask extends TimerTask{
#Override
public void run() {
startTheGame(area);
setBoard(area, board);
}
}
And then wrapping your code like this:
// daemon means, background. If every task is a demon task, the VM will exit
Bolean isDaemon = false;
Timer timer = new Timer("nameOfThread",isDaemon);
TimerTask task = new UserTimerTask();
// Schedules the specified task for repeated fixed-delay execution, beginning after the specified delay
// both parameters are in milliseconds
timer.schedule(task,0,1000);

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?

Changing the delay of the timer without creating a new one every time the method runs

So basically I have a timer method in my program which uses the integer z as it's parameter as well as the delay for the timer itself. But every time I run this method, it creates a new timer not deleting the old one. So I decided to add an if else block that made it so that it only created a timer on the first time but now it's saying that it might not have been initialized because it was initialized in the if else block. Can someone help me?
public void timer(int z) {
int count = 0;
Timer tester;
z = (60000 / z);
decide = true;
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {noteDecider();}
};
if(count == 0) {
tester = new Timer(z, taskPerformer);
tester.start();
}
else {
tester.setDelay(z);
tester.start();
}
count++;
}
I would say that if you are concern about optimizing your code you should look into optimizing your Timer class. Like moving the ActionListener object inside Timer itself and more. All your timer(int z) method is doing is trying to use an object to keep track time not managing the lifecycle of Timer objects.

Displaying graphics as they paint in swing

I created a maze generator in swing for a class, and it works great. The only thing is, I want to show the maze being created in realtime, but the way I have everything set, it only updates after all the calculations have completed. I am using paintComponent and repaint in my code. How do I have it show the JFrame and draw lines immediately, rather than doing the algorithm and showing them all at the end?
Here is the relevant code:
public void generateMaze() {
Stack<Box> stack = new Stack<>();
int totalCells = Finals.numCol * Finals.numRow, visitedCells = 1;
Box currentCell = boxes[0][0];
Box nextCell;
stack.add(currentCell);
while (visitedCells < totalCells) {
nextCell = checkNeighbors(currentCell.xCoord, currentCell.yCoord);
if (nextCell != null) {
knockWalls(currentCell, nextCell);
stack.add(currentCell);
currentCell = nextCell;
visitedCells++;
} else {
currentCell = stack.pop();
}
}
repaint();
}
Here is my paintComponent method override
public void paintComponent(Graphics g) {
for(int x = 0; x < Finals.numRow; x++) {
for(int y = 0; y < Finals.numCol; y++) {
if(boxes[y][x].top != null)
boxes[y][x].top.paint(g);
if(boxes[y][x].bottom != null)
boxes[y][x].bottom.paint(g);
if(boxes[y][x].left != null)
boxes[y][x].left.paint(g);
if(boxes[y][x].right != null)
boxes[y][x].right.paint(g);
}
}
}
The knockWalls method sets certain walls equal to null, which causes them to not be drawn in the paintComponent method. I'm still fairly new at a lot of this, so I apologize if some of the code isn't super high quality!
Thanks everyone.
As MadProgrammer already pointed out in the comments, you are almost certainly blocking the Event Dispatch Thread. This is the thread that is responsible for repainting the GUI, and for handling the interaction events (like mouse clicks and button presses).
So presumably, you start the computation via a button click, roughly like this:
// The actionPerformed method of the button that
// starts the maze solving computation
#Override
void actionPerformed(ActionEvent e)
{
generateMaze();
}
That means that the event dispatch thread will be busy with executing generateMaze(), and not be able to perform the repainting.
The simplest solution would be to change this to something like
// The actionPerformed method of the button that
// starts the maze solving computation
#Override
void actionPerformed(ActionEvent e)
{
Thread thread = new Thread(new Runnable()
{
#Override
public void run()
{
generateMaze();
}
});
thread.start();
}
However, some care has to be taken: You may not modify Swing components from this newly created thread. If you have to modify Swing components, you have to put the task that performs the actual modification of the Swing component back on the EDT, using SwingUtilities.invokeLater(task). Additionally, you have to make sure that there are no other synchronization issues. For example, the lines
if(boxes[y][x].top != null)
boxes[y][x].top.paint(g);
are still (and have to be!) executed by the event dispatch thread. In this case, you have to make sure that no other thread can set the boxes[y][x].top to null after the EDT has executed the first line and before it executes the second line. If this may be an issue in your case, you might have to provide a bit more code, e.g. the code that is showing where and how the boxes[y][x] are modified.

Categories

Resources