I am using Eclipse WindowBuilder to build a GUI for my Java program. I am currently stuck as I have created a button and I have give the X and Y locations different variables. These variables change in a 'While' loop when the button is clicked and sends out an event.
I have tried looking at multi-threading. However I don't think this is the most viable option. Also if I did multi-thread I don't know which bit of the code I would have to put in the separate thread.
New button = Button button(X, Y, 100,100);
I am trying to increase the x and Y coords
Awt and Swing are not thread safe so, if you are trying to update a UI in the same thread you will have the "application freeze" behavior and the button will not change it's position if you click on it several times. You could disable the button meanwhile the loop is being executed and before starting the loop check that the button is not disabled. For example:
walkerButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
walkerButtonActionPerformed(evt);
}
});
private void walkerButtonActionPerformed(java.awt.event.ActionEvent evt) {
// if walker button is disabled exit the method
if (!walkerButton.isEnabled()) {
return;
}
// Disable the button before starting the loop
walkerButton.setEnabled(false);
int steps = 20;
int stepDistance = 2;
while (steps > 0) {
// Set the walker button new location
int x = walkerButton.getX() + stepDistance;
int y = walkerButton.getY() + stepDistance;
walkerButton.setLocation(x, y);
steps--;
}
// Enable the button after the loop execution
walkerButton.setEnabled(true);
}
Read also:
Java awt threads issue
Multithreading in Swing
Related
Whenever I choose to hard code an object (so far, I have sampled buttons, text fields and comboboxes), it does not appear on the associated form. Is there a separate piece of code that handles this, or can I use the following? Additionally, are layout bonds strictly necessary?
JButton startButton = new JButton("Start for loop ex");
startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0){
int start = 1;
int end = 5;
int answer = 0;
for (int i = start; i < end; i++){
answer = answer + i;
}
};
IDEOne showing the entirety of the code:
http://ideone.com/u7CuoG
I think you only created the button, but forgot to put it in the JFrame.
Assuming that this is a subclass of JFrame, you can do this to add the button to the frame:
this.add(startButton);
Also check if you have called setContentPane. If you have not, the button will fill up the whole frame.
It is only natural that dynamically added buttons don't appear in the design view because it would be very slow to compile and run your code every time you open the design view!
EDIT:
I ran the code you gave me and produced this frame. As you can see, the button is on the frame:
I am doing a Pacman game using A* algorithm in Java. I searched a lot of questions. I found a solution for one step. But I want to refresh my table in while block and my solution is just refreshing JTable according to the last step(just showing the result) in while(calculated all steps). But I want to refresh and show Pacman's places(location) step by step in while block. It has to look like Pacmans are moving. But I couldn't. My codes is below:
btnStartGame.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
//randomly placement of Pacmans
table_1.setValueAt(yellowPacman, locationyellowX, locationyellowY);
...calculating heuristics
//after calculation
newXYellow =locationyellowX;
newYYellow =locationyellowY+1;
nodeYellow = 10 * newXYellow + newYYellow;
while(heuristics != zero){
...enemy pacmans' movement
//after enemy pacmans' movement calculating yellow pacman's movement
if((newXYellow>=0 && newXYellow<10 && newYYellow>=0 && newYYellow<10) && !wallList.contains(nodeYellow)){
//calculate heuristic again
manhattanDistance[0][0] = Math.abs(newXYellow-locationblackX[0])+
Math.abs(newYYellow-locationblackX[0]);
manhattanDistance[0][1] = Math.abs(newXYellow-locationblackX[1])+
Math.abs(newYYellow-locationblackX[1]);
manhattanDistance[0][2] = Math.abs(newXYellow-locationblackX[2])+
Math.abs(newYYellow-locationblackX[2]);
fyellow[0] = manhattanDistance[0][0] + manhattanDistance[0][1] + manhattanDistance[0][2];
selectedNodeXYellow = newXYellow;
selectedNodeYYellow = newYYellow;
timer2.start();//updated
while(delay != 0)
delay--;
delay = 4000;
locationyellowX = selectedNodeXYellow;
locationyellowY = selectedNodeYYellow;
nodeYellow = 10 * selectedNodeXYellow+ selectedNodeYYellow;
timer3.start();//updated
while(delay != 0)
delay--;
delay = 10000;
}//ending if
}//ending while
}
}//ending action
timer2 = new Timer(ONE_SECOND, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
table_1.setValueAt(null, locationyellowX, locationyellowY);//I wanted to delete old moves
timer2.stop();
}
});
timer3 = new Timer(ONE_SECOND, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
table_1.setValueAt(yellowIcon, locationyellowX, locationyellowY);//here I want to show each moves step by step in while block
timer3.stop();
}
});
UPDATE 1 :
Delay was just an idea. Maybe algorithm is calculated too quickly and timers cannot be fired. But it didn't work and also does not timer suppose to be fired at each one second? still I've seen the last values of JTable.
I suspect your main issue here is that you need to understand how the various threads in a Java GUI application work. Specifically, if you have code executing in the event dispatch thread then there will be no updates to the UI while that code is executing. In your case you are making multiple updates to a JTable and then returning control to the display which will then show the last value.
The solution here is to introduce a timer element that executes each step of your algorithm in each tick of the timer and then returns control to display the result. Check the javax.swing.Timer class for details. I also suggest you read the sections 'concurrency in Swing' and 'How to use Swing Timers' in the Java tutorials.
I implemented a JFrame that contains some JLable's. I would like to change their appearance once they are clicked. The appended code should do so. In fact: It does not. Taking the same code and putting it into the run of an inner Thread-class does the job. The inner Thread-instance inverts the clicked JLable twice.
Can anybody give me a hint why the mouseClicked-method seems not to be able to affect the clicked JLable's appearance?
#Override
public void mouseClicked(MouseEvent e) {
if (clickable) {
for (Position p : positions.keySet()) {
JLabel lable = positions.get(p);
if (lable == e.getComponent()) {
pickedPosition = p;
LOGGER.info(pickedPosition + " pressed");
synchronized (lable) {
// store old colors
Color obg = lable.getBackground();
Color ofg = lable.getForeground();
// invert them
Color nbg = new Color(255 - obg.getRed(), 255 - obg.getGreen(), 255 - obg.getBlue());
Color nfg = new Color(255 - ofg.getRed(), 255 - ofg.getGreen(), 255 - ofg.getBlue());
// set them
lable.setOpaque(true);
lable.setForeground(nfg);
lable.setBackground(nbg);
// wait a while
try {
lable.wait(WAIT_WHILE_INVERTING_MS);
}
catch (InterruptedException i) {
LOGGER.warn(i.getMessage());
}
// switch back to initial
lable.setBackground(obg);
lable.setForeground(ofg);
}
e.consume();
}
}
}
}
There is no need for the synchronized block of code. All code executed from the event code will execute on the Event Dispatch Thread (EDT). Since you should always update the properties of components on the EDT you don't need to worry about other threads updating the component.
It looks like you want to temporarily change the Color of the label. The problem is the wait() method will block the EDT and prevent the GUI from repainting itself.
You can either:
Use a SwingWorker to start a Thread and then sleep for a period of time. Then when the worker is finished you can restore the color of the label. See Concurrency for more information and examples.
Use a Swing Timer to schedule the changes. See How to Use Swing Timers for more information.
I'm having a problem I'm making a pool game and I need the ballos to react when I simulate a hit, the program works like this, you click the direction and power to hit the ball and the click go, the go button is in the GUI class where my labels are created, the button calls a method from my main class that recieves the parameter and then with a while in it, changes the X and Y of the ball till the power is reduced to 0 and then stops, the code is working, but the ball moves until the while stops. So the while works and when the power int is 0 the while goes out and then the new X,Y are painted.
This is the funcion that the button calls, the button sends all the parameters
public void golpe(int pbola, int pvelocidad, String pdireccion, JLabel[] listalabels) throws InterruptedException{
listabolas[pbola].setVelocidad(pvelocidad);
listabolas[pbola].setDireccion(pdireccion);
while (listabolas[pbola].getVelocidad() > 0) {
moverBola(pbola, listalabels);
//System.out.println(listabolas[pbola].getPosX());
//System.out.println(listabolas[pbola].getPosY());
Thread.sleep(500);
//This line is supposed to change the X and Y of the object over and over
//but only does it till the end
listalabels[pbola].setLocation(listabolas[pbola].getPosX(), listabolas[pbola].getPosY());
}
}
Here is the function moverbola(), only copied one "if" so that the code doesn't look to big
private void moverBola(int pbola, JLabel[] listalabels) {
if (listabolas[pbola].getDireccion().equals("SE")) {
int pposX = listabolas[pbola].getPosX();
listabolas[pbola].setPosX(pposX + 1);
int pposY = listabolas[pbola].getPosY();
listabolas[pbola].setPosY(pposY + 1);
}
Swing is a single threaded framework. That is, all interactions with UI are expected to occur from within a single thread, known as the Event Dispatching Thread.
Any action that blocks this thread, will prevent the EDT from updating the screen or processing any new events.
Your while-loop is blocking the EDT, preventing it from painting any updates until after the while-loop is completed.
Take a look at Concurrency in Swing for more details.
There are a number of approaches you could take...
You could use a Thread, but this causes problems as you need to ensure that any changes you make to the UI are re-synced back to the EDT and this can become messy...
For example
You could use a javax.swing.Timer that ticks at a regular interval and you would update any internal parameters from within it's assigned ActionListener. Because the tick events occur within the EDT, it is save to update the screen from within it.
For example
You could use a SwingWorker to run the task in the background. It has methods for re-syncing updates back to the EDT, but might be a little over kill for your purposes...
Updated with a possible Timer example
Caveat- It is very hard to produce a reasonable example with only a code snippet, but, something like this might work
public void golpe(final int pbola, int pvelocidad, String pdireccion, final JLabel[] listalabels) throws InterruptedException{
listabolas[pbola].setVelocidad(pvelocidad);
listabolas[pbola].setDireccion(pdireccion);
Timer timer = new Timer(40, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
if (listabolas[pbola].getVelocidad() == 0) {
((Timer)evt.getSource()).stop();
} else {
moverBola(pbola, listalabels);
}
}
});
timer.setRepeats(true);
timer.start();
}
My question is straight.
I have made a simple app in neatbeans in which when I click a button the x coordinates of the text say a '#' keeps changing by 20.
heres the code:-
int x;
private void wActionPerformed(java.awt.event.ActionEvent evt)
{
x=x+20;
q.setLocation(x, 0);
}
this code simply moves the jlabel ( q ) to the right by 20 coordinates each time i click the jbutton ( w ).
now what i want is that when i click the button only ONCE then the position of the JLabel should keep increasing its x coordinate by 20 untill it has reached a specific x coordinate say 200.
i tried using for loops :-
private void wActionPerformed(java.awt.event.ActionEvent evt)
{
for(x=0;x<201;x=x+20)
{
q.setlocation(x,0);
}
}
but with this when I click the button, the jlabel directly moves to 200 x coordinate without stopping after every 20 coordinates...please help..
Regards,
Slinger
The problem with the above is that Swing is calling your incrementer and only performing a refresh once your incrementing function has completed. Instead you need to start up a separate thread to perform this animation and let Swing update after each increment.
Check out SwingUtilities.invokeLater() and the SwingWorker class. Here's a tutorial on SwingWorker.