This question already has an answer here:
While loop with delay makes JFrame unresponsive
(1 answer)
Closed 9 years ago.
I am making a simple PopUp game where the code below calls a new instance of a class called PopUp. PopUp is a Jframe with a button on it. When the constructor is called inside the loop the button is not displayed. However when the loop is removed the button is displayed just fine. Please help me. Thank you.
public void game() {
PopUp p1;
while(!gameover) {
try {
//If block to set the difficulty of the game
if(diff==0)
TimeUnit.MILLISECONDS.sleep(1000);
else if(diff==1)
TimeUnit.MILLISECONDS.sleep(750);
else if(diff==2)
TimeUnit.MILLISECONDS.sleep(500);
else if(diff==3)
TimeUnit.MILLISECONDS.sleep(250);
else if(diff==4)
TimeUnit.MILLISECONDS.sleep(100);
p1 = new PopUp(); //keep
p1.setLocation(((int)(Math.random()*2000)), ((int)(Math.random()*1000)));
popUpsOpen++;
} catch (InterruptedException ex) {
Logger.getLogger(PopUpGame.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
Try to call Game constructor with different Thread.
Thread queryThread = new Thread() {
public void run() {
new game();
}
};
queryThread.start();
and in Game constructor show the popup with UI thread
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
p1 = new PopUp(); //keep
p1.setLocation(((int)(Math.random()*2000)), ((int)(Math.random()*1000)));
popUpsOpen++;
}
});
i think the button is not displaying because the UI thread busy with looping,so the button doesnt get chance to rendered by UI thread
place the these statements after the try-catch block, and also check the value of the variable gameover.
p1 = new PopUp(); //keep
p1.setLocation(((int)(Math.random()*2000)), ((int)(Math.random()*1000)));
popUpsOpen++;
Related
This question already has answers here:
Calling a method from a JButton is freezing a JFrame?
(2 answers)
Display indeterminate JProgressBar while batch file runs
(1 answer)
Something seems wrong with the layout, JButton showing unexpected behaviour at resize of the window
(4 answers)
Closed 5 years ago.
I am trying to make a program that has a toggle button (regular JButton) that when clicked, runs a while loop that runs until the button is clicked again to stop it.
I have done this, however, when I click the button, the entire JFrame freezes because of it being stuck in the while loop, as the loop will run forever until the button is pressed again. However, it is impossible to click the button again because the JFrame freezes. The button itself also just stays blue because the JFrame freezes before the colour change occurs; right before I click the button.
My code looks something like this:
boolean isRunning=false;
private void buttonClickEvent(ActionEvent evt) {
if(isRunning){
isRunning=false;
System.out.println("Stopped running!");
jButton.setText("Start Running");
} else { // BELOW IS THE CODE THAT CAUSES IT TO LOCK
isRunning=true;
jButton.setText("Stop Routine");
while(isRunning){
// DO STUFF
}
}
}
EDIT: I tried doing the following code (below) and it does print the text and allow the colour change to occur in the button, but the UI still freezes quickly afterward.
boolean isRunning=false;
private void buttonClickEvent(ActionEvent evt) {
if(isRunning){
isRunning=false;
System.out.println("Stopped running!");
jButton.setText("Start Running");
} else { // BELOW IS THE CODE THAT CAUSES IT TO LOCK
isRunning=true;
jButton.setText("Stop Routine");
new Thread(new Runnable() {
public void run() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
while(isInRoutine){
System.out.println("lolk");
}
}
});
}
}).start();
}
}
What I am trying to do is an Appled which throws 2 threads, each running a counter which increases itself via an infinite loop
I then use a while(true) in the Applet's paint() method, which continuously paints the counters, the problem is that I have also 2 buttons, each intended to stop each thread, but the infinite loop in the paint() method doesn't let me neither click none of them nor close the Applet's window nor anything
Here a screenshot followed by the code
btw I'm certain the problem is the paint() loop as if I disable the loop I can interact with the buttons, but the counters are obviously not updated, and weird thing is that I put the mouse cursor over the buttons to show it took the form like when you want to resize a windows but the imprpant didn't capture it :/
http://i.imgur.com/PJnDI4u.png
public class MainApplet extends Applet implements ActionListener {
private static final long serialVersionUID = -2500043816999861110L;
private Font fuente;
private Button bUno, bDos;
private HiloContador hUno, hDos;
public void init() {
setBackground(Color.LIGHT_GRAY);
fuente = new Font("Verdana",Font.BOLD,26);
bUno = new Button("Parar");
bUno.addActionListener(this);
bDos = new Button("Parar");
bDos.addActionListener(this);
bUno.setSize(40,20);
add(bUno);
bDos.setSize(40,20);
add(bDos);
hUno = new HiloContador(20);
hUno.start();
hDos = new HiloContador(40);
hDos.start();
}
#SuppressWarnings({ "deprecation", "static-access" })
public void actionPerformed(ActionEvent e) {
if(e.getSource().equals(bUno)){
hUno.parar();
bUno.setLabel("1 parado");
}else if (e.getSource().equals(bDos)){
hDos.parar();
bDos.setLabel("2 parado");
}
}
public void paint(Graphics g) {
while (true){
g.clearRect(1,1,getSize().width,getSize().height); //dibuja la ventana
g.setFont(fuente);
g.drawString(hUno.getContador()+"",40,60);
g.drawString(hDos.getContador()+"",100,60);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
in case it helps anyone, solved deleting the infinite loop and adding this method
Timer timer = new Timer();
timer.schedule( new TimerTask() {
public void run() {
repaint();}
}, 0, 1000);
I am working on a project in which I would like to close a generic JOptionPane programmatically (by not physically clicking on any buttons). When a timer expires, I would like to close any possible JOptionPane that may be open and kick the user back to the login screen of my program. I can kick the user back just fine, but the JOptionPane remains unless I physically click a button on it.
I have looked on many sites with no such luck. A doClick() method call on the "Red X" of the JOptionPane does not seem possible, and using JOptionpane.getRootFrame().dispose() does not work.
Technically, you can loop through all windows of the application, check is they are of type JDialog and have a child of type JOptionPane, and dispose the dialog if so:
Action showOptionPane = new AbstractAction("show me pane!") {
#Override
public void actionPerformed(ActionEvent e) {
createCloseTimer(3).start();
JOptionPane.showMessageDialog((Component) e.getSource(), "nothing to do!");
}
private Timer createCloseTimer(int seconds) {
ActionListener close = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Window[] windows = Window.getWindows();
for (Window window : windows) {
if (window instanceof JDialog) {
JDialog dialog = (JDialog) window;
if (dialog.getContentPane().getComponentCount() == 1
&& dialog.getContentPane().getComponent(0) instanceof JOptionPane){
dialog.dispose();
}
}
}
}
};
Timer t = new Timer(seconds * 1000, close);
t.setRepeats(false);
return t;
}
};
This code gotten from
https://amp.reddit.com/r/javahelp/comments/36dv3t/how_to_close_this_joptionpane_using_code/ seems to be the best approach to me. It involves Instantiating the JOptionPane class rather that using the static helper methods to do it for you. The benefit is you have a JOptionPane object that you can dispose when you want to close the dialog.
JOptionPane jop = new JOptionPane();
jop.setMessageType(JOptionPane.PLAIN_MESSAGE);
jop.setMessage("Hello World");
JDialog dialog = jop.createDialog(null, "Message");
// Set a 2 second timer
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(2000);
} catch (Exception e) {
}
dialog.dispose();
}
}).start();
dialog.setVisible(true);
I'm in the process of writing a game. The game plays background music while it is running. This works fine, and I've decided to add a main menu, as their are three types of this game:
Single Player
Two Player
Online
When I run these classes individually (which have their own main methods - obviously), they work perfectly fine. However, in my Welcome Menu class, which is responsible for the main menu (all necessary imports are there, just not shown here):
public class WelcomeMenu implements ActionListener {
public void setButtonBG(JButton button, String imgPath) throws IOException //this method is reponsible for setting images to their corresponding JButton(s)
{
BufferedImage img = ImageIO.read(ClassLoader.getSystemResource(imgPath));
ImageIcon sp = new ImageIcon(img);
button.setIcon(sp);
button.setBorderPainted(false);
}
private JFrame welcomeWindow = new JFrame("Tic-Tac-Toe");
private JButton singlePlayerButton = new JButton();
private JButton twoPlayerButton = new JButton();
private JButton onlineButton = new JButton();
public WelcomeMenu() throws IOException
{
//START OF CONSTRUCTOR
//Main window is being sized, default way to close, and internal layout
welcomeWindow.setSize(600, 420);
welcomeWindow.setLayout(new CardLayout());
//Object res = this.getClass().getResource("/");
//System.out.println(res);
BufferedImage bf = ImageIO.read(ClassLoader.getSystemResource("images/mainMenuBG.jpg"));
welcomeWindow.setContentPane(new backImage(bf)); // adding created component to the JFrame using the backImage class
welcomeWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
welcomeWindow.setLocationRelativeTo(null);
welcomeWindow.setResizable(false);
welcomeWindow.setVisible(true);
//setting the icon
try
{
java.net.URL url = ClassLoader.getSystemResource("images/icon.png");
Toolkit kit = Toolkit.getDefaultToolkit();
Image img = kit.createImage(url);
welcomeWindow.setIconImage(img);
}
catch(NullPointerException n)
{
System.out.println("Image could not be fetched.");
}
//adding custom buttons
//ImageIcon singlePlayer = new ImageIcon("images/singlePlayerButton.jpg");
//setting sizes
singlePlayerButton.setSize(387, 72);
twoPlayerButton.setSize(387, 72);
onlineButton.setSize(387, 72);
//setting background images to buttons
setButtonBG(singlePlayerButton, "images/sPlayerButton.jpg");
setButtonBG(twoPlayerButton, "images/tPlayerButton.jpg");
setButtonBG(onlineButton, "images/mPlayerButton.jpg");
//adding listeners
singlePlayerButton.addActionListener(this);
twoPlayerButton.addActionListener(this);
onlineButton.addActionListener(this);
//adding the custom buttons
welcomeWindow.add(singlePlayerButton);
welcomeWindow.add(twoPlayerButton);
welcomeWindow.add(onlineButton);
//setting locations and visibility
singlePlayerButton.setLocation(110, 90);
singlePlayerButton.setVisible(true);
twoPlayerButton.setLocation(110, 182);
twoPlayerButton.setVisible(true);
onlineButton.setLocation(110, 274);
onlineButton.setVisible(true);
//END OF CONSTRUCTOR
}
public static TicTacToeTP spg;
//All actions are done here
#Override
public void actionPerformed(ActionEvent e)
{
if(e.getSource() == singlePlayerButton)
{
System.out.println("<LOG> SINGLE PLAYER GAME REQUESTED");
JOptionPane.showMessageDialog(welcomeWindow, "This game mode has not been implemented yet.");
}
if(e.getSource() == twoPlayerButton)
{
System.out.println("<LOG> TWO PLAYER GAME REQUESTED");
try
{
//spg = new TicTacToeTP("images/black-squareMod_RED.jpg");
//spg.playBackgroundSong();
TicTacToeTP.main(null);
}
catch(IOException io)
{
System.out.println("IO EXCEPTION!");
}
welcomeWindow.setVisible(false);
welcomeWindow.dispose();
}
if(e.getSource() == onlineButton)
{
System.out.println("<LOG> ONLINE GAME REQUESTED");
JOptionPane.showMessageDialog(welcomeWindow, "This game mode has not been implemented yet.");
}
}
public static void main(String[] args) throws IOException
{
EventQueue.invokeLater(new Runnable()
{
#Override
public void run()
{
try
{
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch(ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex)
{
}
}
});
new WelcomeMenu();
}
}
... if I click the Two Player button, for example, it plays the audio ONLY. None of my other components load. Just an empty JFrame. Notice how in the actionPerformed() method, I tried both TicTacToeTP.main(null) and (commented out, now) instantiating a new TicTacToeTP object AND calling the playBackgroundSong() method. If I eliminate this methods call, and just instantiate the object, it works fine - but no music.
Why is this happening, and how can I fix it?
Here is the playBackgroundSong() method:
private Player p = null;
//private InputStream fis = null;
public void playBackgroundSong() //responsible for playing background music
{
//PausablePlayer p = null;
InputStream fis = null;
ArrayList<InputStream> stream = new ArrayList<InputStream>(); //this ArrayList contains multiple audio files that the method will loop through >> defined below
stream.add(ClassLoader.getSystemResourceAsStream("resources/01 Intro.mp3"));
stream.add(ClassLoader.getSystemResourceAsStream("resources/Basic space - The XX - Instrumental.mp3"));
stream.add(ClassLoader.getSystemResourceAsStream("resources/Mirrors [ Upbeat Electronic Instrumental ] Spence Mills HQ Free Beat Download 2012.mp3"));
stream.add(ClassLoader.getSystemResourceAsStream("resources/Static [ Aggressive Dark Pop Hip Hop Rap Instrumental ] Spence Mills Free Beat Download Link 2012 HD.mp3"));
stream.add(ClassLoader.getSystemResourceAsStream("resources/System Shock 2 soundtrack Med Sci 1.mp3"));
stream.add(ClassLoader.getSystemResourceAsStream("resources/System Shock 2 Soundtrack Ops 2.mp3"));
stream.add(ClassLoader.getSystemResourceAsStream("resources/01 Intro.mp3"));
Collections.shuffle(stream);
for(int i = 0; i < stream.size(); i++)
{
try
{
fis = stream.get(i);
}
catch (NullPointerException ex)
{
Logger.getLogger(TicTacToeTP.class.getName()).log(Level.SEVERE, null, ex);
}
try
{
p = new Player(fis);
}
catch (JavaLayerException ex)
{
Logger.getLogger(TicTacToeTP.class.getName()).log(Level.SEVERE, null, ex);
}
try
{
p.play();
}
catch (JavaLayerException ee)
{
Logger.getLogger(TicTacToeTP.class.getName()).log(Level.SEVERE, null, ee);
}
}
playBackgroundSong();
}
You appear to be playing a long-running bit of code, playBackgroundSong(), on the Swing event dispatch thread or EDT. This thread is responsible for painting the GUI and interacting and responding to user input, and if it gets tied up, the program essentially freezes. This might not have been an issue when you called this method in the main method -- basically off of the Swing event thread, but is an issue when it is specifically called on the event dispatch thread. A possible solution: play your music in a background thread. A SwingWorker might work well for you, and there are decent tutorials on the use of these and the EDT. Google "Concurrency in Swing", and check out what will likely be the first hit for more.
As an aside: you usually don't want to call another class's main method. Instead create an instance of the other class and use it.
Edit You state:
Thanks. Looking at this part: docs.oracle.com/javase/tutorial/uiswing/concurrency/simple.html Seems to explain what I want to do, correct? I am reading it all, by the way
Actually you could go even simpler. Since you're not waiting for a result from your playBackgroundSong(), you could possibly just call it in its own simple thread by just wrapping it in a Runnable and then putting that in a Thread:
new Thread(new Runnable() {
public void run() {
playBackgroundSong();
}
}).start();
I have a JFrame with a CardLayout component. I am using the CardLayout to switch between different JPanel's at different moments of the application execution. At some point I am using a SwingWorker Object to generate some XML files. In this time I want to display another JPanel in my window to tell the user to wait. On this JPanel I want to switch between 3 labels.
JLabel 1 would be : "Please wait."
JLabel 2 would be : "Please wait.."
JLabel 3 would be : "Please wait..."
Right now the code looks like this:
ConvertersWorker.execute();
CLayout.show(Cards, WAIT_PANEL);
Timer t =new Timer(500, new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e) {
WaitPanel.SwitchLabels();
}
});
t.start();
while (!this.finishedConverting)
{
}
//After this im am executing other methods based on the generated XML files
The SwingWorker code:
SwingWorker<Boolean, Void> ConvertersWorker = new SwingWorker<Boolean, Void>() {
public Boolean doInBackground() {
Boolean result = RunConverters();
return result;
}
public void done() {
try {
finishedConverting = get();
} catch (InterruptedException ex) {
ex.printStackTrace();
} catch (ExecutionException ex) {
ex.printStackTrace();
}
}
} ;
The second JPanel is not even displayed because the JFrame blocks. It blocks because of the while loop but I don't know how to implement it differently. And also the method done() from the SwingWorker is never executed. If it were executed then the finishedConverting variable would have been set to true and the while loop would have stopped. Can anyone help me to find a better solution?
I know you solved this but that's happening because you are using just one thread, and it blocked because of the While, so you need to create a new thread to handle this
new Thread(){
public void run() {
//code here
}
}.start();
and to refresh the content of a JPanel you can use
myJpanel.doLayout();
or
myJpanel.repaint();
I removed the while loop and moved the code which was after the loop in another method which is executed in the done() method of the SwingWorker so now it works.