Cast Object to JTable? - java

I am trying to implement a ListSelectionListener for some of my JTables. Simply (at the moment) the ListSelectionListener is supposed to simply return the text of the cell that was selected.
My program design has several JTables and I would like to have one ListSelectionListener work for them all. In the valueChanged event of the ListSelectionListener I thought it was possible to do something like:
private class SelectionHandler implements ListSelectionListener {
public void valueChanged(ListSelectionEvent e)
{
JTable table = (JTable)e.getSource();
String data = (String) table.getValueAt(table.getSelectedRow(), 0);
// Print data
}
}
Behind the scenes I have used the following code to get the SelectionHandler working with the table in question:
fbTable.setCellSelectionEnabled(true);
ListSelectionModel cellSM = fbTable.getSelectionModel();
cellSM.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
cellSelectionModel.addListSelectionListener(selectionHandler);
When I run the program I get a ClassCastException error:
Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: javax.swing.DefaultListSelectionModel cannot be cast to javax.swing.JTable
at cardboardfantasy.CardboardFantasyView$SelectionHandler.valueChanged(CardboardFantasyView.java:360)
// This is the line in question: JTable table = (JTable)e.getSource();
Is there a way to do something like this? One solution I thought of was to compare the source of the event (e.getSource()) to all my JTables to see if they were equivalent (big if block) and then just calling .getValueAt inside that block but that would making the code in the future difficult if tables were to be added or removed.

Either debug your code in your IDE, set a breakpoint and see what the type of e.getTarget() is:
Object source = e.getSource();
JTable table = (JTable)source; // breakpoint on this line and inspect the variable 'source'
String data = (String) table.getValueAt(table.getSelectedRow(), 0);
Or if debugging is not possible for whatever reason do this:
Object source = e.getSource();
System.out.println(source.getClass());
But: debugging using System.out.println is evil. your debugger is your friend.

As the error implies, the source object in question is a DefaultListSelectionModel not a JTable. This makes sense since the source of the event (that is, the object which fired the event) was the selection model object, not the table. Also, models in themselves make no assumptions about what type of object is using them as a model so there is no way to get a reference to the table via the selection model.

Pass the JTable instance to your selection handler. As long as the handler listens on one table, you'll be able to use that instance instead of relying on the information from the event.

I think there are two main solutions:
Use a JList and register the listener not with model but directly with the list. Then, if the list is contained by a table you could just ask for the list's (Component) parent to find the responsible table
Override DefaultListSelectionModel to (for example) take an additional argument in the constructor, which would be a JTable instance (every table will need a new instance of that model). You would save that instance in an instance variable and could then operate directly on the table when an event occurrs
I do not think that either of these solutions is ideal. I have the feeling that you could make your life easier by using some pattern or idiom to get around having to know which table the source was. But to give you any clues there we'd have to see a lot more of your code.

Related

how to make a JTextArea have clickable buttons

As the title says I'm trying to make it so my JTextArea have some strings so that I can call other functions, like a hyperlink of sorts, can that be done?
For reference, I would like to know how the left side of any Tutorialspoint tutorial is made but in Java.
PS: I'm using a CardLayout.
EDIT: Something like this
Forget about using a JTextArea. Take a look at JList instead. This is Swing's basic list class. It supports the selection of one or more items from a list. Although often the list consists of strings, it is possible to create a list of just about any object that can be displayed.
Although a JList will work properly by itself, most of the time you will wrap a JList inside a JScrollPane, so long lists will automatically be scrollable.
A JList generates a ListSelectionEvent when the user makes or changes a selection. This event is also generated when the user deselects a n item. It is handled by implementing ListSelectionListener. This listener specifies only one method, which is called:
void valueChanged(ListSelectionEvent le)
Here, le is a reference to the object that generated the event. Although ListSelectionEvent does provide some methods of its own, often you will interrogate the JList object itself to determine what has occurred.
By default, a JList allows the user to select multiple ranges of items within the list, but you can change this behavior by calling setSelectionMode(int), which is defined by JList. The integer passed to this method must be one of the values defined by the ListSelectionModel interface:
SINGLE_SELECTION
SINGLE_INTERVAL_SELECTION
MULTIPLE_INTERVAL_SELECTION
You can obtain the selected values by calling getSelectedValuesList(), or, if you are using single selection, you can call getSelectedValue(). Once you have the selected the value(s), you can invoke the method(s) dedicated to that/those objects accordingly.
One last tip: In Java, they are called methods, not functions ;)
Happy programming!

Handling button event in main class

I'm new to Java and programming. I want to generate an int in a JDialog class by selecting a row in a table and send that int to the main class which created it, or, to handle the button action performed in the main class. Main class creates the subclass here:
private void launchtable() {
DlgBeds dcl = new DlgBeds();
dcl.setLocationRelativeTo(this);
dcl.setVisible(true);
// I want in this place to put something like this:
txtCode.setText(subclassgeneratedint );
}
But first I need to get that int from the subclass., I tried creating a method there that I can use in main to return the int, but it instead sets the text with the first row selected (the default selection), and it can't return more row selections to keep changing txtCode; the method like just dies there.
The main could also have an action performed for the button in the subclass but the parameter would need to be one from the subclass I guess.
protected void actionPerformed[button in the subclass](ActionEvent e) {
//actions
}
I'm really lost, I know I need to study more to solve situations like this but I needed the answer as fast as possible.
Add a ListSelectionListener to your table. You can get the selected row as shown here and pass it to your main window using a PropertyChangeListener as shown here and here.

swing tableChanged() not responding to table changes

I'm coding in Swing in Java. I'm using the Netbeans layout manager. I'm having trouble with a jTable. I've applied a customer model to it which extends AbstractTableModel. I want the third column to contain boolean values in the form of checkboxes (this I have done successfully). The dialog I have the jTable in implements TableModelListener. My tableChanged() method has only the following code: System.out.println("Table changed!");
However, whenever I try to check one of the checkboxes, it does the little "suppression" thing when I click and hold, then when I release, it doesn't change the checkbox's state. It also does not print out "The table has changed!" This has been driving me crazy. I've read all about it, but can't figure out why mine's not working. Please help. Here's the relevant code:
In jDialog constructor:
this.chapterTableModel = new ChapterTableModel(chapterList);
chapterTableModel.addTableModelListener(this);
And then a method which does this: chapterTable.setModel(chapterTableModel);
Then below my constructor, I have this method:
#Override
public void tableChanged(TableModelEvent tme) {
System.out.println("Table Changed!");
}
The entire code can be found here: http://collabedit.com/ttcds
and here: http://collabedit.com/qn3kx
Thanks for your help in advance!
Are you calling one of the fire-methods of the parent AbstractTableModel class in the mutators of ChapterTableModel?
You are not overriding setValueAt anywhere so the value in your table isn't being changed.

Java Swing Threading Problem

so here's the problem. I have a JDialog box that consists of 3 combo boxes, a text field, a few buttons and a JTable. The JTable information is filtered based on the text field and combo boxes, so for instance it starts with all of the data and gets shrunk down to only the data that starts with any string value the user decides.
What's happening though is that while the values filter correctly, if I click in the JTable (in the white space, where there are no rows) then the rows that were deleted show up, like they were invisible until I clicked on them. I've tried almost everything:
I've tried re-creating the table every time filter is clicked (bad hack that didn't even work), I've called all of the repaint, revalidate, firechanged methods, I rewrote the dialog from scratch to make sure I didn't do any stupid mistakes (if I made one I didn't find it at least), and I've tried putting them on separate threads. The only fix I haven't tried is using a swing worker, but that's because my filtering was a little too complicated for me to figure out what goes where and how to extend the swing worker correctly. The GUI is generated by netbeans (bleh), and has worked in my other dozen or so JDialogs just fine (perfectly in fact). Here's the method that doest the filtering, if any of you can help it would be greatly appreciated.
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
nameFilter = "task1";
javax.swing.table.DefaultTableModel dm = (javax.swing.table.DefaultTableModel)jTable1.getModel();
tempParameters = parameters;
String currentString;
int rowNumber = 0;
while (dm.getRowCount()>rowNumber){
currentString = (String)(jTable1.getValueAt(rowNumber,1));
if(!nameFilter.equalsIgnoreCase(currentString.substring(0,nameFilter.length()))){
dm.removeRow(rowNumber);
parameters--;
}
else rowNumber++;
}
parameters = numOfRows;
}
Update, I also implemented the filter from the comment below, and while it filtered out the correct data, it had the exact same problem. In the future I will probably use this filter feature though, so thanks.
Another update, the code is still failing even after removing everything but this chunk, and all (at least I believe..) I am doing here is doing a simple remove row call. Hope this helps a bit.
Have you tried creating a new Model every time you want to filter, instead of clearing it by deleting rows? Create new model, copy relevant rows to new Model, set new Model in table. Really shouldn't be necessary, but it might be a quick fix.
Also, I really have to wonder why you're calling toLowerCase on two strings when you're using equalsIgnoreCase to compare them.
So long as this method is called from the EDT I don't think there would be a threading problem. Try using
SwingUtilties.isEventDispatchThread()
to make sure.
If you look at the API for DefaultTableModel, updates are being sent to your JTable which will repaint itself, so I don't think that is the problem.
I would guess that it is a logic problem. If you can extract the logic into separate methods it will be easier to test and verify whether it is updating the model as you expect.
Couple of observations:
If the filter happens to be larger than the string content of the row, it'll throw in the substring call
Calling the dm.removerow is generating a bunch of tablerowsdeleted events.
You're asking for a rowcount from the model, yet are getting the value through the table (a little inconsistent, if the model gets wrapped around another model you might be acting upon different rows), so instead of jtable1.getvalueat, use the dm.getvalueat.
I think what might be happening is that as the events get fired I see there are repaint and revalidate events fired in the JTable, these can be trampling over each other as they get enqueued in the EDT.
What I would suggest is to create a new datamodel, add the rows that you want to keep, and then reassign it to your jTable1.setModel(newDm);
Also to watch for is if someone else is modifying the model while you're in your eventlistener.
Hope this helps

JTree refreshing after setting new jtree model

I'm trying to use dynamically JTree component.
Under root node I have four nodes and one of them ("Operations") can have 0 to many children. This is set by user via editable list in separate window opened on users request. After editing this list user hits button 'Save' and then magic should happen. Edited list is sent to server(on the same machine actually, so it doesn't take to long), the window with list is closed but right before that the main window (with jtree) is told to refresh itself, and I can see that it does what is told in log output, but the changes don't show on the screen.
I am using DefaultTreeModel, this method is called to create model at the beginning(when first opening the window) and after the change to update the new model with new structure.
with dmtn.getLeafCount() I can see that newly downloaded structure from server is the right one with the changed number of leaves under 'Operations'
public DefaultTreeModel getDataStructure() {
int dataID = task.getData().getId();
LoggerUtility.logger.info("Data ID: " + dataID);
DefaultMutableTreeNode dmtn = Manager.manager.getDataStructure(task.getId());
LoggerUtility.logger.info("DTMN created "+dmtn.getLeafCount());
return new DefaultTreeModel(dmtn);
}
the method used to refresh the jtree looks like this (it's very messy):
public void updateTree(){
taskDataTree.setModel(getDataStructure());
((DefaultTreeModel)taskDataTree.getModel()).reload();
this.revalidate();
this.repaint();
taskDataTree.revalidate();
taskDataTree.repaint();
taskDataTree.updateUI();
taskDataTree.setVisible(false);
taskDataTree.setVisible(true);
jScrollPane2.setViewportView(taskDataTree);
}
It's very messy because I have tried to put in there every possible solution to my problem that I have found on forums,
I also tried with my own treemodel implementation which would call fireTreeStructureChanged(...) but it also didn't change.
I should probably also add that I'm using Netbeans GUI Builder to build my gui although I don't know if it has anything to do with that.
I would be very grateful for any help with that
BR
Lucja
EDIT!!!
I also tried puting it in another thread like that:
public void updateTree() {
SwingWorker sw = new SwingWorker() {
#Override
protected Object doInBackground() throws Exception {
taskDataTree.setModel(getDataStructure());
((DefaultTreeModel) taskDataTree.getModel()).reload();
taskDataTree.revalidate();
taskDataTree.repaint();
taskDataTree.updateUI();
taskDataTree.setVisible(false);
taskDataTree.setVisible(true);
jScrollPane2.setViewportView(taskDataTree);
return null;
}
};
sw.execute();
}
but it also didn't help.
tree.setModel( anotherModel );
Is the only line of code that you need.
If it doesn't work then it means that the tree variable does not contain a reference to the tree that was added to the GUI. Maybe you have a class variable and a local variable of the same name.
From my point of view the own TreeModel implementation was a good approach. But I know that creating an TreeModelEvent with the correct data isn't that simple.
I would suggest to update your question with your TreeModel implementation so that we can find the problem with it.
In principle it should work this way (when you set a new Model, the tree reloads itself). (This is not the most efficient way, better let the model send appropriate events when it changes.)
If this does not work, make sure you are calling the setModel method in the AWT Event Dispatch Thread (with EventQueue.invokeLater (or SwingUtilities.invokeLater, which is the same), for example. I think you should not need all your revalidate(), repaint() etc. calls (and updateUI should only be done if you changed the look-and-feel configuration).

Categories