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.
Related
I'm a beginner in Java programming and have come across an issue (probably an easy one to solve).
I am experimenting with Java GUI and wish to create a window in which the colours of an array are cycled through until there are no more colours. I believe I can do this using a for loop and cycling through the array, however I do not know how to loop through the background colour.
Any help and explanation would be appreciated.
public void flashColor() {
Color [] color = { Color.red,Color.orange,Color.green };
int i = 0;
for(i=0;i<color.length;i--){
getContentPane().setBackground(Color(i));
}
}
This line tells me:
getContentPane().setBackground(Color(i));
that yours appears to be a Swing GUI (a key bit of information that you left out of your question!), and so you need to take Swing threading into consideration. Your current code will in fact loop through all the colors, but it will do so immediately, and on the Swing thread so that the GUI will have no way to paint any of the colors other than the last one. The solution: use a Swing Timer and not a for loop. Inside the timer advance an index int variable and use it to show the color.
Something like:
getContentPane().setBackground(colorArray[0]);
int delay = 1000; // for 1 second
Timer myTimer = new Timer(delay, new ActionListener() {
int index = 0;
public void actionPerformed(ActionEvent e) {
index++;
if (index >= colorArray.length) {
((Timer)e.getSource()).stop(); // stop the timer
} else {
getContentPane().setBackground(colorArray[index]);
}
}
});
myTimer.start();
The code has not been tested, and you'll want to read the Swing Timer tutorial for the details.
Note the key here is that yes you need to loop, and to pause (so that the color can be seen) but you need to do your looping and pausing in a thread thread is off of the Swing event dispatch thread (or EDT). Yes you could do this using a SwingWorker, but that is a way more difficult way to do this. It is far easier to use a Swing Timer to do this for you. Note that it uses a background thread invisibly for you.
I have fairly simple question I didn't see properly answered anywhere.
I'm designing a Java applet using java.awt. What I'm trying to do is to have Java wait a few seconds between executing different parts of code in a method for a simple graphical animation.
So it goes like this:
runAnimation() {
// draw red shapes
// wait 2 seconds so the shapes remain visible
// set color of shapes to green and repaint
}
As suggested elsewhere, if I use something like
try {
// do first task
Thread.sleep(2000);
// do second task
} catch (InterruptedException e) {
}
the program only shows the results of the second task after waiting 2 seconds ie I never see the red shapes. I want to see the red shapes for two seconds and then have them set to blue and so on.
You don't say what GUI / graphics library you're using which is key information. If Swing or AWT, then use a Swing Timer to do your pausing. You should not use Thread.sleep(...) for this as you would put the GUI's event thread to sleep, causing the whole application to freeze.
e.g.,
someColor = Color.RED;
int delay = 2000;
repaint()
Timer swingTimer = new Timer(delay, new ActionListener() {
public void actionPerformed(ActionEvent e) {
someColor = Color.GREEN;
repaint();
}
});
swingTimer.setRepeats(false);
swingTimer.start();
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();
}
Got a problem with ComponentListener. I'm using it to check if a certain component is resized, and to update some stuff if it is.
The code looks like this though this probably won't be much use to you:
#Override
public void componentResized(ComponentEvent e) {
// Graph resized, reposition slice nodes
Component c = e.getComponent();
if (graphHeight > 0) {
if (c == graph) {
int offset = (c.getHeight() - graphHeight) / 2;
if (offset != 0) {
try {
controller.shiftSlice1NodesY(offset);
} catch (GraphIntegrityException e1) {
logger.error(e1.getMessage(), e1);
}
graphHeight = c.getHeight();
}
}
} else {
graphHeight = c.getHeight();
}
}
For one section of my code I need to disable this listener. That looks like this:
graph.removeComponentListener(this);
controller.parseFile(filename);
graph.addComponentListener(this);
Everything goes smoothly until I add the component listener again. At this point the componentResized method is called about 20 times. It has possibly buffered the resize events from what I can see. Anyone know what's going on here?
Looks like you are trying to modify a component off the Event Dispatch Thread (EDT). That's not even a good idea in AWT, let alone Swing.
Other than get all the AWT/Swing stuff on the right thread, part of the fix should be to get the listener check state to see if it should execute its body, rather than attempting to remove and add the listener.
I have an application which opens multiple JIFs, But I only want to create a single instance of the JIF, so I use these function to check that, and I use dispose to close the JIF after a key is pressed(JDesktopPane.getSelectedFrame().dispose()). However after 2-3 successive disposes, it doesn't create a new JIF? Am I doing anything wrong over here?
public static void setInternalFrame(final JInternalFrame internalFrame) {
log.debug("CurActiveInternalFrame " + ShoppyPOSApp.getCurrentActiveInternalFrame(), null);
log.debug("Incoming internalFrame " + internalFrame, null);
boolean isFrameFound = false;
try {
// Have a check whether the DesktopPane contains the internal Frame
// If yes bring it to front and set the focus
for (int i = 0; i < ShoppyPOSApp.frame.mainDesktopPane.getAllFrames().length; i++) {
if (ShoppyPOSApp.frame.mainDesktopPane.getAllFrames()[i].getClass() == internalFrame.getClass()) {
isFrameFound = true;
}
}
if (!isFrameFound) {
internalFrame.setVisible(true);
internalFrame.setLocation(
ShoppyPOSApp.frame.mainDesktopPane.getWidth()/ 2 - internalFrame.getWidth() / 2,
ShoppyPOSApp.frame.mainDesktopPane.getHeight() / 2 - internalFrame.getHeight() / 2
);
ShoppyPOSApp.frame.mainDesktopPane.add(internalFrame);
}
internalFrame.setSelected(true);
} catch (Exception e) {
log.debug(e.toString(), null);
}
}
You are comparing the classes of your input parameter and your desktops internal frames in your for loop. This will always be true as your parameter is an instance of JInternalFrame and the getAllFrames method returns an array of JInternalFrames. Why not just do a regular comparison? :
ShoppyPOSApp.frame.mainDesktopPane.getAllFrames()[i] == internalFrame
I would recommend using HIDE_ON_CLOSE as your default close operation on the frames and using setVisible(false) in your key listener instead of dispose(). When frames are disposed they are closed and you should not try and reuse a frame after is has been closed. If you just hide the frame it will still be a child of the desktop pane so you shoud add a call to setVisible(true) when you find a frame in your setInternalFrame method.
It sounds like you're getting inconsistent behaviour (you say it fails after two or three disposes). This suggests to me that you have an event thread problem. Is your setInternalFrame being called on the event thread? Are you familiar with the Event Dispatch Thread and are you using it correctly?
I don't think dispose is doing what you mean for it to do. dispose gets rid of the operating system "peer" of your frame. But if you intend to show that frame again, then you shouldn't throw away its underpinnings!
I'd go with setVisible(false) on the JIF to hide it. Then you can re-activate it with setVisible(true).