I have such code in my application which I want to run in background:
import java.awt.*;
import java.awt.datatransfer.*;
class Main extends Thread implements ClipboardOwner {
private Clipboard sysClip = Toolkit.getDefaultToolkit().getSystemClipboard();
public void run() {
Transferable trans = sysClip.getContents(this);
regainOwnership(trans);
System.out.println("Listening to board...");
while (true) { }
}
public static void main(String[] args) {
Main b = new Main();
b.start();
}
//............
It listens for Ctrl+C and prints the content of clipboard once this key combination is pressed. However, it makes CPU run 99% all the time. If I remove while (true) { } then the application will just stop in a second.
I tried to launch it as java -jar myapp.jar & but the result was the same. And it would be the same on Windows I guess, although I care about Linux for now.
What do I do about that?
You have a thread running an infinite loop. That's exactly the sort of thing that will use 100% of your CPU for nothing. If nothing else, putting a couple second Thread.sleep() in the loop will bring the CPU usage down.
You should avoid using eternal loops to check if a variable has changed, but rather use a listener. To be more precise, a FlavorListener will allow you to execute code when the clipboard has changed.
It would be something like this:
Toolkit.getDefaultToolkit().getSystemClipboard().addFlavorListener(
new FlavorListener() {
#Override
public void flavorsChanged(FlavorEvent e) {
System.out.println("Clipboard contents: " + e.toString());
}
});
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.
I am developing a Scoreboard Java application for my work. It uses MySQL to store the score values and a Java application accesses them and displays them on a projector. So far I have managed to create a Java application using Swing. I display all of the scores using jLabels so that they can be updated without completely redrawing the scoreboard.
Now, I need to get the scoreboard to update periodically. I have attempted to use Thread.sleep but I don't know how to interrupt the thread. The reason I need to interrupt the thread is that if the number of entries to display on the scoreboard is changed on the config panel, the scoreboard must redraw in order to display the right nummber.
Currently sleep works fine in the code so long as I don't touch anything. But as soon as I change anything in the ConfigPanel things go awry.
package au.thewebeditor.scoreboard.apps;
import java.lang.*;
public class Program {
private static Scoreboard sb;
private static ConfigPanel cp;
public Program(){
sb = new Scoreboard();
cp = new ConfigPanel();
}
public static void redrawScoreboard() throws NullPointerException{
try{
sb.dispose();
} catch (NullPointerException e){
//DO NOTHING
}
sb = new Scoreboard();
try {
cp.toFront();
} catch (NullPointerException e) {
cp = new ConfigPanel();
}
constUpdates();
}
public static void showConfig(){
cp.setVisible(true);
cp.toFront();
}
public static void main(String[] arguments){
new Program();
constUpdates();
}
private static void constUpdates() {
boolean go = true;
while (go){
try {
Thread.sleep(5000);
Scoreboard.updateScores();
} catch (InterruptedException e) {
//DO nothing
}
}
}
}
When the connfiguration has been changed redrawScoreboard() is called.
At the moment, when redrawScoreboard is called it just sits in the queue while constUpdates keeps counting to 5000. How do I interrupt the sleep so I can redraw the scoreboard. Is sleep even the best option here? Or should I try something else?
you have an issue with Concurency in Swing, any create, update, modify Swing GUI must be done on Event Dispatch Thread, maybe reason for wrapping sb.dispose(); into try - catch by throws NullPointerException
Swing GUI must be created on Initial Thread
there no reason to recreate a new Top-Level Container every 5th. seconds, reuse JComponents added to contianer on app's start_up
use util.Timer to invoke SwingWorker,
Calling constUpdates takes the current thread an puts it in an infinite loop.
If the config UI is calling it it will put the UI thread in an infinite loop.
It'd be better just to have that loop in the main function.
Should you get an InteruptedException you should break out of the loop, not keep going.
You've a heady mix of static and non-static things, try to make it so that objects get passed arround instead.
If you want the config to ask the scoreboard to redraw, pass it the scoreboard so it can call redraw directly and leave the polling alone.
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.
I have the following
public static void main(String[] args) {
boolean running = true;
boolean foo= false;
while(running)
{
doSomeTask(); // might set foo true
if(foo) {
//This call waits/blocks until gui is done working.
fireUpSwingGui(); //does work...
foo=false;
godModeReleaseGUIandALLResourcesOnlyWantMainThreadLeft();
}
}
}
Hope that godModeReleaseGUIandALLResourcesOnlyWantMainThreadLeft() says it all.
Bear in mind that we might fire up the gui again at a later stage when foo becomes true again somewhere inside doSomeTask().
Take a look at AWT Threading Issues which explains the criteria for an AWT application to exit. The part you want to focus on is the following:
Therefore, a stand-alone AWT application that wishes to exit cleanly
without calling System.exit must:
Make sure that all AWT or Swing components are made undisplayable when the application finishes. This can be done by calling Window.dispose on all top-level Windows. See Frame.getFrames.
Make sure that no method of AWT event listeners registered by the application with any AWT or Swing component can run into an infinite loop or hang indefinitely. For example, an AWT listener method triggered by some AWT event can post a new AWT event of the same type to the EventQueue. The argument is that methods of AWT event listeners are typically executed on helper threads.
A quick sample app to demonstrate...
import java.awt.Frame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
public class CloseAWT
{
private static boolean running = true;
private static int response = -1;
public static void main(String[] args)
{
boolean showSwing = true;
boolean checkFrames = true;
while (running)
{
if (showSwing)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
response = JOptionPane.showConfirmDialog(null, "Hello World?");
}
});
showSwing = false;
}
else
{
if (response >= 0 && checkFrames)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
// topFrame.dispose();
Frame[] frames = Frame.getFrames();
System.out.printf("frames.length=%d\n", frames.length);
}
});
checkFrames = false;
}
}
}
}
}
To confirm the behavior was as expected, I ran this in JProfiler. After clicking 'yes' to dismiss the confirmation dialog, the 'AWT-EventQueue-0' thread was marked as dead. The only threads alive after this were the 'main' and the thread which listens for Ctrl-Break.
I highly recommend using something like JProfiler, YourKit, JProbe or one of the free profilers to make sure you've properly released all the components and removed all the listeners.
One final thought... You might want to consider spawning your GUI as a separate process and using some sort of IPC to pass information between your daemon process and GUI. Although this incurs the additional overhead of an extra process and the IPC, it would give you a greater assurance that your GUI is completely cleaned up when it is no longer needed.
Assuming you're opening JFrame isntances, why don't you just store them in a collection and inside godModeReleaseGUIandALLResourcesOnlyWantMainThreadLeft() you iterate over them ans call setVisible(false);
I'm not sure whether you actually can stop the AWT event queue that drives the gui.