I'm creating some kind of menu (in swing), here's my code
public class JavaApplication5
{
public static void main(String[] args)
{
NewJFrame frame = new NewJFrame();
frame.setVisible(true);
if(frame.getRunning() == true)
{
System.out.println("why it doesn't work");
}
}
}
And here is my menu class:
public class NewJFrame extends javax.swing.JFrame
{
public boolean isRunning = false;
public void setRunning(boolean isRunning)
{
this.isRunning = isRunning;
}
public boolean getRunning()
{
return isRunning;
}
public NewJFrame()
{
initComponents(); //this refers to auto-generated code by swing library
}
//some swing stuff...
private void PlayActionPerformed(java.awt.event.ActionEvent evt) {
this.setRunning(true);
System.out.println(getRunning());
}
}
And the output is whenever i click on "Play" button:
"true
true
true"
And here my question rises: Why in the output's console, the following line is not displayed "why it doesn't work" if I've changed that value from false to true (by pressing button)? How to call that constanly changing variable in the main function? Thanks in advance.
Your application does not block. It sets the JFrame to visible (i.e. displays the window) and then immediately checks whether frame.getRunning() == true. There's absolutely zero chance that you can hit the button before the condition is evaluated.
NewJFrame frame = new NewJFrame();
frame.setVisible(true);
// you're assuming the application waits here, but it does not
if(frame.getRunning() == true)
{
System.out.println("why it doesn't work");
}
The way to solve this is either use a synchronization aid (maybe a CountDownLatch) which will block your main thread or rethink the sequence of events that happen in your program. Perhaps you should register a listener / callback.
Related
In this example I have a simple JFrame containing a JButton with an ActionListener tied to it. This AcitonListener just changes a boolean flag that should allow the program to complete.
public class Test {
public static void main(String[] args){
final boolean[] flag = new boolean[1];
flag[0] = false;
JFrame myFrame = new JFrame("Test");
JButton myButton = new JButton("Click Me!");
myButton.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent arg0) {
System.out.println("Button was clicked!");
flag[0] = true;
}
});
myFrame.add(myButton);
myFrame.setSize(128,128);
myFrame.setVisible(true);
System.out.println("Waiting");
while(!flag[0]){}
System.out.println("Finished");
}
}
This never prints "Finished", and after the button has been clicked once prints
Waiting
Button was clicked!
However, if I modify the while loop to read
while(!flag[0]){
System.out.println("I should do nothing. I am just a print statement.");
}
This works! The printout looks like
Waiting
I should do nothing. I am just a print statement.
I should do nothing. I am just a print statement.
....
I should do nothing. I am just a print statement.
Button was clicked!
Finished
I understand this probably isn't the proper way to wait on an action, but nonetheless I am interested in knowing why Java behaves this way.
The likeliest reason is that flag[0] = true; is executed on the UI thread, whereas while(!flag[0]) is executed on the main thread.
Without synchronization, there is no guarantee that the change made in the UI thread will be visible from the main thread.
By adding the System.out.println you introduce a synchronization point (because the println method is synchronized) and the problem gets solved.
You could make flag a volatile instance or class boolean variable (not an array), or, more simply, put whatever code you want executed on the button being pressed in the listener itself.
For reference, the code with a volatile variable would look like this:
private static volatile boolean flag;
public static void main(String[] args) {
JFrame myFrame = new JFrame("Test");
JButton myButton = new JButton("Click Me!");
myButton.addActionListener(new ActionListener() {
#Override public void actionPerformed(ActionEvent arg0) {
System.out.println("Button was clicked!");
flag = true;
}
});
myFrame.add(myButton);
myFrame.setSize(128, 128);
myFrame.setVisible(true);
System.out.println("Waiting");
while (!flag) { }
System.out.println("Finished");
}
I have some doubts about the use of the methods wait() and notify(). I have the next code which has some button events, the first time the user pushes the button it has to stop printing, and the second time it restarts printing again. I understand that is better to use Runnable instead of Thread, but I have to use Thread because of the requirements. The code works fine the first time the button is pushed but the second time it doesn´t, I want to use the wait() and the notify, but i don´t know how to do it with this particular code.
class Thr extends Thread{
private int count = 0;
private long pause;
private boolean canPrint = true;
private JTextArea textArea;
Thr(long miliseconds,JTextArea text){
pause = miliseconds;
textArea = text;
}
public void pushedButton(){
if(canPrint)
this.canPrint = false;
else
this.canPrint = true;
}
public void run()
{
while(this.canPrint)
{
try
{
this.printCounter();
Thread.sleep(pause);
this.count++;
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
}
public void printCounter(){
String time;
time = Integer.toString(count);
textArea.setText(time);
}
}
class Interface extends JFrame implements ActionListener{
private JTextArea textArea,textArea2;
private JButton button;
private Thr thread,threadEvent;
Interface()
{
textArea = new JTextArea(10,7);
textArea2 = new JTextArea(10,7);
thread = new Thr(2000,textArea);
threadEvent = new Thr(1000,textArea2);
button = new JButton("Pausar/Reanudar");
this.getContentPane().add(button,BorderLayout.SOUTH);
this.getContentPane().add(textArea,BorderLayout.WEST);
this.getContentPane().add(textArea2,BorderLayout.EAST);
thread.start();
threadEvent.start();
button.addActionListener(this);
}
public void actionPerformed(ActionEvent event)
{
threadEvent.pushedButton();
}
}
public class MensajesHilos {
public static void main(String[] args){
Interface i = new Interface();
i.setTitle("Control Threads");
i.setBounds(200, 200, 300, 240);
i.setVisible(true);
}
}
The way you have coded, if you want to achieve the desired result,
I feel the modification need to be done in run method,
public void run()
{
while(true)
{
if(this.canPrint){
try
{
this.printCounter();
Thread.sleep(pause);
this.count++;
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
}
}
in this way, your Thread will never go dead and toggle printing based on canPrint boolean value.
Also, make sure to declare canPrint variable volatile, so that changes to it will be directly written to main memory and reflected immediately.
"button event doesn´t work properly"
This is false, if you put a print statement in the actionPerformed method, you will see that it is called every time you press the button.
By the way note that you can simplify this
if(canPrint)
this.canPrint = false;
else
this.canPrint = true;
To
this.canPrint = !this.canPrint;
Note that it is a good practice to always put #Override anotation on top of overriden method.
#Override
public void actionPerformed(ActionEvent event)
{
threadEvent.pushedButton();
}
Now why don't you get the expected result ?
You ommit to call thread.pushedButton, so the canPrint will only be reseted in the threadEvent object, and will never be in thread.
Note that once the boolean are set to false, you will exit the loop and the process won't start back after even if you re-set the boolean value to true. This example will works using while(true) however, you should change the true to any sentinel value to handle the exit of the program as this will loop forever.
#Override
public void run()
{
while(true)
{
if(this.canPrint)
{
this.printCounter();
this.count++;
}
try
{
Thread.sleep(pause);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
Also, make sure that pause is never 0 else you will eat all of the computer process.
Note that, as other stated, you should declare variables that are accessed in thread as volatile (canPrint) in your case.
sorry to bother everyone.
Overall problem: I'm trying to open a dialogue box let the user enter something then close it
Issue: - A function is not being called (i think)
- The main problem is when i use debug it works fine so Its difficult for me to track down the problem
I'm having trouble with JButtons,
it works in debug but not in normal run. this was probably because i was using an infinite loop. someone online suggested i used SwingUtilities but that didn't work (at least i don't think.
/**
*
* #author Deep_Net_Backup
*/
public class butonTest extends JFrame {
String name;
boolean hasValue;
//name things
private JLabel m_nameLabel;
private JTextField m_name;
//panel
private JPanel pane;
//button
private JButton m_submit;
//action listener for the button submit
class submitListen implements ActionListener {
public void actionPerformed(ActionEvent e) {
submit();
System.out.println("Test");
}
}
//constructor
public butonTest(){
//normal values
name = null;
hasValue = false;
//create the defauts
m_nameLabel = new JLabel("Name:");
m_name = new JTextField(25);
pane = new JPanel();
m_submit = new JButton("Submit");
m_submit.addActionListener(new submitListen());
//
setTitle("Create Cat");
setSize(300,200);
setResizable(false);
//add components
pane.add(m_nameLabel);
pane.add(m_name);
pane.add(m_submit);
add(pane);
//last things
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
//submit
private void submit()
{
System.out.println("submit");
name = m_name.getText();
hasValue = true;
}
//hasValue
public boolean hasValue()
{
return(hasValue);
}
//get the text name
public String getName()
{
return(name);
}
public void close()
{
setVisible(false);
dispose();
}
public static void main(String[] args)
{
/* Test 1
boolean run = true;
String ret = new String();
butonTest lol = new butonTest();
while(run)
{
if(lol.hasValue())
{
System.out.println("Done");
run = false;
ret = new String(lol.getName());
lol.close();
}
}
System.out.println(ret);*/
//Tset 2
/*
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
butonTest lol = new butonTest();
if(lol.hasValue())
{
System.out.println(lol.getName());
}
}
});*/
}
}
Edit:
How its not working: When i run Test the program will print test and submit then it should change the hasValue to true. this will (hopefully) allow the if statement to run to print done. This does not happen.
Edit 2:
I have just added a few more lines for further testing 2 prints and this seems to have solved the issue (but this is bad)
System.out.println("hasValue " + hasValue); -> to the hasValue() function
System.out.println("set to true"); -> submit() function
You are doing something far too complicated than is necessary. Instead of having the listener as a seperate class, you could have it as an anonymous class. That way you can get a handle on the outer class (butonTest.this), and call any method you want on it.
m_submit.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
submit();
System.out.println("Test");
butonTest.this.close();
}
});
I'm not sure what you are trying to do with the infinite loop. It would have run to completion before you show the dialog anyway.
It would help to read up a bit on how Event-Handling works in Swing :)
I am afraid your constructor butonTest() and submit() method are out of your
class (public class butonTest extends JFrame).
you need to get them inside your class:
I searched around for this and couldn't get a clear answer. I've written a game that needs to pause until the user clicks a button with their decision, and then continue to execute. Is there a standard way to do this?
I've seen similar questions that refer to using 'wait()' and 'notify()', but I wasn't sure I needed to add more threads, especially since I'm not executing complex or time-consuming code.
I should clarify it's a computer version of a board game, so nothing more than a frame with some components. Here's some of what I'm trying to do, thanks guys:
public class TreasureHunterFrame extends javax.swing.JFrame
{
public TreasureHunterFrame()
{
initComponents();
startNewGame();
}
private void startNewGame()
{
...
// User asked to click button while this method is running
synchronized (this) // wait until Stay of Leave button is clicked
{
try
{
while (!userHasMadeDecision)
this.wait();
}
catch (InterruptedException ie)
{
}
}
....
}
private void userStayButtonActionPerformed(java.awt.event.ActionEvent evt)
{
userHasMadeDecision = true;
userLeaving = false;
synchronized (this)
{
notifyAll();
}
}
public static void main(String args[])
{
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new TreasureHunterFrame().setVisible(true);
}
});
}
}
public class Main
{
private static boolean SaH=false,LaE=false;
public static void main(String[] args{
//other code
choice1.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
SaH = true;
frame.dispose();
}
}
);
if (SaH==true)
{
// more code
When I run the program, the frame goes away via the dispose() method; but it won't enter the if-statement (SaH isn't changing).
It looks like Java. The statement if (SaH==true) is executed when the java program loads as it is within main method. If you want to execute it after the dispose() method, then create a new method and call the method straight after dispose() within the actionListener