Java ListSelectionListener interface with keyboard - java

I have implemented ListSelectionListener as you can see below, so that after a specific line in the first table is being chosen, the second table gets updated accordingly.
class SelectionListener implements ListSelectionListener {
public SelectionListener(){}
#Override
public void valueChanged(ListSelectionEvent e)
{
if (e.getSource() == myTrumpsAndMessages.jTable1.getSelectionModel()
&& myTrumpsAndMessages.jTable1.getRowSelectionAllowed()
&& e.getValueIsAdjusting())
{
int selected = myTrumpsAndMessages.jTable1.getSelectedRow();
clearjTable(jTable4);
showSubscribers(selected);
}
}
}
Is there a way to invoke the listener not only when the mouse is choosing, but also when the choice is being made from the keyboard?

The reason for the unusual experience - no notification on selection via keyboard - is a subtle different setting of valueIsAdjusting for keyboard vs. mouse-triggered selection events:
keyboard triggered selection (even with modifiers) only fires once (with adjusting == false)
mouse triggered selection always fires twice (first with true, second with false)
That fact combined with the unusual logic (which #Robin spotted, +1 to him :-)
if (e.getSource() == myTrumpsAndMessages.jTable1.getSelectionModel()
&& myTrumpsAndMessages.jTable1.getRowSelectionAllowed()
// typo/misunderstanding or feature? doing stuff only when adjusting
&& e.getValueIsAdjusting())
(reacting only if the selection is adjusting) leads to not seeing keyboard triggered changes.

Is there a way to invoke the listener not only when the mouse is choosing, but also when the choice is being made from the keyboard?
The listener will be triggered, independent of the source of the selection change. So yes, this is perfectly possible and even the default behavior. So nothing special must be done to get this working.
Looking at the code of your listener, I would suggest to rewrite it to
class SelectionListener implements ListSelectionListener {
public SelectionListener(){}
#Override
public void valueChanged(ListSelectionEvent e){
if ( e.getValueIsAdjusting() ){
return;
}
if (e.getSource() == myTrumpsAndMessages.jTable1.getSelectionModel() &&
myTrumpsAndMessages.jTable1.getRowSelectionAllowed() ) {
int selected = myTrumpsAndMessages.jTable1.getSelectedRow();
clearjTable(jTable4);
showSubscribers(selected);
}
}
}
Note the quick break from the method when getValueIsAdjusting() returns true as this is the behavior you want in most cases.

I've just tried a ListSelectionListener and the valueChanged() event is actually being triggered on keyboard selection change as well. See my example below:
list.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
System.out.println(list.getSelectedValue());
}
});

Related

Mouse click to boolean

Hello from novice java developer, I created a MouseListener and MouseAdapter in a thread to control mouse action for mouse pressed, released and drag action. Each action will do specific things but i could not assign each MouseEvent e from each action to a variable.
So, how can deal with this problem? I also wonder if the method parameter MouseEvent e is specific to each method?
Here is my code:
Thread thread = new Thread() {
public void run() {
addMouseListener(new MouseAdapter() {
//#override deleted because i want to use e as a different action.
public void mouseaction(MouseEvent e) {
/* In here i want to control MouseEvent e action
(drag, pressed and released) and do specific things in with e event
and if e changes state should be changed in code during while(true) */
}
}
}
You can get all this information from the mouseEvent by calling the method getModifiersEx(), for example:
int eventType = e.getModifiersEx();
if (eventType & MOUSE_DRAGGED > 0) {
// Code to be executed when mouse is dragged
}
if (eventType & MOUSE_PRESSED > 0) {
// Code to be executed when mouse button is pressed
}
...
Note that the eventType is a bit field where multiple bits can be activated simultaneously.
//#override deleted because i want to use e as a different action.
public void mouseaction(MouseEvent e)
You can't just make up method names. You need to implement the methods of the listener. You need to handle the mousePressed, mouseReleased methods separately. For the mouseDragged you need to implement the MouseMotionListener.
Read the section from the Swing tutorial on Implementing Listener. You can find sections on:
How to Implement a MouseListener
How to Implement a MouseMotionListener
which both contain working examples.
I'll address this concern:
I also wonder if the method parameter MouseEvent e is specific to each method?
Every time this method is invoked by Swing, a new Event is generated. Your #Override annotation makes no difference.
So when user clicks somewhere, a MouseEvent N°2556 is generated for it, and the method is invoked with that event as a parameter.
When user drags the mouse away, a MouseEvent N°2557 is generated, and the method is again invoked with this new event as a parameter.
More broadly: All those MouseEvents will always be different instances. They are immutable, as well.
This means if you want to persist some information for your game loop to see, you need to store the relevant conditions in a field somewhere. And you won't be able to access it from an anonymous class because you won't have a handle to it. Here is a quick and dirty example (shameless reuse of #FrankPuffer's code):
public class MyMouseAdapter extends MouseAdpater {
public boolean isMousePressed = false; // This info is persisted here
public void mouseaction(MouseEvent e) { // This is only triggered upon user input
int eventType = e.getModifiersEx();
if (eventType & MouseEvent.MOUSE_PRESSED) {
isMousePressed = true;
}
if (eventType & MouseEvent.MOUSE_RELEASED) {
isMousePressed = false;
}
}
}
public static void main(String[] argc){
// Before the game loop:
MyMouseAdapter myAdapter = new MyMouseAdapter();
jpanel.addMouseListener(myAdapter);
// In the game loop
while(true) {
if(myAdapter.isMousePressed) { // This info is available anytime now!
// Do something
}
}
}

FocusListener for all controls of a Composite

I've written code for a Composite containing multiple controls (StyledTexts, Buttons, etc.).
I wanted to implement a FocusListener for the whole Composite (not only for one of the controls inside of it), but the FocusListener did not do anything.
I tried to implement it myself, and my attempt was: Add a FocusListener to every Control inside the composite and handle these events.
While trying to do so, I found some problems:
When two controls have a FocusListener and I change the focus from one to the other, the FocusLost event is fired before the FocusGained
So I can't find out if the focus was given to one of the other controls in my composite, or if the composite lost the focus completely.
Note: I tried using Display.getFocusControl() inside the focusLost(...) method, but it only returns the control from which the focus is taken!
My question: Is it possible to find out which control will receive the focus next while being inside the focusLost(...) method?
If not: Is there any other way to implement a FocusListener for a Composite?
At the time the focusLost() event is sent, it isn't yet known which control (if any) will receive the focus.
You can add a display filter that will inform you whenever a control within your entire application gains focus. Within your ' Listener` implementation, you can save the text input whenever a control gains focus that is not contained in the composite. For example:
Listener listener = new Listener() {
#Override
public void handleEvent( Event event ) {
if( event.widget != text || event.widget != fontButton || ... ) {
save();
}
}
};
display.addFilter( SWT.FocusIn, listener );
Make sure to add the listener only while the observed composite is alive. Remove the filter when the composite is disposed of.
display.removeFilter( SWT.FocusIn, listener );
#RüdigerHermanns works pretty good, but for the sake of completeness I'll post my solution here too:
I've written listeners for SWT.Activate and SWT.Deactivate in my composite:
public MyComposite(Composite parent, int style)
{
super(parent, style);
createGuiElements(this);
this.addListener(SWT.Deactivate, new Listener()
{
#Override
public void handleEvent(Event event)
{
for (FocusListener listener : focusListeners) listener.focusLost(new FocusEvent(event));
}
});
this.addListener(SWT.Activate, new Listener()
{
#Override
public void handleEvent(Event event)
{
for (FocusListener listener : focusListeners) listener.focusGained(new FocusEvent(event));
}
});
}
which notify all focusListeners on the Composite.

Keeping Track of Every Time that a Checkbox is checked and unchecked

I have most of my java application done already, so I am now logging all user activity. One thing I want to keep track of is whenever one of my checkboxes is checked and unchecked. I am able to read at the end if the object is checked or unchecked, however I want to know each time the checkbox is used in real time. I want to know how many times the user checks and unchecks the box. Right now I am using something similar to this syntax, but it doesn't print a statement each time the checkbox is checked and unchecked.
public CheckboxAction(String text) {
super(text);
}
#Override
public void actionPerformed(ActionEvent event) {
JCheckBox cbLog = (JCheckBox) event.getSource();
if (cbLog.isSelected()) {
System.out.println("Logging is enabled");
} else {
System.out.println("Logging is disabled");
}
}
An ItemListener seems appropriate here
yourJCheckBox.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent arg0) {
if (yourJCheckBox.isSelected()) {
// Code to execute when it's selected
}
else {
// Code to execute when not selected
}
}
});
First and foremost, do not override actionPerformed. If you need to - at least call super.actionPerformed before performing your action. Best way is to use addActionListener or in this case as #BoDidely mentioned use an addItemListener.

Can't get ItemListener to work for JCheckBox

I am using this code to create a JCheckBox
private final JCheckBox cbDisplayMessage = new JCheckBox("Display");
cbDisplayMessage.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
if(e.getItemSelectable() == cbDisplayMessage) {
if(cbDisplayMessage.isSelected()) {
cbDisplayMessage.setSelected(false);
} else {
cbDisplayMessage.setSelected(true);
}
}
}
});
When I run this it causes an StackOverflow error on setSelected(true). Can't figure out what I am doing wrong. Any ideas appreciated....
You can try with ActionListener instead of ItemListener as shown below without causing StackOverflow error.
cbDisplayMessage.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (cbDisplayMessage.isSelected()) {
cbDisplayMessage.setSelected(false);
} else {
cbDisplayMessage.setSelected(true);
}
}
});
There is no need to check the source of the event again because you are sure that you have added this listener on the same object. This is required only if same listener is added for more components.
-- EDIT--
Now Your requirement is clear to me. If you want to toggle the state of the check box then there is no need to do it using listener because that's the default behavior of the check box.
Your listener is called every time the state changes, but you trigger a new state change from within that listener, so each state change results in that listener being called over and over again until your stack is full. Your setup has to be a bit more complicated to do something like that - if you want to change the state of the component you're listening to, you'll want to remove its listener(s), fire your programmatic state change, then re-add them.

setEditable using ActionListener

Clicking the button should toggle between setting the textfield as editable or not. When the GUI opens the textfield should be editable.
public void actionPerformed( ActionEvent evt)
{
if(inputField.setEditable() == (true))
{
inputField.setEditable(false);
}
else
{
inputField.setEditable(true);
resultMessage.setText("");
resultMessage.setText("Edit Button Pressed");
}
What am i doing wrong here?
I know that the else statement is right just the start of the IF is wrong, i'm not sure where i'm going wrong.
Additional question:
public void actionPerformed( ActionEvent evt)
{
if(inputField.isEditable() == (true))
{
inputField.setEditable(false);
}
else
{
inputField.setEditable(true);
inputField.setText("");
resultMessage.setText("Edit Button Pressed");
}
if(inputField.getBackground() == Color.RED)
{
inputField.setBackground(Color.WHITE);
}
else
{
inputField.setBackground(Color.RED);
resultMessage.setText("Colour Button Pressed");
}
}
I now currently have 2 IFs but obviously the first IF will stop the second IF from working how do i get around this so that when i press one button that will do the setEditable section and when i press the other button it will do my change colour?
You're checking if setEditable() is true which really makes no sense; after all, it returns void and requires a boolean parameter. The bigger problem is that you shouldn't be checking the editable status via a "setter" field but rather a "getter" field, here isEditable()
if (inputField.isEditable()) {
//....
} else {
//...
}
As MadProgrammer points out, this information is all readily available in the Java API, something you'll want to get very familiar with.
Edit, regarding your new question:
I now currently have 2 IFs but obviously the first IF will stop the second IF from working how do i get around this so that when i press one button that will do the setEditable section and when i press the other button it will do my change colour?
No, the first if/else will have no effect on the second if/else block. Your problem lies elsewhere. Consider asking this with additional information as a new question on stackoverflow if still suck.
Also note that this is unnecessarily wordy:
if(inputField.isEditable() == (true))
and is better written as I have it above:
if (inputField.isEditable())

Categories