4 Replies Latest reply: Jul 16, 2012 7:18 AM by 945083 RSS

    Using AbstractTableModel - problem when passing User Defined Tree Objects

    945083
      ***Same question also posted on code ranch***:

      http://www.coderanch.com/t/584706/GUI/java/AbstractTableModel-show-data-user-defined

      I seem to have offended some people by not linking both articles and so am including the link at the top of the post (I realised it was less visible at the bottom where it was previously) I also asked the mods on code ranch to remove my account from the site, however I can see the topic is still visible although my account is indeed gone. I hope that having just the one question will clear up any confusion and will avoid getting similar responses here

      Hi all, I have a problem when passing a user defined class to an extended AbstractTableModel

      I will ask up front for some patience as I am new to Java having done most of my (bad) coding in .NET :)

      Scenario: I have a form with a jTree, I make several calls to a database and I populate the jTree (lazily) with the returned objects, I pass these objects to different Classes (defined by me) to store the relevant information. When the use selects a Node in the jTree I would like to retrieve the user object and display its details in a jTable (in .NET I used the ListView and jTable seems to be the best thing in Java)

      I coded a new AbstractTableModel inside the main class and call it when the user selects a node, this code works fine and I can set column names and return tree node data, however this is within the main class.....so.....

      After doing some reading and looking at some examples I decided to create my own AbstractTableModel class for each of my own classes and then instantiate them on demand by passing the selected tree node to the relevant table model (sounds reasonable??)

      The problem is that for some reason my class object is not being passed correctly and I get a null exception, I have debugged and can see that the object I pass is the correct one but it never gets used in my table model

      My table model class is here:
      public class TableModelRNC extends AbstractTableModel  {
          
          private RNC myRNC;
          //RNC is one of my user defined classes contained in the jTree
             
          public TableModelRNC(RNC tmpRNC){
              
              //I should be passing my RNC object here, debugger shows that tmpRNC is in fact the object i pass from the jTree each time
              //tmpRNC has all the required information stored....
              //The problem is that the line below is never processed therefore myRNC never gets any data passed and the code fails
             
              //for some reason myRNC is always a null value
      
              myRNC = tmpRNC;
              
          }    
          
          //set the data to be passed to the columns
          Object columnData[][] = {{myRNC.rncID, myRNC.rncName, myRNC.rncOMSip}};
          //set the column names
          Object columnNames[] = {"RNC ID", "RNC Name", "OMS IP"};
         
          @Override
          public String getColumnName(int column) {
              return columnNames[column].toString();
          }
      
          @Override
          public int getRowCount() {
              return columnData.length;
          }
          
          @Override
          public int getColumnCount() {
              return columnNames.length;
          }
      
          @Override
          public Object getValueAt(int row, int col) {
              
              return columnData[row][col];
          }
      
          
          
      }
      And here is the code I use to pass the treenode to the AbstractTableModel:
      private void jTree1ValueChanged(javax.swing.event.TreeSelectionEvent evt) {                                    
      
              //we respond to mouse selection on the tree and set the selected treenode
              DefaultMutableTreeNode node = (DefaultMutableTreeNode) jTree1.getLastSelectedPathComponent();
              final Object nodeObject = node.getUserObject(); //get the user object associated with the treenode
      
              //now we see if the selected treenode is RNC/WBTS/WCEL etc, this part only sets the userobject so we can display details
              if (nodeObject instanceof RNC) {
                  //set it as final so we can pass it to the jtable
                  final RNC selectedRNC = (RNC) nodeObject;
                  TableModelRNC tablemodelRNC = new TableModelRNC(selectedRNC);
                  
                  //now we set the forms jtable to our created model
                  
                  jTable2.setModel(tablemodelRNC);
      I can't figure out where it goes wrong? I think my constructor is correct and I know I pass the correct user object from the tree

      Here is the code that works from inside the main class:
      private void jTree1ValueChanged(javax.swing.event.TreeSelectionEvent evt) {                                    
      
              //we respond to mouse selection on the tree and set the selected treenode
              DefaultMutableTreeNode node = (DefaultMutableTreeNode) jTree1.getLastSelectedPathComponent();
              final Object nodeObject = node.getUserObject(); //get the user object associated with the treenode
      
              //now we see if the selected treenode is RNC/WBTS/WCEL etc, this part only sets the userobject so we can display details
              if (nodeObject instanceof RNC) {
                  //set it as final so we can pass it to the jtable
                  final RNC selectedRNC = (RNC) nodeObject;
                  //TableModelRNC tablemodelRNC = new TableModelRNC(selectedRNC);
                  //setup a new table model to pass to the jtable on our form, abstract is used as it is flexible            
                  TableModel tablemodelRNC = new AbstractTableModel() {
      
                      //set the data to be passed to the columns
                      Object columnData[][] = {{selectedRNC.rncID, selectedRNC.rncName, selectedRNC.rncOMSip}};
                      //set the column names
                      Object columnNames[] = {"RNC ID", "RNC Name", "OMS IP"};
                      //below is required for the jtable to function
      
                      @Override
                      public String getColumnName(int column) {
                          return columnNames[column].toString();
                      }
      
                      @Override
                      public int getRowCount() {
                          return columnData.length;
                      }
      
                      @Override
                      public int getColumnCount() {
                          return columnNames.length;
                      }
      
                      @Override
                      public Object getValueAt(int row, int col) {
                          return columnData[row][col];
                      }
                  };
                  //now we set the forms jtable to our created model
                  
                  jTable2.setModel(tablemodelRNC);
      Can someone point me in the right direction? I have been searching and searching and I think I am doing things in the correct order but i'm stuck as to where I have gone wrong......apologies if this may have been answered somewhere on the forum - I did use the search button first and have read the examples present here and also the javadocs examples but they don't seem to work with my data model and or my coding

      Thanks in advance for any help with the issue; and also for any (helpful) advice on correct posting etiquette if there is something wrong with what I have included (or excluded for that matter)

      Edited by: Matt_C on Jun 26, 2012 4:46 AM
        • 1. Re: Using AbstractTableModel - problem when passing User Defined Tree Objects
          DarrylBurke
          Cross posted, and became sarcastic when Michael Dunn linked this cross post. Later, accused others of being sarcastic.

          http://www.coderanch.com/t/584706/GUI/java/AbstractTableModel-show-data-user-defined

          db
          • 2. Re: Using AbstractTableModel - problem when passing User Defined Tree Objects
            gimbal2
            Darryl Burke wrote:
            Cross posted, and became sarcastic when Michael Dunn linked this cross post. Later, accused others of being sarcastic.

            http://www.coderanch.com/t/584706/GUI/java/AbstractTableModel-show-data-user-defined

            db
            Yeah that isn't a productive way to deal with a thread. But I've seen worse.

            @OP: perhaps you're taking just a step too far. In stead of trying to hook up the JTree to the JTable directly, why don't you first try to create a small "prototype" with only a JTable and your own table model which you try to populate with some hardcoded dummy data? When you get that working you may try to extend it by filling the model based on a selection in a simple JTree, and from that you can make the jump to your real database driven stuff. Having the intermediate steps will give you something to play around with and reproduce the problem, plus the code will be easier to debug. Even if you can reproduce the problem but still can't figure it out, you'll have something runnable that you can post and others to take a look at. Right now all you present is a wall of text and some bits of code.

            Also you're aware of the Swing tutorial right?

            http://docs.oracle.com/javase/tutorial/uiswing/components/table.html
            • 3. Re: Using AbstractTableModel - problem when passing User Defined Tree Objects
              945083
              Hi Gimbal2, yep I went through the tutorial you linked and I have been through the steps you mention, I've looked at a lot of examples and think i'm doing the correct steps so I will try to lay them out below to make things clearer

              Step 1) In my main class on the (private void jTree1ValueChanged(javax.swing.event.TreeSelectionEvent evt) event I have instantiated a new abstracttablemodel that I pass some data to from my user defined treenode and this works fine - when called from within the main class in an event driven call; this is in the bottom posted code in the original post and this works fine for me

              Step 2) I hard coded into the TableModelRNC class some dummy data, and if I just instantiate this class from my main class then I can return dummy data to the jTable and this also works fine, however at this point I have not tried to pass any object to TableModelRNC, I just call it and get hard coded data back, this is also working for me (no constructor at this point in my table model class)

              So from Step 1) I figure I can pass data that belongs to my classes to the jTable via abstracttablemodel and have it displayed

              And from Step 2) I figure that if I create a custom abstracttablemodel in a separate class I can also call it and have it populate my jTable. My tree has many different objects that contain differing info so my plan is to do a custom abstract model for each

              I can get the info from the database no problem, creating the custom nodes in the tree also works fine and I can cast them and do other stuff. I use the ListView control in .NET and jTable seems to be the best solution in java as from what i've read theres not much you cant do with one when you understand how they work!!

              Step 3) Is where i'm stuck! I figure that in my TableModelRNC class I need to pass it an object containing the data I want, so in the main class i'm passing the treenode object to the new tablemodel class, and I can see when I debug that in fact the object I pass is the correct one and all my information is correct - however it never gets casted into the table model and I think this is my problem, I have put some more comments in below:
              public class TableModelRNC extends AbstractTableModel  {
                  
                  private RNC myRNC;
                  //RNC is one of my user defined classes contained in the jTree, I need to pass this object containing the info to my table model
                  //so I can display some of its details in the jTable
                     
                  public TableModelRNC(RNC tmpRNC){
                      
                      //Here is my constructor - and I think this is where it goes wrong
                      //So I should be passing my RNC object here, debugger shows that tmpRNC is in fact the object i pass from the jTree each time
                      //tmpRNC has all the required information stored in its user object
                      //The problem is that the line below is never processed therefore myRNC never gets any data passed and the code fails
                     
                      myRNC = tmpRNC;
              
                      //for some reason myRNC is always a null value
                      //I think here is where I need to cast tmpRNC into myRNC so I can then access the data the getColumnName etc etc        
                      
                  } 
              When hard coded with dummy data and without passing an object my class works fine, I think the problem is either within the constructor above or in how I pass the object from the main class. Apologies if this may be a bit of a long reply, and also thanks in advance for any advice people may give - it is greatly appreciated...
              • 4. Re: Using AbstractTableModel - problem when passing User Defined Tree Objects
                945083
                Okay - so I finally figure out what was going wrong. My constructor was in fact correct, this issue turned out to be in the method I was using to return my object data

                I found a nice example which eventually led me to my errors here:
                http://www.javareference.com/jrexamples/viewexample.jsp?id=17
                I had looked at many examples and tutorials for table models but I found the one above was the clearest (for my level of idiocy anyway :)

                My new abstract table class is now:
                import javax.swing.event.TableModelListener;
                import javax.swing.table.AbstractTableModel;
                
                /**
                 *
                 * @author id011593
                 */
                public class TableModelRNC extends AbstractTableModel  {
                    
                    //Column names are specified here
                    private String columnNames[] = {"RNC ID", "RNC Name", "OMS IP"};
                    //Pass some dummy data
                    private Object columnData[][] = {{"1", "TempName", "10.10.10.10"}};
                    //Declare the data object
                    private RNC myRNC;
                    
                    /*
                     * Constructor
                     * Pass the RNC object stored in the treeview to the table model
                     */
                    public TableModelRNC(RNC tmpRNC){
                        
                        //Assign the data from the tree object to our data object
                        myRNC = tmpRNC;   
                   
                    }   
                    
                    /*
                     * Provide methods for the table to work properly
                     */
                    
                    //Return the column names
                    @Override
                    public String getColumnName(int column) {
                        return columnNames[column].toString();
                    }
                
                    //Return the overall length of the data used
                    @Override
                    public int getRowCount() {
                        return columnData.length;
                    }
                    
                    //Return the number of columns
                    @Override
                    public int getColumnCount() {
                        return columnNames.length;
                    }
                
                    /*
                     * Return the data depending on the data stored in the table model and update the jTable
                     * I fill the columns by their number and then assign the data I want to the column I want
                     */
                    @Override
                    public Object getValueAt(int row, int col) {
                              
                        RNC rncData = myRNC;
                
                        switch (col) {
                            case 0:
                                return rncData.rncID;
                            case 1:
                                return rncData.rncName;
                            case 2:
                                return rncData.rncOMSip;
                        }
                
                        return new String();
                    }
                
                    /*
                     * Below are other methods that are not (yet) used in this implementation of the abstract table
                     */
                    
                //    @Override
                //    public Class<?> getColumnClass(int columnIndex) {
                //        throw new UnsupportedOperationException("Not supported yet.");
                //    }
                //
                //    @Override
                //    public boolean isCellEditable(int rowIndex, int columnIndex) {
                //        throw new UnsupportedOperationException("Not supported yet.");
                //    }
                //
                //    @Override
                //    public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
                //        throw new UnsupportedOperationException("Not supported yet.");
                //    }
                //
                //    @Override
                //    public void addTableModelListener(TableModelListener l) {
                //        throw new UnsupportedOperationException("Not supported yet.");        
                //    }
                //
                //    @Override
                //    public void removeTableModelListener(TableModelListener l) {
                //        throw new UnsupportedOperationException("Not supported yet.");
                //    }
                
                    
                }
                 
                Thanks to all who replied and gave me some useful pointers, and also to those who just had a look to see if they could help

                BTW - if anyone on here is also active on Code Ranch would they do me a big favour and post a link back to this thread and mark the one on Code Ranch as solved? I am no longer a member on Code Ranch and would appreciate if someone could also close that question down to avoid any issues with cross posting, I think some of the mods here are also mods on Code Ranch??

                Any comments or feedback on my implementation would be welcome, as I said I'm new to Java and making things work doesn't mean they work properly!