I found the method addAWTKeyListener in the class Toolkit, but I can't get it to work properly, whether or not the window has focus. My code is as follows:
import java.awt.AWTEvent;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.KeyEvent;
public class KeyTest {
public static void main(String[] args){
Thread t = new Thread(){
#Override
public void run() {
System.out.println("STARTING");
Toolkit kit = Toolkit.getDefaultToolkit();
kit.addAWTEventListener(new AWTEventListener(){
#Override
public void eventDispatched(AWTEvent event) {
System.out.println("EVENT");
if(event instanceof KeyEvent){
KeyEvent kEvent = (KeyEvent) event;
System.out.println(kEvent.getKeyCode());
}
}
}, AWTEvent.KEY_EVENT_MASK);
while(true);
}
};
t.start();
}
}
Is there something I'm doing wrong? I get to the point that STARTING prints and there are no errors. The even is simply not called.
I may be wrong as I'm certainly not an expert, but as far as I know what you're trying to do isn't possible in Java.
Are you trying to capture a key click using a Java program, but without creating a window? Part of Java's security, and this is what I may be wrong on, is that it can only listen to events inside Java windows created by that particular Java program.
So if you were trying to make something key-logger-esque that runs in the background and captured a key press, it wouldn't be able to do that.
I wish I could give you a more concrete answer but I hope this helped.
Just a guess, but you your sample doesn't have any AWT windows in it, so I'm guessing that is why the event never gets fired.
When you say "whether or not the window has focus" does your real app have windows that you have chopped out, or are you talking about a java console window or similar?
Related
I've been using JFrame to learn graphics and test my code because I know it much better. Now I want to update to Javafx. I have this JListener class that handles all the buttons for my JFrame. Is it possible to still use this class with Javafx? If so how?
For example, with JFrame I could use Button.setActionCommand("command"); and when the button was pressed it would run this with the actionListener, can I do this same thing with javafx?
package src.com.Kingdom;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Scanner;
import java.net.*;
public class JListener implements ActionListener
{
private boolean registered = false;
registerClient register;
loginClient login;
static GUIs gui = new GUIs();
#Override
public void actionPerformed(ActionEvent e) {
switch(e.getActionCommand()) {
case("login"):
login = new loginClient(gui.getUsername(), gui.getPassword());
System.out.println("Login");
break;
case("exit"):
System.out.println("exit");
break;
case("register"):
System.out.println("register");
gui.getFrame().dispose();
gui.createRegisterGui();
break;
case("registerperson"):
if(gui.checkRegister()) {
if(hasInternet()) {
if(!(registered)) {
registered = true;
try {
register =
new registerClient(gui.getUsername(), gui.getPassword(), gui.getEmail(), gui.getAge());
} catch(Exception ex) {
GUIs.showError(ex.getMessage());
}
if(!(register.isRegistered())) {
gui.createLoginGui();
}
new Timer().schedule(new TimerTask() {
public void run() {
registered = false;
}
},1000*1);
}
} else {
GUIs.showError("No Internet! Please connect to internet to connect!");
}
} else {
GUIs.showError("Problem with registration format");
}
break;
}
}
}
It is technically possible to integrate JavaFX and Swing. Oracle provide a tutorial on this. I don't recommend integrating the two unless you really need to (which you probably don't in this case). Note that the level of integration possible is just embedding Swing Components into JavaFX nodes (or vice versa). You cannot directly use a Swing listener to take action on a JavaFX button press.
Instead, I recommend that you write your code native to a single library, either JavaFX or Swing.
For your example code. The JavaFX equivalent for handling button actions is:
button.setOnAction(EventHandler<ActionEvent>)
How would I set the String for the action command? Is this possible? Or do I have to do it a different way?
You wouldn't, it's not necessary.
I don't code Swing, so I'm not familiar with the Swing ActionEvent. From looking at your code, your listener seems to be providing a single point for handling multiple action events which originate from different sources, then acting on them.
For JavaFX, just define separate event handlers for each source rather than using switches, then you don't need to pass a string to the action command because it is clear what action is to be taken based upon the context.
For instance:
loginButton.setOnAction(event -> { /** handle login **/});
exitButton.setOnAction(event -> { /** handle exit **/});
If you have multiple ways to trigger the actions, for instance an exit could be triggered by both a menu item and a button, then you can define a variable for the action handler and reuse that for each instance, for instance:
EventHandler<ActionEvent> exitHandler = event -> { /** handle exit **/ };
exitButton.setOnAction(exitHandler);
exitMenuItem.setOnAction(exitHandler);
On the Linux platform, Frame::getBounds and Frame::setBounds do not work consistently. This has already been reported in 2003(!), see here:
http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4806603
For convenience, I have simplified the stated code that results in a bug and paste it as:
import java.awt.Button;
import java.awt.Frame;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/** Demonstrates a bug in the java.awt.Frame.getBounds() method.
* #author Mirko Raner, PTSC
* #version 1.0 (2003-01-22) **/
public class GetBoundsBug extends Frame implements ActionListener {
public static void main(String[] arg) {
GetBoundsBug frame = new GetBoundsBug();
Button button = new Button("Click here!");
button.addActionListener(frame);
frame.add(button);
frame.setSize(300, 300);
frame.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent event) {
Rectangle bounds = getBounds();
bounds.y--;
setBounds(bounds);
bounds.y++;
setBounds(bounds);
}
}
Unexpected behavior: Upon clicking the button the window is shifted slightly below! (On my system by 28 pixels each click.)
Here is a screen recording: https://youtu.be/4qOf99LJOf8
This behavior has been around for 13+ years, so probably there won't be any change from the official side.
Does anybody have a workaround for this bug? Specifically, I would like to store and restore the window/frame/dialog at the previous location reliably on all platforms.
PS: My java installation is jdk1.8.0_102 for amd64 by Oracle on Ubuntu 16 Linux. Since I recently migrated from Windows to Ubuntu, I know that on Windows, the code above works as expected.
The adaptation to Swing using SwingWorker produces the same effect:
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingWorker;
public class GetBoundsBug extends JFrame implements ActionListener {
public static void main(String[] arg) {
GetBoundsBug myJFrame = new GetBoundsBug();
JButton myJButton = new JButton("Click here!");
myJButton.addActionListener(myJFrame);
myJFrame.setContentPane(myJButton);
myJFrame.setSize(300, 300);
myJFrame.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent event) {
SwingWorker<Void, Void> mySwingWorker = new SwingWorker<Void, Void>() {
#Override
public Void doInBackground() {
Rectangle myRectangle = getBounds();
myRectangle.y--;
setBounds(myRectangle);
myRectangle.y++;
setBounds(myRectangle);
return null;
}
};
mySwingWorker.execute();
}
}
Well, in the original bug database entry this is marked as "Won't fix" and explained as a quirk in the window manager, rather than the JDK.
What window manager are you using?
Just an additional note. I noticed that your code failed to do very much on the Event Dispatch Thread. All of Java's drawing APIs are single threaded by design, meaning that your application should not be expected to work correctly unless you dispatch GUI updates to the Event Dispatch Thread.
This means you need to (in your main) create a new Runnable that when evaluated will present your widgets, and submit that to the EDT.
Also, your action listener updates the component state within the action, bypassing the repaint request and ignoring the typical safeties required to ensure dispatch to the EDT.
In both of these ways, you code is not valid GUI code in a Java environment, and the bug that you identify may have nothing to do with your behavior, as your program is violating the GUI toolkit design before you even know if the bug impacts it.
Also, awt only wraps components. If the components lie, then the lie trickles into Java. Not much can be done about that (but I no longer think it's the primary thing to worry about). If you don't like that, use Swing, which is a much more sane / stable environment.
I'm currently working on an application for work that has a main JFrame that always exists. I currently have a child JDialog that shows up on a button press. This frame has a JMenu with an item to "log out of the display." I've been tasked to ensure this child JDialog goes away when the log out of the display option is pressed. When the logout occurs, the main display is set invisible via:
mainFrame.setVisible(false);
The child JDialog has the default close operation:
DISPONSE_ON_CLOSE
When the user logs back in, the first thing that's done is:
mainFrame.setVisible(true);
When this happens, the child dialog shows back up. Looking at the JDialog Javadoc, this seems to be expected behavior. However I haven't found a way to break the parent/child releationship or completely destroy the child JDialog. It also seems like the JDialog will remain until it has been GC, which may not happen in a timely manner.
Here is a sample program that simulates the behavior I'm seeing:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JToggleButton;
import javax.swing.SwingUtilities;
public class WindowTest {
public static void createAndShowGUI() {
JFrame aFrame = new JFrame("LAUNCHER");
final JFrame aParent = new JFrame("PARENT");
final JDialog aChild = new JDialog(aParent);
aParent.setSize(200,200);
final JToggleButton showParentButton = new JToggleButton("HIDE");
showParentButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
showParentButton.setText(!showParentButton.isSelected() ? "SHOW": "HIDE");
aParent.setVisible(!showParentButton.isSelected());
}
});
aChild.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
aChild.setSize(200,200);
aParent.addComponentListener(new ComponentAdapter() {
public void componentHidden(ComponentEvent e) {
aChild.dispose();
aChild.setVisible(false);
}
});
aFrame.setContentPane(showParentButton);
aFrame.pack();
aFrame.setVisible(true);
aParent.setVisible(true);
aChild.setVisible(true);
}
public static void main(String [] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
createAndShowGUI();
}
});
}
}
When the parent is hidden, the child is disposed. When the parent is shown, the child shows back up. What's really weird is that when I press the X on the child: when the parent is hidden and then shown again, the child does not show back up.
The only difference I see is that clicking the X also fires a WindowClosing event. I tried the dispatch the even, in the componentHidden method above by:
//Added into the constructor
//add to the imports: import java.awt.event.WindowEvent;
aParent.addComponentListener(new ComponentAdapter() {
public void componentHidden(ComponentEvent e) {
aChild.dispose();
aChild.setVisible(false);
WindowEvent closingEvent =
new WindowEvent(aChild, WindowEvent.WINDOW_CLOSING);
aChild.dispatchEvent(closingEvent);
}
});
And that didn't solve the problem.
Currently it looks like my only option is to change the type of child to a JFrame. I just wanted to know if there was a proper way of disposing a child JDialog.
I'm currently running with Java version: 1.7.0_76 64 bit on Redhat Enterprise Linux Server release 6.4.
I wasn't aware the naming conventions affected the compile.
It doesn't. Conventions are done for consistency and readability and maintainability. The person who writes the code is not always the person that maintains the code. So if you want other people to read your code, especially when asking for help, follow the standards.
You can start with Java Programming Style Guidelines
I'm copying the code by hand from another screen per my companies standards.
This is a complete waste of time. There is nothing proprietary about your code. Again when you ask a question, the code should be in the form of a SSCCE so it demonstrates the problem. This allows you to remove all the unnecessary code.
it would be straight forward to figure out the imports.
Exactly, so you should do it. You want us to help you, so why should we spend the time figuring it out??? Make is as easy as possible for people to want to help you.
Adding the imports did not help. The code you posted still does not compile so I don't know if it accurately reflects the problem you are attempting to describe.
Again the point of posting code is so that we can copy/paste/compile/test. Until you post a proper SSCCE I will not provide the answer.
Edit:
From my testing, if the visibility of the child window is changed by the visibility of the parent when the parent is made non-visible, then the visibility of the child is also changed by the parent when it is made visible. So it looks like the parent is retaining the state of the child windows when the visibility changes.
So the solution is to make the child window non-visible before the parent:
showParentButton.setText(!showParentButton.isSelected() ? "SHOW": "HIDE");
aChild.setVisible(false); // add this
aParent.setVisible(!showParentButton.isSelected());
If you don't have a reference to the child window then I guess you can use the Windows.getOwnedWindows() method to access all the child windows.
Another edit:
As a hack I created a custom dialog that can't be shown again once it is disposed:
final JDialog aChild = new JDialog(aParent)
{
private boolean disposed = false;
#Override
public void dispose()
{
super.dispose();
disposed = true;
}
#Override
public void show()
{
if (disposed)
return;
super.show();
}
};
Within a Java swing application, the following snippet is supposed to play a siren. It starts OK but stops prematurely, not always at the same time (i.e. sometimes it stops almost immediately and sometimes after a longer delay, but usually it does not finish playing the whole sound file). What could be causing this?
I've done my best to create a minimal example that still has the problem:
package monster;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.io.File;
import javafx.embed.swing.JFXPanel;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Example_2 extends JPanel {
protected static final long serialVersionUID = 1L;
public Example_2() {
setPreferredSize(new Dimension(100,100));
setBackground(Color.white);
createPanel();
}
public static void main(String[] args) {
Example_2 e = new Example_2();
JFrame f = new JFrame();
f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
f.add(e, BorderLayout.CENTER);
f.pack();
f.setVisible(true);
f.repaint();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
new Thread(
new Runnable() {
public void run() {
try {
File f = new File("sound/siren_short.wav");
String url = "file:///"+f.getAbsolutePath().replaceAll("\\\\","/").replaceAll(" ", "%20");
MediaPlayer mp = new MediaPlayer(new Media(url));
mp.play();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
public static JFXPanel createPanel() {
return new JFXPanel();
}
}
In the current example code "Example2" posted, it looks to me like the main() executes and exits. Yes, the call to MediaPlayer launches a background thread, but I'm guessing when the main() ends, this terminates the MediaPlayer thread as well (perhaps because it only has daemon status). I haven't used the MediaPlayer yet, myself, so I don't know if this behavior can result or not.
Here is a simple test for you: add the following line.
Thread.sleep(5000); // pauses 5 seconds
or something similar to the end of the main(), after the repaint() call. The number is milliseconds: use a number that is longer than the length of your sound. Does the sound now play to completion? You'll probably have to put the new line of code in a try...catch block.
Check out the api for Thread() when you get a chance. When you get to the page, I'd recommend doing a search on "daemon". There are methods for testing or setting daemon status, plus a terse explanation of what the status means. There is a chance that if you set your runnable to not be a daemon, the program (as shown) will play once and then hang with no way to terminate it except killing it via Eclipse (if it was run in Eclipse) or via an OS task manager.
I haven't delved much into debugging threads in Eclipse--am afraid I can't offer any suggestions there.
Andrew Thompson made a good suggestion, to make use of Clip. This has the benefit of keeping us in "familiar" territory. I've used Clip frequently, but not JavaFX libraries. If you had used Clip, the line of code I'm suggesting (Thread.sleep) would definitely have been needed to allow the sound to play to completion.
Here is a theory: the code which loads and executes the play() command is non-daemon. However, the background processes which deliver the sound data to the line are daemon. If that were the case, then the behavior I describe (termination after the main thread is done) would be consistent.
I cannot use sequence at all, even THESE gives me an error.
this.AddAction(sequence());
this.AddAction(sequence(setX(getY())));
No matter what I do sequence won't work, despite these being imported. addAction does not work either, nor does addAction & Actions.sequence.. Nothing does as far as this goes.
import com.badlogic.gdx.scenes.scene2d.actions.Actions;
import com.badlogic.gdx.scenes.scene2d.actions.AddAction;
Edit: I needed to make my class an Actor.
This worked fine for me.
Do this in your constructor of the screen where you want the action:
image.addAction(sequence(fadeOut(3), run(new Runnable() {
#Override
public void run() {
game.setScreen(new MenuScreen(game));
}
}));