I have an application which on exit should close all windows and write some configuration files.
Without the things I did below, the following was never triggered and so the closeEXES which writes all the configs out was never run.
mainframe.addWindowListener(new java.awt.event.WindowAdapter() {
#Override
public void windowClosing(WindowEvent winEvt) {
closeEXES();
}
});
I used the following to catch the Cmd-Q on Mac OS:
import com.apple.eawt.QuitStrategy;
import com.apple.eawt.Application;
And in main:
if (System.getProperty("os.name").equals("Mac OS X")) {
Application.getApplication().setQuitStrategy(QuitStrategy.CLOSE_ALL_WINDOWS);
The version before that I did:
public class MacQuitAdapter extends ApplicationAdapter {
#Override
public void handleQuit(ApplicationEvent e) {
System.out.println("Using deprecated AplicationAdapter for handling Quit.");
}
}
How would I accomplish the same thing with JDK 8? The "same thing" is to make sure that when Command-Q is hit, the closing of the windows will be passed to AWT so that the windowClosing method will do what I want.
Alternatively, is there some other listener I need to sense the Command-Q? I'll keep looking but thought it was worth asking here.
Thanks.
I'm sorry to answer my own question. Please let me know if this is a faux pas. I used this plus still kept the close-window part of the code. For JDK 8 this does most of what I want.
So now the code looks like this:
mainframe.addWindowListener(new java.awt.event.WindowAdapter() {
#Override
public void windowClosing(WindowEvent winEvt) {
closeEXES();
}
});
if (System.getProperty("os.name").equals("Mac OS X"))
{
Runtime.getRuntime().addShutdownHook(new Thread()
{
#Override
public void run()
{
System.out.println("in : run () : shutdownHook");
doCloses();
System.out.println("Shutdown hook completed...");
}
});
}
one method, closeEXES, prompts the user to make SURE they really meant to quit the application. The other checks a condition (have the files been closed before?) and closes them if they have not been closed.
For completeness:
public void closeEXES() {
int n = JOptionPane.showConfirmDialog(mainframe,
"Close EXES GUI?", "Closing EXES GUI",
JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
if (n == 0) {
System.out.println("Exiting...start");
doCloses();
System.exit(0);
}
}
public void doCloses() {
if ( beenClosed )
{
System.out.println("Already closed all files.");
}
else
{
// ... a bunch of stuff here writing GUI screen positions to a file and
// things like that ...
beenClosed = true;
}
}
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/
When I try to call Desktop.getDesktop().open(), my program crashes.
I'm on Ubuntu GNOME 16.10, running Gnome 3.20.4. I haven't had a chance to test this code on another platform, but on this platform it is definitely crashing the program.
browseMenuItem.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
Platform.runLater( new Runnable() {
public void run() {
try {
System.out.println ( Desktop.isDesktopSupported() );
Desktop.getDesktop().open( albumTable.getSelectionModel().getSelectedItem().getPath().toFile() );
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
});
Any thoughts on how to fix or troubleshoot this?
You're mixing JavaFX and AWT, which is likely causing the problem. Instead of
Desktop.getDesktop().open(file);
try using the JavaFX API:
getHostServices().showDocument(file.toURI().toString());
getHostServices() is defined in Application (so you may need to retrieve it in your start method and pass it to whichever object - perhaps a controller - is registering the listener with the menu item).
It looks like #James_D's answer is the better way to do things, but currently (as of 2017/05/03) it doesn't work on the OpenJDK / OpenJFK.
Thankfully, his comment about mixing JFX and Swing helped me find a solution which will work on OpenJDK / OpenJFX:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
Desktop.getDesktop().open( albumTable.getSelectionModel().getSelectedItem().getPath().toFile() );
} catch (IOException e) {
e.printStackTrace();
}
}
});
The trick was using SwingUtilities.invokeLater() rather than Platform.runLater(), since the code inside is swing.
I have made a basic chat application in java using eclipse. I am now starting to add extra features to it and am currently stuck on a feature that tells the user when the other person is typing, similar to whatsapp and facebook messenger.
currently i have an integer that records if the user is typing
public int typing = 0;
when it is 0 the user isn't typing when it is 1 they are (a boolean wouldn't work for some reason)
I have an action listener on the textbox that listens for a caret update and excecutes this code:
isTyping = 1;
String typing = ("t-");
client.send(typing.getBytes());
The server then relays this back to the other clients and when they recieve this message that gets sent if they are not typing it will make the someone is typing label appear.
What i would like is something to listen for when the caret is not updating to execute this code:
isTyping = 0;
String typing = ("n-");
client.send(typing.getBytes());
Is this possible or is there a way to make this work as i seem to need to listen for no carat update?
I suggest avoiding the listener and creating a thread:
The created thread checks the value of textbox and remembers the current value of the textbox in a loop. If the value hasn't changed since the last check, it means that the user is not typing. It is up to you to consider frequency of the check and maybe only a length of the value could be used for the check.
Make a single “expiration” Timer that waits a short delay, and then executes your “not typing” action. Whenever the text field’s document changes, restart the Timer, to ensure it only manages to execute when there is a lull in the user’s typing:
JTextField textField = /* ... */;
ActionListener idleSender = new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
isTyping = false;
client.send("n-".getBytes(StandardCharsets.UTF_8));
}
};
int delay = 2000; // 2 seconds
final Timer sendTimer = new Timer(delay, idleSender);
sendTimer.setRepeats(false);
sendTimer.start();
textField.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void insertUpdate(DocumentEvent event) {
sendTimer.restart();
}
#Override
public void removeUpdate(DocumentEvent event) {
sendTimer.restart();
}
#Override
public void changedUpdate(DocumentEvent event) {
sendTimer.restart();
}
});
Some notes:
It is important to use javax.swing.Timer, not java.util.Timer. The latter uses its own thread, while the former always executes its task on the AWT Event Dispatch Thread. Calling (almost) any AWT or Swing method on any thread other than the EDT is not allowed, and while violating that rule may not generate an exception, things tend to break intermittently and unpredictably.
Using typing.getBytes() without passing an charset to getBytes() may cause data corruption on the other side. It will convert bytes using the underlying system’s default charset, which may not be the same as the server’s default charset. It is a good idea to use "n-".getBytes(StandardCharsets.UTF_8) instead.
I don’t know what “a boolean wouldn’t work for some reason” actually means, but booleans work perfectly in all circumstances. If you had a problem, you will be doing yourself a service by finding out what that problem is and fixing it, rather than writing peculiar code that sidesteps the issue, only to come back to it months later and wonder why you are using 0 and 1 in place of false and true.
Performing a command while an action isn't happening isn't really possible, because it doesn't answer one crucial question - how often should it happen? Always isn't really an answer - that would require an infinite loop constantly executing, which will throttle your application as a whole.
That said, you can set up a timed delay for sending a notification that the person has stopped editing. In my mind it would count down (via thread sleep) towards 0 and refresh to a set (positive) amount whenever a key is pressed, but it could be the opposite as well (as AJ suggests in the comments).
public class NotificationSender {
private boolean isEditing;
private final Object isEditingLock;
private DelayedTurnOffThread turnOffThread;
private static final long MS_TO_OFF_NOTIFICATION = 1000;
public NotificationSender() {
isEditing = false;
isEditingLock = new Object();
turnOffThread = null;
}
private void sendEditingNotification(String newContent) {
System.out.println("Editing, new content=" + newContent);
}
private void sendStopEditingNotification() {
System.out.println("Editing stopped");
}
public boolean isEditing() {
synchronized (isEditingLock) {
return isEditing;
}
}
public void doEdit(String newContent) {
synchronized (isEditingLock) {
isEditing = true;
sendEditingNotification(newContent);
if (turnOffThread != null) {
turnOffThread.interrupt();
}
turnOffThread = new DelayedTurnOffThread();
turnOffThread.start();
}
}
private class DelayedTurnOffThread extends Thread {
#Override
public void run() {
try {
Thread.sleep(MS_TO_OFF_NOTIFICATION);
synchronized (isEditingLock) {
isEditing = false;
sendStopEditingNotification();
}
} catch (InterruptedException e) {
//Do nothing - superceded by other turnoff thread
}
}
}
//
//DEMO CODE BELOW
//
private static class NotificationDemo extends JFrame {
private NotificationSender notificationSender;
public NotificationDemo() {
notificationSender = new NotificationSender();
JTextField textField = new JTextField();
getContentPane().add(textField, BorderLayout.CENTER);
textField.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
notificationSender.doEdit(((JTextField)e.getSource()).getText() + e.getKeyChar());
}
#Override public void keyPressed(KeyEvent e) {}
#Override public void keyReleased(KeyEvent e) {}
});
pack();
setLocationRelativeTo(null);
setVisible(true);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
}
public static void main(String[] args) {
new NotificationDemo();
}
}
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 sending a file over network using sockets. The file is received properly without any problem. But now I am using a JProgressBar to show percentage of file sent. My problem is that even when I update GUI in a separate thread, the progress bar is updated only when file is completely sent. I also tried adjusting the priority of main thread to Thread.MIN_PRIORITY but the problem still persisted.
The complete code is long so I am not posting it (I will post if someone asks). The short code for sending file and updating progress bar is
final double temp=(done/fileSize)*100; // percentage of file sent
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
try
{
jpb.setString("Completed : "+temp+" %");
jpb.setValue((int)temp); // this is executed only when 100%
}
catch(Exception e)
{
e.printStackTrace();
}
}
});
System.out.println(temp); // only this and
bos.write(b,0,read); // this statement is executed
Problem lies in below line:
final double temp=(done/fileSize)*100; // percentage of file sent
If done and fileSize are both not double then result of done/fileSize is 0.0.
Make them double (at least one of them) to keep the decimal part of the division.
Here is a implementation that I talked about.
It's not the best design as I did it quick and dirty but this way the file transfer code is not dependent on the UI.
public class FileTransfer implements Runnable
{
double transferPercent = 0.0;
double getTransferPercent(){ return transferPercent; }
#Override
public void run()
{
while(transferingFile)
{
// Write data
// Update transferPercent
}
}
}
public class UIClass extends TimerTask
{
private FileTransfer fileTransfer;
public void createUI()
{
TimerTask myClass = this;
JButton b = new JButton("Transfer");
b.addMouseListener(new MouseAdapter()
{
#Override
public void mouseClicked(MouseEvent e)
{
fileTransfer.start();
Timer t = new Timer();
t.scheduleAtFixedRate(myClass, 0.0, 20);
}
});
}
// Update the UI here!
#Override
public void run()
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
jpb.setValue(fileTransfer.getTransferPercent());
}
});
}
}
I'd probably design this differently. I'd make the network code independent of the UI and have it just update a variable on percentage sent.
The UI would then poll this number with a timer to update the progress bar.
But your code should work. Try adding an #Override on your run function. Maybe SwingUltities.invokeLater is calling Runnable's run function instead of your own.