I came across this interesting situation while answering this question.
Try this piece of poorly designed code -
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
class abc extends JFrame implements ActionListener
{
boolean button_clicked = false;
JButton b1;
abc(){
this.setSize (400, 400);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.createUI();
}
void createUI(){
this.setLayout(null);
b1 = new JButton("Click here");
b1.setSize(110,30);
b1.setLocation(10,210);
this.add(b1);
b1.addActionListener(this);
}
public boolean isButton_clicked()
{
return button_clicked;
}
public void setButton_clicked(boolean button_clicked) {
this.button_clicked = button_clicked;
}
public void actionPerformed(ActionEvent arg0) {
button_clicked = true;
}
}
Here's the main method.
class tempMain extends JFrame
{
public static void main(String[] args) throws Exception
{
abc temp = new abc();
temp.setVisible(true);
while(true)
{
// Thread.sleep(200);
if(temp.isButton_clicked())
{
JOptionPane.showMessageDialog(null, "Hello");
temp.setButton_clicked(false);
}
}
}
}
When I ran this on my Windows 7 machine, nothing happened for at least about a minute (I didn't wait after that) after I clicked the button.
Now, just make one small change -
Thread.sleep(200); // uncomment this from the main.
And surprisingly, it works and a JOptionPane message is displayed. Why is the message not displayed the first time?
And surprisingly, it works and a JOptionPane message is displayed. Why is the message not displayed the first time?
button_clicked is not marked as volatile and is being updated from a different thread than the main thread. Since the call-back is made from the event handler thread, the main thread will not see the update unless button_clicked is defined as a volatile boolean. Putting a sleep may allow a memory barrier to be crossed and button_clicked to be updated in the main thread luckily.
Here's some more reading about volatile and why it is important when we are dealing with multiple threads.
Another issue is that you have an infinite loop which is spewing messages to System.out. This completely blocks after a while because the console can't display lines that fast which stops the checking for the click.
Related
I'm developing a game, what stops if the window lost the focus. The problem is when the focus is gained, it doesn't start. I simplyfied that part of my game, here is the code:
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.JFrame;
public class Main extends JFrame
{
static boolean running = true;
public static void main(String[] args)
{
Main main = new Main();
main.frameSetup();
while(true)
{
if(running)
{
System.out.println("running");
}
}
}
void frameSetup()
{
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(900, 600);
addFocusListener(new FocusListener()
{
public void focusGained(FocusEvent e)
{
System.out.println("focus gained");
running = true;
}
public void focusLost(FocusEvent areg0)
{
System.out.println("focus lost");
running = false;
}
});
setVisible(true);
}
}
output:
running
running
...
focus lost
focus gained
After the "focus gained" I expected to write the lot running again.
The game works, if I put something to the while(true) like a System.out.println:
while(true)
{
System.out.println("while true");
if(running)
{
System.out.println("running");
}
}
output:
running
while true
running
while true
...
focus lost
while true
while true
...
focus gained
running
while true
running
while true
...
I don't want to put that System.out.printline or whatever because it uses the processor...
So do you know something to fix this "bug"?
Try adding volatile to the definition of running. I believe the problem is that once running == false is detected, it's caching this value and never checking memory again.
at first look you need syncchronization
if only one thread is writting your boolean, you can use a volatile
(usually you do this to define a stop variable checked in the thread's main loop).
if you have multiple threads modifying the boolean, you should use synchronization
READ - MODIFY- WRITE can't be achieved with volatile
https://jorosjavajams.wordpress.com/volatile-vs-synchronized/
I've been trying to learn java for a few weeks now, and I'm working on a pretty simple autoclicker.
The clicker itself works, but my problem is that my GUI never shows up.
The GUI runs just fine when I run the GUI file itself, but when I'm trying to run it from my main program (different file) it never shows. The clicker works fine all the time though. I'm sure the problem is something really simple that I have simply missed, but this is now my 4th day without any clue on what might be wrong with it, so decided I'd ask here.
Beware - the code is really messy atm, because I've been trying pretty much everything possible to get it working.
This is the code in the main program trying to run the GUI.
package autoclicker;
import java.awt.AWTException;
/**
* The main program for the autoclicker.
*/
public class AutoClicker {
public static void main(String[] args) throws AWTException {
Click click = new Click(true);
click.clicker();
try {
Swingerinos sw = new Swingerinos();
sw.initialize();
}
catch (AWTException e) { e. printStackTrace(); System.exit(-1); }
}
}
And this is the whole GUI file.
package autoclicker;
import java.awt.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.JLabel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
public class Swingerinos extends Click implements WindowListener,ActionListener {
private int numClicks = 0;
TextField text;
private JFrame frame;
/**
* #wbp.nonvisual location=181,19
*/
private final JLabel lblAutoclicker = new JLabel("AutoClicker");
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Swingerinos window = new Swingerinos();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public Swingerinos() throws AWTException {
initialize();
}
/**
* Initialize the contents of the frame.
*/
public void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 109);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
frame.getContentPane().add(panel, BorderLayout.WEST);
JButton btnNewButton = new JButton("Toggle On / Off");
text = new TextField(20);
text.setLocation(100, 100);
btnNewButton.addActionListener( this);
btnNewButton.setToolTipText("Toggles the autoclicker on / off.");
panel.add(btnNewButton);
panel.add(text);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent e) {
toggle();
numClicks++;
text.setText(""+numClicks);
}
public void windowClosing(WindowEvent e) {
System.exit(0);
}
public void windowOpened(WindowEvent e) {}
public void windowActivated(WindowEvent e) {}
public void windowIconified(WindowEvent e) {}
public void windowDeiconified(WindowEvent e) {}
public void windowDeactivated(WindowEvent e) {}
public void windowClosed(WindowEvent e) {}
}
I know the GUI file is really messy (there's 2x initialize(), one in the main program and one in the GUI file, and lots of other stuff, but I'm just too confused as for what to do now.
EDIT: I added the whole main program code, also this is the code for the autoclicker.
package autoclicker;
import java.awt.*;
import java.awt.event.InputEvent;
public class Click {
private boolean active;
private Robot robot;
public Click(boolean active, Robot robot) {
this.active = active;
this.robot = robot;
}
public Click() throws AWTException {
this(false, new Robot());
}
public Click(boolean active) throws AWTException {
this(active, new Robot());
}
//TODO: add click.toggle() to somewhere and control da clicker
public void toggle() {
active = !active;
}
public void clicker() {
while (active) {
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
robot.setAutoDelay(10000);
}
}
}
Expanding JB Nizet's comment(s) into an answer.
The immediate cause:
When the JVM calls your code, it is run on the main thread. It calls main(String[]), as you know. You posted two main methods, only one of which is relevant to your nothing-is-happening problem: AutoClick#main(String[]). Let's go through it:
Click click = new Click(true);
click.clicker();
This first of the above two lines obviously calls the constructor of Click, which sets the active variable to true. So far so good. The second line is much more interesting. It calls Click#clicker(). Let's look at that method:
public void clicker() {
while (active) {
// <snip>
}
}
This method is the problem. Since you haven't started any other threads, the main thread is the only one you have at that moment, the only thread on which you can execute code. When this loop is executed it only finishes when the active variable is set to false. As long as it is true, it will keep looping. This means that Click#clicker() only returns if active is set to false. But, you never do that in the loop itself, meaning you need a thread different from the thread executing the loop to change active. So, how many threads do we have? 1, the main thread. See the problem? Because the loop never ends, the main thread never reaches the statements in the main method after click.clicker().
Simple solution
You could just set a fixed number of iterations:
public void clicker() {
int i = 0;
while (i < 100) { // iterate 100 times
// <snip>
++i;
}
}
Or using a for-loop (recommended):
public void clicker() {
for (int i = 0; i < 100; ++i) {
// <snip>
}
}
This eliminates the need for the active variable and hence the need for another thread.
A somewhat more complicated solution
If you really want the active variable, you'll need to have multiple threads. This is conveniently known as "multithreading"1, a very complicated topic. Luckily, we only need a bit of it, so it is only a bit complicated.
Don't just call the method Click#clicker() like you would normally. This creates your current problem. You'll need a worker thread, which can call the method. The easiest way to create a new thread is to call the constructor of the class Thread which takes a single argument of type Runnable. Like this:
Thread worker = new Thread(new Runnable() {
public void run() {
click.clicker();
}
});
This returns relatively quickly and leaves the Click#clicker() method running on another thread. Your main thread is now free to execute the other statements and even call click.toggle() after a while.
As JB Nizet pointed out, there are some other problems with your code. For example, Swingerinos shouldn't extend Click, but have an instance variable of type Click (http://en.wikipedia.org/wiki/Composition_over_inheritance) (as JB Nizet pointed out). Also, you shouldn't need to implement WindowListener to just call System.exit() when the window closes if you already call frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);. To get all kinds of feedback (not limited to but including this kind of issues, style and design) on working code2 I highly recommend the StackExchange website codereview.stackexchange.com
1: I by no means consider myself even remotely an expert on threading, so I won't go into it. If you want to know more about it, google it - there's lots of texts on multithreading - or ask another question - if you have a specific problem.
2: this is important: broken code is off-topic on Code Review.
Hello I know there is many questions about it and some relevant answers. Like for returning response into GUI JTextArea from backend use SwingUtilities.invokeLater and for passing messages to backend using blocking queue. This I can work with.
But I would like to skip implementing queue's message parser. I would like to know if there is possible to directly call methods from another thread. Good partial answer is to call method using class implements runnable but it is only able to start a single task thread. What I'm looking for is a persistent object accepting more methods to be called from another thread and performing serialization.
So to say it more concretely:
1st thread is GUI having multiple button like "open device", "set reg A to user input", "set reg B to user input", "enable feature X", "flash FW"...
2nd is a working thread - it is already done consisting of multiple class. And having methods which needs to be called from GUI.
I need following properties
- working thread is only 1 and persistent through all GUI calls
- all GUI calls shall be serialized (another call is started only after first call is fully processed and returns)
- working thread shall be able to send some "log messages" into GUI (for example % of flashed FW) (this probably can be done easily by SwingUtilities.invokeLater)
Is there a better way to call methods than implement queue parser? If there is can you provide some link to good example? Or is the queue correct approach to this task? If the Queue is the correct approach how to best encode different parameters? Eg "flash firmware" button would need to pass "File", "set reg A to value XY" button would need to pass Byte...
You can use Executors.newSingleThreadExecutor() to create an Executor to run tasks. Once you have the Executor instance you can send Runnable objects to it. The tasks will be queued and each task will run to completion before the next task is begun, all using the same worker thread.
For instance, in your UI thread you can send a task to the executor like this:
ExecutorService executor = Executors.newSingleThreadExecutor();
...
JButton b1 = new JButton("doTask1");
b1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
executor.execute(yourRunnable1);
});
});
JButton b2 = new JButton("doTask2");
b2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
executor.execute(yourRunnable2);
});
});
Based on user "mevqz" answer I made a example code. It is fully working and seems to be the good answer to my question. I'm providing this example code as elaborated answer - as it still was quite a effort for me to put it together. Also as a newbie I would like to ask if I got mevqz hint correctly and my code is truly thread safe?
Here is basically just an original Backend, where I have implemented possibility to call method log() which shall write back into GUI JTextArea in thread safe manner.
import javax.swing.*;
public class Backend {
private int handle=0;
private int regA=0;
Main guiLogger;
Backend(Main guiLog){ // interface having log() would be enough
guiLogger = guiLog;
}
public void log(final String txt){
SwingUtilities.invokeLater(new Runnable() {
public void run() {
guiLogger.log(txt);
}
});
}
public void open(){
log("openning\n");
// some code that work longer time...
try{
Thread.sleep(1000);
}catch(Exception e){}
handle++;
log("opened: "+handle+"\n");
}
public void setRegA(int val){
log("using handle:"+handle+" set reg A val: "+val+"\n");
regA = val;
}
}
Here is wrapper which which holds executorService and Backend reference. Here it seems not so nice as Backend is actually stored in wrong thread and always passing into Runnable.run(). Is there better way to hide Backend reference directly into ExecutorService?
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class BackendRunWrapper{
private Backend backend; // never call it from this thread
private ExecutorService executor;
public BackendRunWrapper(Main logger){
backend = new Backend(logger);
executor = Executors.newSingleThreadExecutor();
}
public void executorShutdown(){
executor.shutdown();
}
public void open(){
executor.execute(new Runnable(){
public void run(){
BackendRunWrapper.this.backend.open();
}
});
}
public void setRegA(final int val){
executor.execute(new Runnable(){
public void run(){
BackendRunWrapper.this.backend.setRegA(val);
}
});
}
}
Here is just a main gui with 2 buttons "Open" and "SetRegA" and JTextArea for logging. This only calls function from BackendRunWrapper. The only question here is wether executorShutdown() is called correctly?
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Main{
BackendRunWrapper backendWrapper;
StringBuilder sb;
JTextArea jta;
public void log(String txt){
sb.append(txt);
jta.setText(sb.toString());
}
public Main(){
backendWrapper = new BackendRunWrapper(this);
sb = new StringBuilder();
JFrame frame = new JFrame("Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container pane = frame.getContentPane();
pane.setLayout(new BoxLayout(pane, BoxLayout.Y_AXIS));
JButton b1 = new JButton("open");
b1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
backendWrapper.open();
}});
pane.add(b1);
JButton b2 = new JButton("setRegA");
b2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
backendWrapper.setRegA(42);
}});
pane.add(b2);
jta = new JTextArea(20, 80);
pane.add(jta);
frame.pack();
frame.setVisible(true);
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
public void run() {
Main.this.backendWrapper.executorShutdown();
}}));
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Main();
}});
}
}
I've been searching near and far for a solution to my question but I am having difficulty even defining my search terms.
I have a method that creates a Swing GUI using invokeLater where the user completes some task. Once the task is completed, the window closes and the initial calling thread (e.g. the method) should resume execution. To be more specific, here is a summary of the method:
public class dfTestCase extends JFrame{
public dfTestCase{
... //GUI code here
}
public String run()
{
CountDownLatch c = new CountDownLatch(1);
Runnable r = new Runnable()
{
public void run()
{
setVisible(true); //make GUI visible
}
};
javax.swing.SwingUtilities.invokeLater(r);
//now wait for the GUI to finish
try
{
testFinished.await();
} catch (InterruptedException e)
{
e.printStackTrace();
}
return "method finished";
}
public static void main(String args[]){
dfTestCase test = new dfTestCase();
System.out.println(test.run());
}
}
Within the GUI, I have actionListeners for buttons that will close and countDown the CountDownLatch.
While the CountDownLatch works, it is not suitable for my purposes because I need to run this GUI several times and there is no way to increment the latch. I'm looking for a more elegant solution - it is my best guess that I would need to make use of threads but am unsure how to go about this.
Any help would be much appreciated!
Update
Some clarification: What is happening is that an external class is calling the dfTestCase.run() function and expects a String to be returned. Essentially, the flow is linear with the external class calling dfTestCase.run()-->the GUI being invoked-->the user makes a decision and clicks a button-->control to the initial calling thread is returned and run() is completed.
For now my dirty solution is to just put a while loop with a flag to continuously poll the status of the GUI. I hope someone else can suggest a more elegant solution eventually.
public class dfTestCase extends JFrame{
public dfTestCase{
... //GUI code here
JButton button = new JButton();
button.addActionListener{
public void actionPerformed(ActionEvent e){
flag = true;
}
}
}
public String run()
{
Runnable r = new Runnable()
{
public void run(){
setVisible(true); //make GUI visible
};
javax.swing.SwingUtilities.invokeLater(r);
//now wait for the GUI to finish
while (!flag){
sleep(1000);
}
return "method finished";
}
public static void main(String args[]){
dfTestCase test = new dfTestCase();
System.out.println(test.run());
}
}
Modal dialogs and SwingUtilities#invokeAndWait iso invokeLater should allow you to capture user input and only continue the calling thread when the UI is disposed
For an example of using model dialogs you can check out the ParamDialog class I wrote. In particular, check out ParamDialog.getProperties(Properties);
http://tus.svn.sourceforge.net/viewvc/tus/tjacobs/ui/dialogs/
In my Java application, when the main module is invoked, i start my SWT GUI in a separate thread. I need to perform some long opertations in the main thread and update the GUI thread. When I try to update the GUI thread from the main thread i.e. change a label text or something, i get a java.lang.NullPointerException. From what I've read online is because SWT doesn't allow non-UI threads to update UI objects. How can I update the GUI thread from the main thread.
I've found some examples online but they all deal with the scenario in which the GUI runs in the main thread and long operation is in separate thread. My scenario is the total opposite.
Could someone tell me how I can update widgets in the GUI thread?
To say things short, SWT is a single-threaded UI toolkit. As a consequence, widgets must be updated in SWT event thread, like in Swing. Thus, you'll have to call the refresh using anonymous Runnable classes :
Display.getDefault().asyncExec(new Runnable() {
public void run() {
someSwtLabel.setText("Complete!");
}
});
For a longer explanation, this JavaLobby article is a good introduction to this threading usage model.
I think you are getting java.lang.NullPointerException because you are trying to access the GUI component before it is created. Ideally you should wait for the gui component to get created... for example...
I create a single GUI in a separate thread... like this
package test;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
public class GUIThread implements Runnable
{
private Display display;
private Label label;
public Display getDisplay(){
return display;
}
public void run()
{
display = new Display();
Shell shell = new Shell(display);
shell.setLayout(new GridLayout());
shell.setLayoutData(new GridData(SWT.FILL,SWT.FILL,true,false));
label = new Label(shell,SWT.NONE);
label.setText(" -- ");
shell.open();
shell.pack();
while (!shell.isDisposed()) {
if (!display.readAndDispatch ()) display.sleep ();
}
display.dispose();
}
public synchronized void update(final int value)
{
if (display == null || display.isDisposed())
return;
display.asyncExec(new Runnable() {
public void run() {
label.setText(""+value);
}
});
}
}
And in my main method i do something like this....
package test;
import org.eclipse.swt.widgets.Display;
public class Main
{
public static void main(String[] args) throws Exception
{
final GUIThread gui = new GUIThread();
Thread t = new Thread(gui);
t.start();
Thread.sleep(3000); // POINT OF FOCUS
Display d = gui.getDisplay();
for(int i = 0; i<100; i++)
{
System.out.println(i + " " + d);
gui.update(i);
Thread.sleep(500);
}
}
}
Now if we comment out the POINT OF FOCUS in the above code then I will always get NullPointerException... But a delay of 3 seconds gives my GUI thread enough time to be in ready state and hence it doesn't through NullPointerException.....
In scenario like this you have to efficiently use the wait and yield methods... otherwise it would result in "Hard to find Bugs"... i.e. wait for UI to properly instantiate and then yield...
Also the actual processing is done in main thread and GUI is running in separate thread... to communicate properly it is good to have some shared and synchronized data structure... or it could be done using socket communication... your main thread populating some port and your GUI thread asynchronously listening on that port....
Hope this will through some light on your problem....