I have look all over the web, and found no solution to my problem. For a AP Comp Sci project, I am making a Set of games, that will be run from a JFrame with JButtons. I have the games all ready, along with action listeners, but the games dont launch properly. The JFrame and JButtons are all setup correctly too.
private static class TetListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
GameCenter.quit();
GameCenter.startTetris();
}
}
GameCenter.quit() does nothing but run JFrame.dispose(), and GameCenter.startTetris(); constructs a new Tetris object, then run the play() method to start the game. All of Tetris is coded properly and works correctly when it is run in the main method (outside the actionlistener). But as soon as I put it in the ActionListener, it fails to be constructed properly. I tracked the problem down to:
public BlockDisplay(BoundedGrid<Block> board)
{
this.board = board;
grid = new JPanel[board.getNumRows()][board.getNumCols()];
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
SwingUtilities.invokeLater(new Runnable() // <<<<<<<<<<------------------- Problem Here
{
public void run()
{
createAndShowGUI(); // <<<<<<<<<<<<-------- Never Run
}
});
//Wait until display has been drawn
try
{
while (frame == null || !frame.isVisible()) // <<<<<<<-------- Never Resolved
{
Thread.sleep(1);
}
}
catch(InterruptedException e)
{
e.printStackTrace();
System.exit(1);
}
}
So the program always hangs. I also made a Pacman game that uses this SwingUtilities.invokeLater, so it doesnt work either. I cant figure out why this is happening or how to fix it.
Any help is appreciated. Let me know if you need any more info.
If the thread that runs SwingUtilities.invokeLater is already the swing event thread and you run in this while loop, yup, your application will hang.
Get rid of the while loop.
Related
I write Java SE 8 desktop application. It's got a Swing UI.
Platform:
Eclipse IDE
Windows 10 OS
Now when I close the main window, by pressing on the "X" on the top-right-corner, I have a listener to listen for such event.
The listener right here:
private void listenerForClosingResources(){
this.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
if(e.getID() == WindowEvent.WINDOW_CLOSING){
CountDownLatch continueOn = new CountDownLatch(1);
saveUnsavedTmpProject(continueOn);
try {
continueOn.await();
}
catch(InterruptedException ee) {
ee.printStackTrace();
}
}
}
});
}
So, I use the listener to identify the window closing event, and when that happens I ask the user whether or not to save the project (it's data on DB).
This method (saveUnsavedTmpProject(continueOn);) leads to the other window which supposed to take the name under which to save the project.
Now the CountDownLatch forces the main window to stay up, up till when the user confirms/rejects saving the project on the other panel.
The other class method which creates the window, leading to saving the project, is right here:
public static void getInstance(CountDownLatch continueOn, String openProjectName) {
if(frame == null) {
synchronized(SaveAsPane.class) {
if(frame == null) {
carryOn = continueOn;
if(!openProjectName.isEmpty()){
openProject = openProjectName;
}
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
frame = new SaveAsPane();
frame.setVisible(true);
frame.setLocationRelativeTo(MainGUI.getMainGUI());
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
}
}
Now, when I run the app, I don't get inside the run() method (and no window pops-up). But that only happens when I access this method only from the mentioned above listener. Which has the CountDownLatch, and it appears that it stops the execution of the new thread.
The latch gets counted-down when the user confirms/denies saving the project, so that the execution flow continues on.
Yet, I create the additional thread on the EventQueue.
How come that the thread gets stopped?
The Java group on facebook.com pointed me to the right direction.
The solution is this:
redefine what the close button (X) does on the main GUI.
And here it comes:
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
And now when I click the main GUI window's close button, the close does not lead to closing the window. Meaning that I don't need any longer the CountDownLatch class, which was stopping the main window from closing up (and waiting till the user counts-down on the other class).
In the end, I made the app to work in the way I like.
So I'm trying to display an image(ball) which I'll eventually control with user input. For know, the image just gets displayed over intervals using thread's sleep method.
I've made 2 classes, one that extends JPanel and the other extends JFrame.
The JPanel subclass looks like this:
public class BallPanel extends JPanel {
private Image ball;
private int x,y;
public BallPanel(){
try {
ball=ImageIO.read(new File("C:\\Users\\Owner\\Desktop\\ball.png"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
x=10;
y=10;
Thread thread = new Thread() {
#Override
public void run(){
loop();
}
};
thread.start();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(ball,x,y,null);
}
public void loop(){
while(true){
repaint();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
In the loop method I call the sleep method to allow repaint to be called over intervals. Then, loop() is called in the constructor.
The JFrame subclass looks like this:
public class BallFrame extends JFrame {
public BallFrame(){
setVisible(true);
setSize(800,800);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setContentPane(new BallPanel());
}
public static void main(String args[]){
//SwingUtilities.invokeLater(new Runnable() {
// #Override
// public void run() {
new BallFrame();
// }
//});
}
}
Now the interesting, or perhaps confusing thing, is that when I run the code as it is shown here, with the anonymous inner class commented out, the ball doesn't always appear. Sometimes I need to re-size the frame (i.e call repaint) before the ball is shown. However, when I call it through the even dispatch thread using the anonymous inner class the ball appears every time I run the code. What is the reason for this?
It has little to do with starting the UI from within the EDT or not (although you should cause that can cause lots of other weird and interesting issues) and more to do with the fact that you've called setVisible before you've established the contents of the UI.
This is possibly an example of a race condition between the system trying to get the EDT up and running and the OS calls responding before it's established.
In either case you SHOULD start the UI from within the EDT and call setVisible last.
Swing can be lazy about updating the UI, this is actually a deliberate design choice as well as a good idea. You don't always want the UI updated after each and every change you make (like adding/removing components), so it hands over some of the control to the developer to decided when it's best to revalidate container hierarchy and request repaints
I would also avoid using a Thread to update the state of the UI as this could cause dirty paints as Swing uses a passive rendering approach (painting when it feels it's required) and consider using a Swing Timer which updated from within the EDT OR use a BufferStrategy and employ a active rendering approach, which you can then control
i have problem in java and I do not know him and I resolved.
I created a simple program that inserts into the text JPanel using for and sleep function.
Like this(This is an example):
public class example{
JFrame frame....
..
..
public example(){
//ini frame and label.. then..
String s = "abcqweewqewqewqewqweqwqeweqweqwq";
//DO ANIMATION
try
{
for(int i = 0;i<s.length();i++)
{
JLABEL.append(String.valueOf(s.charAt(i)));
Thread.sleep(10);
}
}catch(Exception ex){}
}
public static void main.......{
new example();
}
}
It works perfectly (writes characters after a certain time interval)
But, if i call this main using other class-So waiting until everything renders and then the window appears (so does not animation).
Where is a problem? I hope, you understand me.
Swing is single threaded, and properly written swing code runs in the event dispatch thread. Your sample breaks the threading rule by creating the GUI outside the EDT, and also runs the loop in the main thread. Normally, when created correctly in the EDT, or as a response to an event from a button click or similar, the loop blocks the event dispatch thread so that no drawing can happen until the loop has completed.
You get that behaviour if you initialize the GUI in the event dispatch thread:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new example()
}
});
}
The proper way, instead of sleeping in the EDT, is using a Swing Timer.
To sum the above: your code appears to work only because it has the bug that it runs some of the UI code outside the event dispatch thread.
The goal is a GUI where in a window, having the play button pressed will release the GUI resources and start to run my game (the game is done outside of Swing, in LWJGL).
This is the first way I can see myself doing it. To me the safer option looks like this:
public static void main(String[] args) {
// setup gui objects
JFrame frame = ...;
frame.setVisible(true);
// wait for the play button to be pressed
synchronized(frame) {
frame.wait();
}
// free the gui objects, start the game
frame.dispose();
startGame();
}
// by the way, this method is called from the button's action listener
public void onPlayButtonPress(JFrame parent) {
// end the UI
synchronized(parent) {
parent.notify();
}
}
The reason this seems 'safe' to me is that the cleanup for the GUI and the game execution is done inside the main thread. Here is the second way I can see myself doing it, but I'm not sure how I feel about it:
public static void main(String[] args) {
// setup gui objects
JFrame frame = ...;
frame.setVisible(true);
}
public void onPlayButtonPress(JFrame parent) {
// free the gui objects
parent.dispose();
startGameInNewThread();
}
This second way of doing it seems more preferrable in that it is simpler, but I am worried of some problems coming up. For example:
Disposing the frame in the Event Dispatch Thread could mess things up?
Starting a new thread for the game while the main thread has already terminated?
So the reason I'm asking this question is because I'm looking for the best way to implement this, but I'm also kind of curious if and why any wierd things will happen if I implement my program the second way.
Can anyone tell me why does this timer run only once?
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TimerTest implements ActionListener{
private Robot r;
private Timer t;
private int i;
public TimerTest(){
i = 0;
try {
r = new Robot();
} catch (AWTException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
t = new Timer(1000, this);
t.setRepeats(true);
t.start();
}
public static void main(String [] args){
new TimerTest();
}
#Override
public void actionPerformed(ActionEvent arg0) {
i++;
System.out.println("Action..." + i);
}
The funny thing is that, if I decrease the delay in the Timer to just 100, it works as expected. And what's even funnier is that if I delete the code in which I initialize the Robot, it doesn't work at all, the program terminates as soon as I run it.
I've tried this on Windows 7 and on Ubuntu (although on Ubuntu I couldn't use the Robot at all, since I get an exception. Something related to rights, maybe).
Your main is processed so the program stops. You can test it by using this code, adding it to TimerTest()
JFrame testFrame = new JFrame();
testFrame.setVisible(true);
testFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
That JFrame keeps your main not from finshing, when you close the Frame the TimerTest ends. Which concludes your main which causes the main to finsh. Ending the program and stoping your swing timer.
See "main exits before javax.swing.Timer's start() can start" at the bug database.
Evaluation
Described behavior - when application exits before Swing timer is started - is correct. Here is what's going then:
Swing timer is created.
Separate thread for swing timer is started. It will notify attached actionListeners when the timeout is passed by posting an instance of InvocationEvent to EDT.
Main thread exits.
At this moment there is no non-daemon threads running in JVM. Application is terminated.
..the evaluator goes on to add..
..This looks like a RFE rather than a defect.
One surefire way to make it behave is to create a GUI element and display it. Which is why I asked earlier..
..why exactly are you creating the timer without any GUI elements? Is this for repeated screen-shots?
To handle that situation, I would typically create and show a frame to allow the user to configure the rate and area for screenshots, then minimize the frame and begin processing when the user clicks:
Screen Capture!