Reputation: 311
I am trying to create a kind of simplified graphics library on top of the built-in Java graphics system. I want to use it in teaching so students can create graphical programs without needing to create their own classes, or especially need to use inheritance.
Anyway, as I have it, the windows do not close as I expect them to and I cannot figure out why. The weird thing is that if I have a println in the main program loop it does work. What's going on? Here is a minimal example:
package test;
import javax.swing.JFrame;
import java.awt.event.WindowListener;
import java.awt.event.WindowEvent;
import java.util.Queue;
import java.util.LinkedList;
/** enumeration of the different types of events which a window can produce */
enum EventType {
Closed,
KeyPressed,
KeyReleased,
MousePressed,
MouseReleased,
MouseMoved
}
/** a class which represents an event which a window can produce */
class Event {
private EventType t;
/** create a new event of a given type */
public Event(EventType type) {
t = type;
}
/** check which type of event it is */
public EventType getType( ) {
return t;
}
}
/** a graphics window */
class Window implements WindowListener {
private JFrame frame;
private boolean open;
private Queue<Event> events;
/** create the window */
public Window(String title, int width, int height, boolean resizable) {
frame = new JFrame(title);
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
frame.setSize(width, height);
frame.setResizable(resizable);
frame.setVisible(true);
frame.addWindowListener(this);
events = new LinkedList<>( );
open = true;
}
/** checks whether the window is still open or not */
public boolean isOpen( ) {
return open;
}
/** closes the window */
public void close( ) {
open = false;
frame.dispose( );
}
/** returns the next event, or null if there is none */
public Event pollEvent( ) {
return events.poll( );
}
/* functions which implement window listening */
public void windowOpened(WindowEvent e) { }
public void windowIconified(WindowEvent e) { }
public void windowDeiconified(WindowEvent e) { }
public void windowActivated(WindowEvent e) { }
public void windowDeactivated(WindowEvent e) { }
public void windowClosed(WindowEvent e) { }
public void windowClosing(WindowEvent e) {
System.out.println("Adding close event");
events.add(new Event(EventType.Closed));
}
}
public class Test {
public static void main(String args[]) {
// create the window
Window window = new Window("Hello world!", 800, 600, false);
// while the window is open
while (window.isOpen( )) {
// check for events
Event event = window.pollEvent( );
if (event != null) {
switch (event.getType( )) {
// handle the window close event
case Closed:
System.out.println("Calling close");
window.close( );
break;
}
}
// when this line is un-commented, it works as expected???
//System.out.print('.');
}
System.out.println("All done!");
}
}
Upvotes: 1
Views: 335
Reputation: 311
OK, I figured it out. The issue was a lack of synchronization between the Java event threads and my main thread. My main thread was constantly calling which pulls an event from the event Queue.
Then the Java event thread would at some point add the close event to the queue. This was not synchronized, so the event was somehow lost. I'm guessing that it was called "during" a check of the queue and was not committed.
Adding the "synchronized" keyword to "windowClosing" which enqueues events, and "pollEvent" fixed the issue.
Thanks all!
Upvotes: 1
Reputation: 12332
Make sure you are calling dispose()
from the EDT. This should work for you:
switch (event.getType()) {
// handle the window close event
case Closed:
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
System.out.println("Calling close");
window.close();
}
});
break;
}
Upvotes: 2
Reputation: 17548
Try changing
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
to
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
Upvotes: 1