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).
Related
So I am trying to run a code, open a GUI window, choose between two buttons, which set a value and then with this value continue the rest of the code.
I have seen similar questions or Tutorials, but I do not find the suitable solution for my problem.
As I have already seen, JFrame, ActionListener and ActionEvent have to be used in order to make a GUI with a button.
An Object which extends JFrame and implements ActionListener is writen in the main method.
The Problem is, that the code writen in the main method opens the GUI window and continues to run. I just want that the code waits till the user clicks a button and then continue.
A sub-solution is, to write the code that I want in the actionPerformed method but:
The GUI window remains open, after the selection of a button
It makes no sense to me to write the rest of the code in the actionPerformed method.
Or to write a while loop until a button is clicked. A more sensible solution has to exist that I am not aware of or I do not understand the way this should work.
Here is a part of the code.
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == testStringA) {
setVariableTo = "testString_a";
try {
runMethodWithNewVariable(setVariableTo);
} catch (IOException e1) {
e1.printStackTrace();
}
System.exit(0);
} else {
setVariableTo = "project";
try {
runMethodWithNewVariable(setVariableTo);
} catch (IOException e1) {
e1.printStackTrace();
}
System.exit(0);
}
}
Instead of a JFrame, why don't you use a JOptionPane (showOptionDialog) with two buttons, "string A" and "project" instead of "Yes" and "No", for example?
JOptionPanes like "show Option Dialog" are intrinsically blocking. If you put one in your main() method, execution will "wait" for the user to select something in the dialog and the dialog will return an indicator to what was selected before execution in main() continues.
At the begining of your program, show a modal JDialog to the user! You can do this using JOptionPane.show() methods, like this:
String[] buttonTexts = {"first","second"}; //create the button texts here
//display a modal dialog with your buttons (stops program until user selects a button)
int userDecision = JOptionPane.showOptionDialog(null,"title","Select a button!",JOptionPane.DEFAULT_OPTION,JOptionPane.PLAIN_MESSAGE,null,buttonTexts,buttonTexts[0]);
//check what button the user selected: stored in the userDecision
// if its the first (left to right) its 0, if its the second then the value is 1 and so on
if(userDecision == 0){
//first button was clicked, do something
} else if(userDecision == 1) {
//second button was clicked, do something
} else {
//user canceled the dialog
}
//display your main JFrame now, according to user input!
You basically have two threads running - the main thread and the GUI thread. You don't explicitly create the GUI thread but it is there.
You can use a number of techniques to synchronise these two threads. The most basic is the good old synchronized, wait and notify. Something a Semaphore can also be used. In the main thread you would create the GUI and wait until a condition is met. In the GUI thread (i.e. actionPerformed) you would notify.
I have a following situation: my program repeatedly calls something that makes a JFrame with text appear. I read the text from that frame. The frame has a special type, let's call it MyFrameType, so I recognize it by the type, and dispose of the frame at the end of each call, in all possible way of closing a frame I know of... (the following code is within a loop)
callMyFrame();
Frame[] frames = Frame.getFrames();
for (Frame openFrame : frames) {
if (openFrame instanceof MyFrameType) {
MyFrameType myFrame = (MyFrameType) openFrame;
(do something, read the frame etc.)
myFrame.setVisible(false);
myFrame.dispose();
myFrame.dispatchEvent(new WindowEvent(
myFrame,
WindowEvent.WINDOW_CLOSED));
break;
}
}
Now, the problem is: while the frame gets actually closed (which is not always case with the last frame for some reason - sometimes it gets closed, sometimes not), the closed frames are still listed by the frames array and the program ends up reading from the wrong frame - the first one of MyFrameType it finds, although only one of them is actually open. I know that getFrames() gets all frames created by the application. But how do I exclude those disposed frames, so that it doesn't just pick a random previously created, long forgotten frame? The frames in question have apparently no owner, so that removing ownerless frames does not do the job.
You can just check if the JFrame is displayable, here is a simple example that you can use to verify:
JFrame jFrame = new JFrame();
jFrame.setVisible(true);
jFrame.dispose();
System.out.println(jFrame.isDisplayable());
Output:
false
So in your loop instead of just checking if the JFrame is an instanceof MyFrameType you can do:
for (Frame openFrame : frames) {
if (openFrame instanceof MyFrameType && openFrame.isDisplayable()) {
}
}
You should set the frame in the array to null, or otherwise indicate that it is "deleted". Also, to do this you need to use a standard for-loop instead of the enhanced for-loop, something like this:
Frame[] frames = Frame.getFrames();
for(int i=0; i<frames.length; i++) {
if (frames[i] instanceof MyFrameType) {
(do something, read the frame etc.)
frames[i].setVisible(false);
frames[i].dispose();
frames[i].dispatchEvent(new WindowEvent(
frames[i],
WindowEvent.WINDOW_CLOSED));
frames[i] = null;
break;
}
}
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.
There is this article:
Someone jumped the queue!
Every now and then it appears that some swing events are processed in the incorrect order in the Event Queue (and nothing gets my blood boiling like when someone cuts into a queue) resulting in strange behavior. This is best illustrated with a small code snippet. Read the snippet below and think carefully in what order you imagine events will take place.
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
repaint();
doSomething();
}
});
Most developers would image that repaint() method will result in a painting operation taking place before the doSomething() method call. However this is actually not the case, the call to repaint() will create a new paint event that will be added to the end of the Event Queue. This new paint event will only be processed (dispatched) after the current Action Event has completed. This means that the doSomething() method will be executed before the new Paint Event on the queue is dispatched.
The key point here is that calls to repaint() will create a new paint event that will be added to the end Event Queue and not processed immediately. This means that no events jump the queue (and my blood can remain at its correct temperature).
(source)
My question is, how can I force Swing to do the repaint(); BEFORE doSomething();?
Also, if there were calls to the repaint() method WITHIN the doSomething(); they would be executed only after doSomething(); is completed. Is there a way I can pause the doSomething(); mid-executin, then throw in the reapaint();, get done with it, and then resume doSomething();?
Only solution I have found so far is this(link), but it's not really practical...
Well, you and the author of the quoted article are missing the point here. "repaint" method calls simply inform the repaint manager that:
There is a component to repaint (on which you call "repaint")
It should be repainted with (x,y,w,h) clip (if you call "repaint" w/o specifying rect -it will be the whole component bounds, (0,0,w,h))
So it doesn't really matter when the repaint will occur since you might not even notice it if you are calling A LOT of repaints one by one for the same component. That is also why such consequent calls might get merged. Check this example:
private static int repaintCount = 0;
public static void main ( String[] args )
{
final JComponent component = new JComponent ()
{
protected void paintComponent ( Graphics g )
{
try
{
// Simulate heavy painting method (10 milliseconds is more than enough)
Thread.sleep ( 10 );
}
catch ( InterruptedException e )
{
e.printStackTrace ();
}
g.setColor ( Color.BLACK );
g.drawLine ( 0, 0, getWidth (), getHeight () );
repaintCount++;
System.out.println ( repaintCount );
}
};
component.setPreferredSize ( new Dimension ( 200, 200 ) );
JFrame frame = new JFrame ();
frame.add ( component );
frame.pack ();
frame.setLocationRelativeTo ( null );
frame.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );
frame.setVisible ( true );
new Thread ( new Runnable ()
{
public void run ()
{
try
{
Thread.sleep ( 1000 );
}
catch ( InterruptedException e )
{
e.printStackTrace ();
}
System.out.println ( "Starting repaint calls" );
for ( int i = 0; i < 100000; i++ )
{
component.repaint ();
}
System.out.println ( "Finishing repaint calls" );
}
} ).start ();
}
This is the approximate output you will see (might vary depending on computer speed, Java version and lots of other conditions):
1
Starting repaint calls
2
3
4
5
6
Finishing repaint calls
7
8
"1" - the initial repaint when frame is displayed.
"2,3,4..." - other seven repaints occured due to the calls from a separate non-EDT thread.
"But i have called 100000 repaints, not 7!" - you will say. Yes, repaint manager merged those that were similar and in the same time in the repainting queue. That is made to optimize repaints and speedup the UI overall.
By the way, you don't need to call repaint from EDT since it doesn't perform any real painting and just queue your component update for future. It is already thread-safe method.
To summ up - there should be no situations when you really need to repaint the component right before doing some other action (that could also cause its repaint again). Just call the repaint when you need to repaint the component (with specified rectangle when possible) - repaint manager will do the rest. That works well unless you put some calculations inside the paint method which is totally wrong and might cause a lot of problems.
repaint() adds a new paint request to the end of the queue of the Event Dispatch Thread (EDT). So making several calls to repaint() within doSomething() will only repaint after doSomething() completes. (I assume doSomething() is always called from the EDT. Your code example calls doSomething() from insideactionPerformed which is always called from the EDT.)
The reason paint() requests are queued up is to decrease the number of times a component is painted. Queuing up repaint() requests allows several methods to mark different components as dirty so they can all be repainted at the same time in one expensive paint() operation.
If you really want to force a repaint immediate, there are methods like paintImmediately(Rectangle r) and paintImmediately(int x, int y,int w,int h)but you will have to know the dimensions to repaint.
You can also always call paint(Graphics g) yourself if you have a reference to the current Graphics that the Swing component is using. (You can also use this technique to create your own graphics object from a Image object, if you want to take a screenshot and write it a picture file).
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.