Detecting Selection Changes in a JTable - java

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

Related

JXTreeTable - Weird cell rendering issue for certain Look and Feels

So here's my problem. I have developed a plugin for intellij which contains a tool window, and a part of it contains a tabbed pane with a JXTreeTable like this
Looks great and works as expected until I start clicking on the rows. I'll explain the issue through screenshots.
Row selected
Move mouse pointer to next row
Select Next row
Repeat above procedure for the next couple of rows and I end with this!
urghh..puke
Now If I move my mouse pointer back up those again, The colors come back like magic!
Continue moving mouse back up along the rows..
Also at any point if my mouse pointer leaves the column..The view is back to normal again (except for the selected row of course)
My Look and Feel is IntelliJ Dark Look and Feel - com.intellij.ide.ui.laf.IntelliJLaf , which I found out using System.out.println(UIManager.getLookAndFeel())
If I change my look and feel programmatically to something else, This issue disappears. But i'm not in a position to alter the default look and feel so I have to fix this issue (or bug?).
I've used a hack to apply a different look and feel just for my JXTreeTable view component, and it worked great until.. I open another project on a new window (this creates a new instance of my tool window for the new project) and the hack this time around works against me, setting the look and feel properly for the new project instance, but resetting the look and feel back to default for my first project instance
Oh and i'm using the DefaultTreeCellRenderer for my treetable.
EDIT: I implemented a custom cell renderer for the treetable, setting it to transparent when not selected (like MadProgrammer suggested), but the issue is still there.
public class CustomCellRenderer extends JLabel
implements TreeCellRenderer {
#Override
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
if (selected){
setBackground(Color.BLUE);
setForeground(Color.WHITE);
}else{
setForeground(Color.BLACK);
setBackground(Color.WHITE);
setOpaque(false);
}
setText(value != null ? value.toString() : "<null>");
return this;
}
}
There is a slight change in the results now. lol
Compare with 4. above
EDIT 02:
So I decided to completely disable cell selection for my treetable using treeTable.setFocusable(false). Well guess what? Now when I click on a row nothing happens. No cell selections or colour changes. But once I move my mouse pointer to the next row as shown above (step 2), yup same story over again. Looks like it's related to a mouse listener somewhere? idk.. This is driving me nuts. Some help would be highly appreciated!
EDIT 03:
This seems to be the LAF that's giving me trouble
com.intellij.ide.ui.laf.darcula.DarculaLaf
source: https://github.com/JetBrains/intellij-community/blob/master/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/DarculaLaf.java
EDIT 04
So I gave up SwingX and tried to implement a JTreeTable component from scratch, to see if this would fix the issue. I managed to put together an implementation using online source code. The results are interesting.
As you can see the issue is still there but unlike before, it does not propagate from cell to cell. So basically, it only shows on the current selected cell.
Anyway, the implementation I used, contains a MyTreeTable class which extends a JTreeTable class. The complete source code can be found here
If I instantiate JTreeTable instead of MyTreeTable the cell rendering issue disappears, but so does the collapse/expand feature of the JTreeTable. It basically turns into a flat tree. (useless!) So whatever that's causing the issue,
Is in the MyTreeTable class
Provides the collapse/expand behavior
to the tree component
after a bit of debugging I narrowed it down to the following method. If I remove this method from the MyTreeTable class, I can't expand/collapse the treetable, once it's included the cell rendering issue comes back.
public boolean editCellAt(int row, int column, EventObject e){
if(e instanceof MouseEvent){
MouseEvent me = (MouseEvent)e;
// If the modifiers are not 0 (or the left mouse button),
// tree may try and toggle the selection, and table
// will then try and toggle, resulting in the
// selection remaining the same. To avoid this, we
// only dispatch when the modifiers are 0 (or the left mouse
// button).
if(me.getModifiers()==0 ||
me.getModifiers()==InputEvent.BUTTON1_MASK){
for(int counter = getColumnCount()-1; counter>= 0;
counter--){
if(getColumnClass(counter)== TreeTableModel.class){
MouseEvent newME = new MouseEvent
(tree, me.getID(),
me.getWhen(), me.getModifiers(),
me.getX()-getCellRect(0, counter, true).x,
me.getY(), me.getClickCount(),
me.isPopupTrigger());
tree.dispatchEvent(newME);
break;
}
}
}
return false;
}
return super.editCellAt(row, column, e);
}
Anyway, this looks like a bug from the intellij side because it's look and feel specific and exists to some degree in both SwingX and a standard library JTreeTable implementation. So maybe i'm approaching this totally wrong. But still if there is a possible fix, please share your ideas. I need this issue sorted out. thanks

Java/JDBC - Using TableModels to display individual data

My hobby-level programing won't let me extend my program the way I want to, and my books/google won't help me out too much, hopefully you guys can!
I'm writing a simple database viewing program using the 'ResultSetTableModel' to import data from my local mySQL database.
The current program displays the entries in a nice list, and all of the data contained in each entry is presented as an individual cell in the JTable.
However, I now want to implement a feature to the JTable rows, that 'on click' displays the content (in my case an image using an image path)
However, after trying endlessly I cannot seem to find an easy and short way to add an eventhandler that does this for me.
I've managed to do similar things with manually populated tables before, but when trying to apply the lessons learned there to this new project gets me nowhere.
You can simply add a ListSelectionListener to the the table selectionmodel:
table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
#Override
public void valueChanged(ListSelectionEvent e) {
// Last selected row:
table.getSelectedRow(); // -1 if no row selected
// All selected rows:
table.getSelectedRows();
}
});
Have you tried adding a MouseListener (or MouseAdapter) to the the table - e.g.
table.addMouseListener(new MouseAdapter(){
#Override
public void mouseClicked(MouseEvent e){
// do something cool...
}
}

How to refresh JTable with vectors

I have been stumped with this for quite some time now. I understand you use the table model to refresh the actual table with the new values however I cannot seem to get this to work. I have added a tablemodellistener to my form and have a tableChanged method. However, I cannot seem to figure out why the tableChanged method isn't getting called when I insert into a the table.
public void tableChanged(TableModelEvent e) {
int row = e.getFirstRow();
int column = e.getColumn();
DefaultTableModel model = (DefaultTableModel)e.getSource();
// String columnName = model.getColumnName(column);
//Object data_1 = model.getValueAt(row, column);
//model.fireTableCellUpdated(row, column);
//model.fireTableDataChanged();
//customerTable.repaint();
}
Could I completely rebuild the table if I click the refresh button on my form? Would that at all be possible? If not, do I have to call my tableChanged method from my refresh button's action performed method in order for it to trigger? I've been stuck on this for quite some time now and I would just like to get this figured out for the benefit of learning.
If you have the option and it fits your needs, I'd reccomend taking a look at GlazedLists. Then you won't have to worry about updating your table models--it's all handled for you.
Here's a jump to a relevant part of the GlazedLists tutorial.
I believe you need to manually add your Table as Listener of table TableModel.

Whats the proper event for changes in any cell of JTable?

I have a simple JTable, there are two columns that matter: quantity and value (Integers). Each time user enters a new row or updates one, each rows value must be multiplied by quantity, results sumed together and the result sum displayed in a JLabel outside the JTable. Looks pretty simple. Except that I have no idea what event should I look for. Something like "cell value changed"? When I right click on the JTable in NetBeans I see no such event or dont recognize it ;) Anyway, before I come up with some weird noobish solution I thought I might ask here what's the proper way to do it :)
you should add a TableModelListener as described here.
also, in your listener once you've updated the value of the other cell values programatically you will need to call model.fireTableCellUpdated to let swing know about the changes
Finally I managed to find how to do it in NetBeans with all the code protection, et cetera. It's right click on JTable in Design View, Properties, then Code tab, and then add your code in Pre-Adding Code section (code evaluated before table is added to container or something like that).
The exact code which works for me is this:
table.getModel().addTableModelListener(
new TableModelListener()
{
public void tableChanged(TableModelEvent evt)
{
// here goes your code "on cell update"
}
});
I am aware that Tom, above, suggested never calling getModel() but I'm too new to Java to understand why (care to explain, please..?) :) and it's just an example anyway, I'm adding this answer just to show how to do it in NetBeans (thanks pstanton for answering what to do). Because I found so many people asking this in internet and no real answers (apart from "copy your protected code out of NetBeans protected area and then customize your table).

JTable selection change event handling: find the source table dynamically

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.

Categories

Resources