Java MouseEvents not working - java

This may be a stupid question, but I have to ask!
I have the following code snippets that are supposed to run their corresponding methods when the user interacts with objects.
For some reason, "foo" is never printed, but "bar" is.
myJSpinner1.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseEntered(java.awt.event.MouseEvent evt) {
System.out.println("foo"); //"foo" is not printed
}
});
myJSpinner2.addChangeListener(new java.awt.event.ChangeListener() {
public void stateChanged(java.awt.event.ChangeEvent evt) {
System.out.println("bar"); //"bar" is printed
}
});
I get no exceptions or stack trace. What am I missing in the MouseListener one?
Thanks in advance.
EDIT: MouseEntered works perfectly on a JCheckBox implemented in exactly the same way!

JSpinner is a composite component consisting of a text field and 2 buttons. It's possible to add mouse listeners to all of those by iterating over the results of getComponents() and adding a listener to each.
However, in my experience, when something takes that much work, you're probably going about it the wrong way.
Why do you need the mouse-entered information for a JSpinner?
What do you want to do with this event?
Update:
If you're looking to supply information about all of the controls in your panel, you may want to look at using a glasspane to detect the component under the mouse.
A Well-behaved Glasspane by Alexander Potochkin is a good place to start.

This is a guess but I suspect you need to add a MouseListener to the JSpinner's editor (via a call to getEditor()). I imagine that the editor Component occupies all available space within the JSpinner and is therefore intercepting all MouseEvents.

This worked for me.
JSpinner spinner = new JSpinner();
((JSpinner.DefaultEditor)spinner.getEditor()).getTextField().addMouseListener(
new java.awt.event.MouseAdapter() {
public void mouseClicked(final MouseEvent e) {
// add code here
}
});
I needed this in order to evoke a popup key dialog for added usability due to our software requirements.

Aditional to #Rapier answer...
If you change the Spinner using something like
yourOldSpinner = new JSpinner(new SpinnerModel(...))
you will lost your previosly MouseListener...
If you need to change something of SpinnerModel, Don't create a new, change its parameters instead! (if you do it, you will need to reassign the MouseListener again, because it will be lost when you assign a new SpinnerModel).
an example (I'm talking...):
((SpinnerNumberModel)yourOldSpinner.getModel()).setValue(size/3);
((SpinnerNumberModel)yourOldSpinner.getModel()).setMinimum(0);
((SpinnerNumberModel)yourOldSpinner.getModel()).setMaximum(isize/2);
((SpinnerNumberModel)yourOldSpinner.getModel()).setStepSize(1);

Related

Dynamic update of visual components in swing

I have a question regarding the possibility to dinamically update the visual side of a swing application.
I have created a small program, that works without any compile/logic errors and it does it's thing but it has a flaw. It does not automatically update when user clicks on something.
Let me explain the issue with the underneath picture
I tried adding a repaint and revalidate to anything. but it doesn't seem to work. they get ignored. Really, I added a repaint/revalidate method to EVERYTHING. Still nothing :)
I suggest adding the action event to the checkbox (I called it fullAutomaticCheckBox and the field txtField):
private void fullAutomaticCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {
txtField.setEnabled(fullAutomaticCheckBox.isSelected());
}
To add the event listener:
fullAutomaticCheckBox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
fullAutomaticCheckBoxActionPerformed(evt);
}
});
I want the text field to enable itself.
Then you add an ActionListener to the check box to enable/disable the text field depending on the state of the checkbox.
once user inputs a number it will repaint dynamically
If you want the screen to repaint, then you need to invoke the "update calculations" code dynamically. So you can add a DocumentListener to the text field. This will generate an event any time the user adds or removes text in the text field.
Read the section from the Swing tutorial on How to Write a DocumentListener for a basic example to get you started.

How do you attach a listener to a JavaFX spinner?

I've run into what seems (to me, anyway) an odd problem with JavaFX spinners and not being able to attach any kind of listener to it.
I'm used to Swing programming, where I can attach a ChangeListener to a JSpinner and receive events that way, but JavaFX doesn't seem to have anything like that.
The code in question...
IntegerSpinnerValueFactory spinnerValueFactory = new SpinnerValueFactory.IntegerSpinnerValueFactory(0, Integer.MAX_VALUE);
hullPointsSpinner = new Spinner<Integer>(spinnerValueFactory);
hullPointsSpinner.setEditable(true);
((TextField)hullPointsSpinner.getEditor()).setOnAction(new EventHandler<ActionEvent>() {
public void handle( ActionEvent event )
{
System.out.println("Howdy, folks! Value is " + hullPointsSpinner.getValue() + "!!");
}
});
The arrow buttons will increase and decrease the value in the field, but have no effect on the value in the model. Only selecting the contents of the field and pressing enter will actually update the data in the model and prints out the value. (The pressing enter thing is in the documentation, I know.)
I also realize that I'm putting that EventHandler onto the Spinner's TextField with getEditor, but I have yet to see another way to do this.
Is there a way to hook a listener to the spinner's buttons?
(Heck, is there even a way to get at those buttons to attach a listener?)
Am I receiving the wrong type event from the spinner/editor?
Can I put some kind of listener on the spinnerValueFactory?
Is there some kind of obvious solution that I'm overlooking here?
I'll replace this with a JSpinner, if necessary, but it just seems crazy to me that this API would have a spinner component and such an awkward way to use it.
Thanks in advance.
The following seems to work fine for me:
hullPointsSpinner.valueProperty().addListener((obs, oldValue, newValue) ->
System.out.println("New value: "+newValue));
Alternatively you can do
spinnerValueFactory.valueProperty().addListener(...);
with the same listener as above.
You should note this bug, which is fixed in 1.8.0u60.

Using KeyListener for a Calculator in NetBeans

I have written a calculator in NetBeans and it functions perfectly. However, I have to actually click the buttons to insert numbers and am trying to remedy that with a KeyListener. I have all my numbers and function buttons set inside a JPanel named buttons. I have my display label in a JPanel named display.
I set my class to implement KeyListener and it inserted the KeyPressed, -Typed, and -Released methods; however I stuck from there. I'm not sure how to make my buttons actually listen for the KeyPressed event, and when it hears the event - activate the button. Also, my buttons are named by their number (e.g. the Zero Button is named zero, One button is one, etc.).
I've read that you actually have to implement a KeyListener somewhere by using: something.addKeyListener(something);
but I cannot seem to figure this out.
Can I get some help here? I'm new to Java and this is my first solo project. And let me know if I didn't provide enough information.
EDIT: Most of my code is NetBeans Generated and I cannot edit the initialization of the components which seems to be my problem I think?
My class declaration:
public class Calculator extends javax.swing.JFrame implements KeyListener {
//Creates new form Calculator
public Calculator() {
initComponents();
}
One of my buttonPressed actions (all identical with changes for actual number):
private void zeroActionPerformed(java.awt.event.ActionEvent evt) {
if (display.getText().length() >= 16)
{
JOptionPane.showMessageDialog(null, "Cannot Handle > 16 digits");
return;
}
else if (display.getText().equals("0"))
{
return;
}
display.setText(display.getText().concat("0"));
Main method supplied by NetBeans:
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Calculator().setVisible(true);
}
});
}
The initComponents() netbeans generated is absolutely massive (about 500 lines of code) and I cannot edit any of it. Let me know if I can supply any more helpful information.
Could there be an issue of Focus, and if so how can I resolve the issue?
Yes there is probably an issue with focus. That is why you should NOT be using a KeyListener.
Swing was designed to be used with Key Bindings. That is you create an Action that does what you want. Then this Action can be added to your JButton. It can also be bound to a KeyStroke. So you have nice reusable code.
Read the Swing tutorial on How to Use Key Bindings for more information. Key Bindings don't have the focus issue that you currently have.
I'm not sure I completely understand your question, and some code would help, but I'll take a crack, since it sounds like a problem I used to have a lot.
It sounds like the reason that your key presses aren't being recognized is that the focus is on one of the buttons. If you add keylisteners to the buttons, then you shouldn't have any problem.
In netbeans you can add keylisteners through the design screen really easily.
Here's a picture showing you how to add a keyPressed listener to a button in a jPanel.
private void jButton1KeyPressed(java.awt.event.KeyEvent evt) {
//Check which key is pressed
//do whatever you need to do with the keypressed information
}
It is nice to be able to write out the listeners yourself, but if you are just learning, then it is also nice to get as much help as possible.
This might not be the best solution, since you would have to add the listener for each of your buttons.

Java swing combo box only calling listener once

Very new to Java and Swing, and I have been playing with a swing gui application. It generated some code for my combo box:
comboBox.addActionListener(EventHandler.create(ActionListener.class, TestController, "changeSomething"));
and i also have this:
import javax.swing.JComboBox;
import javax.swing.JOptionPane;
public class StudyPlanController {
private JComboBox factors;
public void changeSomething() {
JOptionPane.showMessageDialog(null, "change!");
}
}
I have 2 questions.
When I change the selected item in the combo box i get the message "change!" only the first time it is changed. Why is this?
When googling for a solution, all the code for setting up the listener was different to the code generated for me. e.g
box.addItemListener(new ItemListener(){
public void itemStateChanged(ItemEvent e){
System.out.println(e.getItem() + " " + e.getStateChange() );
}
});
Is the way i'm createing the listener correct? why are there two ways to do this?
Thanks
For JComboBox is better implements ItemListener, but this Listener is always called twice SELECTED and DESELECTED, you can check that if event is SELECTED/DESELECTED
myComboBox.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
//some stuff
}
}
});
You can use ActionListener, but I suggest to use that for changing itself own JComboBox's properties or methods, not to ouside from JComboBox, to ouside somewhere to the GUI
You can use EventHandler, but better would be start to leaning basic stuff before
First an answer about EventHandler. Normally event handling is done as #mKorbel says. For many event listeners classes there are specific methods getting invoked on an event. This can lead to many anonymous inner classes. Therefore EventHandler was introduced. It is more efficient using reflection, and creates less objects. See http://docs.oracle.com/javase/7/docs/api/java/beans/EventHandler.html
Secondly, why it went wrong: I would expect:
comboBox.addItemListener(ItemListener.class, textController, "doSomething");
As #mKorbel said, because of the SELECTED test, it is better to not using EventHandler here.
Further to the given answer I had problems with code generated by Netbeans - which it hides away in case we break it !!
While the Builder gets a quick GUI setup - and for what it does its excellent, I had faulty event code generated.
I am now in a habit of not adding events using the Builder but have an 'own written' method to set these up - especially in this case using the excellent advise above.

Is there an easy way to change the behavior of a Java/Swing control when it gets focus?

For most GUI's I've used, when a control that contains text gets the focus, the entire contents of the control are selected. This means if you just start typing, you completely replace the former contents.
Example: You have spin control that is initialized with the value zero. You tab to it and type "1" The value in the control is now 1.
With Swing, this doesn't happen. The text in the control is not selected and the carat appears at one end or another of the existing text. Continuing the above example:
With a Swing JSpinner, when you tab to the spin control, the carat is at the left. You type "1" and the value in the control is now 10.
This drives me, (and my users) up a wall, and I'd like to change it. Even more important, I'd like to change it globally so the new behavior applies to JTextField, JPasswordField, JFormattedTextField, JTextArea, JComboBox, JSpinner, and so on. The only way I have found to do this to add a FocusAdapter to each control and override the focusGained() method to Do The Right Thing[tm].
There's gotta be an easier, and less fragile way. Please?
EDIT: One additional piece of information for this particular case. The form I am working with was generated using Idea's form designer. That means I normally don't actually write the code to create the components. It is possible to tell Idea that you want to create them yourself, but that's a hassle I'd like to avoid.
Motto: All good programmers are basically lazy.
When I've needed this in the past, I've created subclasses of the components I wanted to add "auto-clearing" functionality too. eg:
public class AutoClearingTextField extends JTextField {
final FocusListener AUTO_CLEARING_LISTENER = new FocusListener(){
#Override
public void focusLost(FocusEvent e) {
//onFocusLost(e);
}
#Override
public void focusGained(FocusEvent e) {
selectAll();
}
};
public AutoClearingTextField(String string) {
super(string);
addListener();
}
private void addListener() {
addFocusListener(AUTO_CLEARING_LISTENER);
}
}
The biggest problem is that I haven't found a "good" way to get all the standard constructors without writing overrides. Adding them, and forcing a call to addListener is the most general approach I've found.
Another option is to watch for ContainerEvents on a top-level container with a ContainerListeer to detect the presence of new widgets, and add a corresponding focus listener based on the widgets that have been added. (eg: if the container event is caused by adding a TextField, then add a focus listener that knows how to select all the text in a TextField, and so on.) If a Container is added, then you need to recursively add the ContainerListener to that new sub-container as well.
Either way, you won't need to muck about with focus listeners in your actual UI code -- it will all be taken care of at a higher level.
I haven't tried this myself (only dabbled in it a while ago), but you can probably get the current focused component by using:
KeyboardFocusManager (there is a static method getCurrentKeyboardFocusManager())
an adding a PropertyChangeListener to it.
From there, you can find out if the component is a JTextComponent and select all text.
A separate class that attaches a FocusListener to the desired text field can be written. All the focus listener would do is call selectAll() on the text widget when it gains the focus.
public class SelectAllListener implements FocusListener {
private static INSTANCE = new SelectAllListener();
public void focusLost(FocusEvent e) { }
public void focusGained(FocusEvent e) {
if (e.getSource() instanceof JTextComponent) {
((JTextComponent)e.getSource()).selectAll();
}
};
public static void addSelectAllListener(JTextComponent tc) {
tc.addFocusListener(INSTANCE);
}
public static void removeSelectAllListener(JTextComponent tc) {
tc.removeFocusListener(INSTANCE);
}
}
By accepting a JTextComponent as an argument this behavior can be added to JTextArea, JPasswordField, and all of the other text editing components directly. This also allows the class to add select all to editable combo boxes and JSpinners, where your control over the text editor component may be more limited. Convenience methods can be added:
public static void addSelectAllListener(JSpinner spin) {
if (spin.getEditor() instanceof JTextComponent) {
addSelectAllListener((JTextComponent)spin.getEditor());
}
}
public static void addSelectAllListener(JComboBox combo) {
JComponent editor = combo.getEditor().getEditorComponent();
if (editor instanceof JTextComponent) {
addSelectAllListener((JTextComponent)editor);
}
}
Also, the remove listener methods are likely unneeded, since the listener contains no exterior references to any other instances, but they can be added to make code reviews go smoother.
After reading the replies so far (Thanks!) I passed the outermost JPanel to the following method:
void addTextFocusSelect(JComponent component){
if(component instanceof JTextComponent){
component.addFocusListener(new FocusAdapter() {
#Override
public void focusGained(FocusEvent event) {
super.focusGained(event);
JTextComponent component = (JTextComponent)event.getComponent();
// a trick I found on JavaRanch.com
// Without this, some components don't honor selectAll
component.setText(component.getText());
component.selectAll();
}
});
}
else
{
for(Component child: component.getComponents()){
if(child instanceof JComponent){
addTextFocusSelect((JComponent) child);
}
}
}
}
It works!
The only way I know is to create a FocusListener and attach it to your component. If you want it this FocusListener to be global to all components in your application you might consider using Aspect Oriented Programming (AOP). With AOP is possible to code it once and apply your focus listener to all components instantiated in your app without having to copy-and-paste the component.addFocusListener(listener) code throughout your application..
Your aspect would have to intercept the creation of a JComponent (or the sub-classes you want to add this behaviour to) and add the focus listener to the newly created instance. The AOP approach is better than copy-and-pasting the FocusListener to your entire code because you keep it all in a single piece of code, and don't create a maintenance nightmare once you decide to change your global behavior like removing the listener for JSpinners.
There are many AOP frameworks out there to choose from. I like JBossAOP since it's 100% pure Java, but you might like to take a look at AspectJ.

Categories

Resources