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);
Related
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();
}
};
We know that JComponent has several methods to add various listeners. One example is the addMouseMotionListneer().
Within a MouseMotionListener, there are 2 methods to be overridden:
public void mouseMoved(MouseEvent e){}
public void mouseDragged(MouseEvent e){}
Whenever the mouse is moved, mouseMoved() will be invoked.
My question is:
1) How does Java detects mouse movement? Is there a lot of lower level stuff (like communicating with mouse drivers..etc) where Java is doing behind our back?
2) I know if we want to detect mouse movements, we simply could use the event listeners in the awt. But is there any possibilities we could write our own listeners to detect mouse movement? Or we can simply forget about it as it is mission impossible?
Something like this might be what you need:
import java.awt.MouseInfo;
import java.awt.GridLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;
import javax.swing.*;
public class mice {
public static void main(String[] args) throws InterruptedException{
while(true){
//Thread.sleep(100);
System.out.println("("+MouseInfo.getPointerInfo().getLocation().x+", "+MouseInfo.getPointerInfo().getLocation().y+")");
}
}
you could use the event listeners of awt but that are not platform independent.
ON some platforms it will not work fine.
Yes could write our own listeners to detect mouse movement by implementing MouseMotionListener or MouseListener interface and add your custom methods for some special events
OR
you have to follow delegate event model. So create a class MyMouseEvent , MyMouse and interface MyMouseListner
interface MyMouseListener{
public void clicked();
}
Class MyMouse{
MyMouseListener m;
public void register(MyMouseListener m){
this.m=m;
}
}
class MyMouseEvent{
//use in case of multiple event listener
}
Then registered by creating object
MyMouse m = new MyMouse().register(new MyMouseListener(){
public void clicked(){
// your code here
}
})
I went through plenty of articles and (imo too complex) examples of how to separate GUI from the rest of the program logic in Java, and to be completely honest, I still have no clue.
Could someone give me a hint of how to do it on this simple example, with just one button?
Let's say there is a button in the Window class:
JButton firstButton = new JButton("My first button");
btnCreateProject.setBounds(100, 100, 80, 30);
frame.getContentPane().add(firstButton);
and let's say this button would call a constructor of the Employee class. So, I could do it like this:
JButton firstButton = new JButton("My first button");
firstButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
.....constructor calling, and rest of the code....
}
});
btnCreateProject.setBounds(100, 100, 80, 30);
frame.getContentPane().add(firstButton);
But this is exactly what I DO NOT want. I want my Window class to be just pure GUI, with buttons, radio boxes, and other stuff, with it's properties. Nothing more. I would like to have all the listeners in another class, let's say Controller, and from this class I would call all the needed methods.
Could someone give me an example of how to do it with this simple button? Thank you very much.
You are drawing a distinction of degree, not kind. Your GUI code cannot be completely separated from program logic, else it would be a static work of modern art.
The various kinds of AWT/Swing listener classes do separate GUI from logic, into altogether separate classes. You do not, however, need to implement listeners as anonymous inner classes; perhaps it would feel better to you to implement them as ordinary, top-level classes instead. Alternatively, you might find that it suits you to model program behaviors via classes implementing the Action interface. Then you can assign those behaviors to controls (buttons, menu items) via the controls' setAction() method.
Any way around, however, the code that sets up your GUI has to somehow know about both the GUI components and the logic that needs to be hooked up to them, else there's no way it could do its job.
This is a constructor for a new class:
new ActionListener() {
public void actionPerformed(ActionEvent e) {
.....constructor calling, and rest of the code....
}
}
You could make a class like:
public class ActionListenerTest implements ActionListener {
...
}
Then make something like this:
firstButton.addActionListener(new ActionListenerTest());
I had the same issue with my projects, but finally I decided to use a concept I learned in android programming. Here is how it works:
I add an identified to my objects (for buttons, menus, etc I use setActionCommand method) so I can use the same identifier for the same operations for different components.
All my objects call one controller with their getActionCommand as cmd and the object itself. Within the controller, I control the cmd and call the proper method from it.
It is much more easier to control the GUI and the rest of the program.
It worked for me this way like charm.
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDialog;
/**
*
* #author Pasban
*/
public class ActionListenerTest {
public static void main(String[] args) {
JButton b1 = new JButton("My first button");
JButton b2 = new JButton("My first button");
b1.setActionCommand("BTN_1");
b2.setActionCommand("BTN_2");
//put this in another class
ActionListener controller = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand().toUpperCase().trim();
System.out.println(cmd);
//System.out.println(e.getSource()); // cast to anything you have in your mind about the caller
if (cmd.equals("BTN_1")) {
System.out.println("BUTTON 1 is clicked");
} else if (cmd.equals("BTN_2")) {
System.out.println("BUTTON 2 is clicked");
}
}
};
b1.addActionListener(controller);
b2.addActionListener(controller);
JDialog frame = new JDialog();
frame.setSize(new Dimension(300, 300));
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
frame.getContentPane().setLayout(new FlowLayout());
frame.getContentPane().add(b1);
frame.getContentPane().add(b2);
frame.setVisible(true);
}
}
You could always just implement something like:
Controller.handleActionEvent(ActionEvent e);
and delegate your button click to that. And if you don't want your controller to know about Swing, you could always create some interface and wrap the Swing ActionEvent in some kind of event of your creation.
Or just implement an Observer (Listener) pattern in the UI class (or you could have a "registry" class that sits in the middle). When the button is clicked, the UI would delegate the event to all registered listeners (implementing some interface that you define). So the Controller (client) would just tell the UI "notify me when Button X is clicked" and the UI would just delegate to all interested parties.
So, the UI wouldn't need to know who to call explicitly. But the controller would have to know who he wants to listen to.
What you should do is write a method where appropriate to access datamodel (supposing you have one) and do the work there, and just call the method from button click.
firstButton.addActionListener(e -> logicClass.addEmployeeToFirm());
or you could event write a custom Listener that would call/do that logic (a class that implements ActionListener).
Inside your controller, create a method
Action get[Operation]Handler(); //Fill in [Operation] will what your button functionality should do
which returns an inner class that implements the proper functionality.
Then, in your GUI code, do
JButton b = ...;
b.setAction(controller.get[Operation]Handler());
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?