I've implemented my own event handler and added it to the selection model of the table:
table.getSelectionModel().addListSelectionListener(event);
And implemented the method for "event" (mentioned above):
public void valueChanged(ListSelectionEvent e) {
log.debug("value changed");
}
Unfortunately the event fires twice if I chance the selection and it doesn't seem possible to find the associated table, because e.getSource provides javax.swing.DefaultListSelectionModel.
Hence my questions are:
1) Why does it fire twice although the eventListener is only registered once?
2) How can I find the table for which the selection applies? The DefaultListSelectionModel doesn't seem to offer any getSource() or similar.
Many thanks!
Thanks Draemon..It Works fine....
Our Code
vMachinesTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent lse) {
if (!lse.getValueIsAdjusting()) {
System.out.println("Selection Changed");
}
}
});
Thanks By
TF Team
1) I think you'll find it fires once for de-selecting the old selection and once for selecting the new selection. If you log the details of the event you should see exactly what's going on. I can't remember the details, so perhaps this is wrong. Either way you should be able to call getValueIsAdjusting() on the event and only use the last one in the chain (ie when it returns false).
2) You shouldn't normally need to, but AFAIK the only way to do this is to create your Listener specifically for the table (ie pass the table to the constructor and remember it).
Since more than one JTable (or other component I'm guessing) can share the same selection model, it doesn't make sense to ask for the associated JTable from the event. This is the same reason that you can't retrieve a JTable from a TableModel. As Draemon suggests, store the reference to the JTable in (or make it accessible to) your listener class.
Related
I have 2 questions for this
First question:
What's the best way (in terms of performance) to add a ListSelectionListner event to JTable.
This:
myTable.getSelectionModel().addListSelectionListener(this);
Or this:
myTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
#Override
public void valueChanged(ListSelectionEvent e) {
//Do my stiff here...
}
}
});
Second question:
I have this code:
myFirstTable.getSelectionModel().addListSelectionListener(this);
mySecondTable.getSelectionModel().addListSelectionListener(this);
How can I know the JTable that fired the ListSelectionListner event ?
Part 1
Irrelevant, neither is better or worse from the perspective of performance, it will come down to needs. Obviously if you have a single listener added to multiple tables it would be more efficient from a memory point of view
Which you would use would come down to needs and what you are trying to achieve
Part 2
Use the ListSelectionEvent#getSource method to determine what actually triggered the event
I need to cancel all selections within a JTable model object. Java provides this function "clearSelection()" which does, what I need, as far as I understand.
But I am confused why this function can be called on a JTable object as well as on a selection model for a JTable object:
1) mytable.clearSelection();
2) mytable.getSelectionModel().clearSelection();
Both ways work, but I do not understand in what situation a clearSelection() of a SelectionModel (like at 2) ) would make any sense. As far as I understood SelectionModels, they are used to decide what kind of selections a JTable allows. I use the SelectionModel to only allow a Selection of exactly one row
//allow only one row to be selected
mytable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
Which way is to be preferred in what kind of situation? Is there a good reason not to use way 1?
I would be glad if anyone has some beginner friendly explanation for that. Thx in advance.
Here is the implementation of JTable#clearSelection()
public void clearSelection() {
selectionModel.clearSelection();
columnModel.getSelectionModel().clearSelection();
}
As you can see, there is two ListSelectionModel which are cleared, because you can select column and/or row and/or cell.
From Oracle tutorial :
JTable uses a very simple concept of selection, managed as an
intersection of rows and columns. It was not designed to handle fully
independent cell selections.
A ListSelectionModel handle all aspect of the selection such as which row is selected, how can we select some rows, etc... Not only the kind of selection !
More information in the Oracle JTable tutorial
Usually when you see two methods like that it is because the table will invoke the SelectionModel.clearSelection() method for you. So the table method is a convenience method.
In this case the actual code is:
public void clearSelection()
{
selectionModel.clearSelection();
columnModel.getSelectionModel().clearSelection();
}
So both the row and column selection models are cleared.
I have a column in JTable that binds to the underlying boolean property on a list of business objects. I also have a combobox, which should select which items should be selected. I basically added the following code as a handler to the combobox:
macroCombo.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JComboBox comboBox = (JComboBox) e.getSource();
Predicate filter = (Predicate) comboBox.getSelectedItem();
for(SelectableKey key : tableEntries){
key.setSelected(filter.evaluate(key));
}
}
});
I also have a few other controls I want to change based on the value. At the moment, only a few cells in the table change their state to be selected/deselected. Only when I click on the row, or select multiple rows, the UI updates itself. Is there a call from the handler I need to make to tell GUI to redraw itself? ALos, if I modify other controls than JTable, how would I tell them to change their state?
Thanks
When you update a value in your TableModel, the model should fire a corresponding TableModelEvent (type: UPDATE).
If your TableModel for example extends from AbstractTableModel, you can call the fireTableRowsUpdated method after you have made the changes.
Another approach is a TableModel which knows when it gets updated (for example by adding listeners to the objects it contains). This allows other code to simply update the objects contained in the TableModel, without having knowledge of the TableModel. The TableModel itself will then fire the event when it detects changes made to the objects it contains.
I prefer the second approach, as this avoids that I have to pass that TableModel around to all my other classes.
Consult the table tutorial for more information.
I'm trying to find a way to detect changes in which column the user selected in a JTable. I did some poking around and it appears that you need to somehow use a TableColumnModelListener in order to detect the changes, but that doesn't seem to fire an event when you change the column you have selected.
You need to add a ListSelectionListener instead. That will capture selection events. Here are some Swing tutorials that go further in depth:
http://download.oracle.com/javase/tutorial/uiswing/events/listselectionlistener.html
http://download.oracle.com/javase/tutorial/uiswing/components/table.html#selection
From what I read, I think you need to add a MouseListener to your table, which for example in mouseClicked will get the row and column using the following code, below:
table.addMouseListener(new MouseListener()
{
#Override
public void mouseClicked(MouseEvent e)
{
Point pnt = evt.getPoint();
int row = table.rowAtPoint(pnt);
int col = table.columnAtPoint(pnt);
}
}
It should work great for you I have used similar thing myself before.
BTW it look similar to the problem I found on coderanch, link:
http://www.coderanch.com/t/332737/GUI/java/detect-single-click-any-cell
Good luck, Boro
If by "change" you mean changing the value of a cell then you can use an AbstractTableModel and implement the fireTableCellUpdated method
JTextField has a keyTyped event but it seems that at the time it fires the contents of the cell have not yet changed.
Because of that .length() is always wrong if read here.
There must be a simple way of getting the length as it appears to the user after a key stroke?
This is probably not the optimal way (and it's been a while), but in the past, I have added a DocumentListener to the JTextField and on any of the events (insert, update, remove) I:
evt.getDocument().getLength()
Which returns the total length of text field's contents.
This may be related to this "bug" (or rather "feature")
The listeners are notified of the key events prior to processing them to
allow the listeners to "steal" the events by consuming them. This gives
compatibility with the older awt notion of consuming events.
The "typed"
event does not mean text was entered into the component. This is NOT a
bug, it is intended behavior.
A possible solution is to listen to an associated Document
// Listen for changes in the text
myTextField.getDocument().addDocumentListener(new DocumentListener() {
public void changedUpdate(DocumentEvent e) {
// text was changed
}
public void removeUpdate(DocumentEvent e) {
// text was deleted
}
public void insertUpdate(DocumentEvent e) {
// text was inserted
}
});
Note this works no matter how the text gets changed; via a clipboard cut/paste, progamatic "setText()" on the TextField, or the user typing into the field on the UI.
KeyEvents are low-level events that are not appropriate here [that sounds familiar].
How does the JTextField system know that a character has been typed? Through a key typed event (IIRC, done through the PL&F). Does the event get dispatched to the system listener before your listener? It might or might not do.
In this case, you probably want to go to the Document and add a higher-level listener. With Swing it's a good idea to go for the model early - the 'J' class interfaces are incoherent. If you are intercepting input data, then you probably want a custom model (or in the case of Document a DocumentFilter).
Use this code:
public void jTextField6KeyReleased(java.awt.event.KeyEvent evt)
{
System.out.println(jTextField6.getText().length());
}