Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / May 2006

Tip: Looking for answers? Try searching our database.

TableSorter class question

Thread view: 
IchBin - 14 May 2006 19:16 GMT
To use the TableSorter class from Sun, referenced in the JTable tutorial
http://java.sun.com/docs/books/tutorial/uiswing/components/table.html. I
have to create a MyTableModel that houses and manipulates the Table
data. The code they have can not really work in a real world
application. That is, hard coded model data and columns. This is not
practical. What I have done, is working as designed. (Attached below)

The pattern that Sun uses for the TableSorter and MyTableModel classes
is the decorator pattern. I have to fold MyTableModel into the
TableSorter class and then set the TableSorter as the JTable model. Code
wise it is done this this way:

    TableSorter sorter = new TableSorter(new MyTableModel());
    JTable table = new JTable(sorter);
    sorter.setTableHeader(table.getTableHeader());

So in TableSorter there is a constructor defined to house the passed
MyTableModel:

  public TableSorter(TableModel tableModel) {
        this();
        setTableModel(tableModel);
  }

OK, MyTableModel works as designed. I have no problem at all with
loading data, Sorting..etc. All works the way it should. The problem I
am having is that when I have to reference the MyTableModel thru the
JTable owner I am not seeing it. Say I have to get the
table.getRowCount(), table.getColumnModel(), table.getColumnCount() or
attached any renders. And if I do table.getModel() I am not getting the
MyTableModel that has the data. The TableSorter HAS the reference to
MyTableModel else no sorting would work but it does.

Hope my question is understandable. It's like I can not reference the
MyTableModel that is in TableSorter set as the model for the JTable
owner..  MyTableModel and TableSorter both extend AbstractTableModel.

public class MyTableModel extends AbstractTableModel
{
    /**
     * Debugging switch for problem determination
     */
    private boolean    DEBUG = false;
    /**
     * Define as string Object and not Vector to maintain Columns
     */
      private String[]   columnNames;
//    private String[] columnNames = {"Index","Entry
Name","URL","Results","Coment"};
    /**
     * Define as new with one element to eliminate error
     * on intial reference from TableSorter
     */
    private Object[][] data = new Object[0][0];

    /**
     * Default Class constructor on intial refference from TableSorter
     */
    public JBookMarksTableModel() {
    }

    /**
     * Added a constructor to load in data column names.
     *
     * @param data         row data to add to row model
     * @param columnNames  columms with colummns names to add to model
     */
    protected JBookMarksTableModel(Object[][] data, String[] columnNames) {
        //
        // Copy all Columns data to instance Columns
        addColumn(columnNames);
        //
        // Redefine the instance row size
        this.data        = new Object[data.length][data[0].length];
        //
        // Copy all row data to instance row data
        copyObjects(data, this.data);
    }
    /**
     * Added a constructor to load in data column names.
     *
     * @param data         row data to add to row model
     * @param columnNames  columms with colummns names to add to model
     */
    protected void addDataObject(Object[][] data) {
        //
        // Redefine the instance row size
        this.data        = new Object[data.length][data[0].length];
        //
        // Copy all row data to instance row data
        copyObjects(data, this.data);
    }
    /**
     * Delete all data.
     */
    protected void deleteDataObject() {
        //
        // Redefine the instance row size to zero
        this.data        = new Object[0][0];
     }
    /**
     * Non-Standard Added this method to return the all the Models data
     *  @return data[][]
     */
    protected Object[][] getTableData(){
        return data;
    }
    /**
     * @see javax.swing.table.TableModel#getColumnCount()
     */
    public int getColumnCount() {
        return columnNames.length;
    }
    /**
     * @see javax.swing.table.TableModel#getRowCount()
     */
    public int getRowCount() {
        return data.length;
    }
    /**
     *  Added Method to add Columns[]. There is no equivwent method
     *  in Sun's table models.
     *  It overrides addColumn(String columnName)
     *  (Mine only works for seq column adds)
     *
     * @param columnNames All Table Column names
     */
    protected void addColumn(String[] columnNames) {
        //
        // Copy all Columns data to instance Columns
        this.columnNames = new String[columnNames.length];
        this.columnNames = columnNames;
    }
    /**
     *  I added Method to add Columns
     *  DefaultTableModel uses a addColumn(int column, String[] column)
     *  (Mine only works for seq column adds)
     *
     * @param columnName Column name
     */
    protected void addColumn(String columnName) {

        if (columnNames == null)  {
            //
            // First time
            this.columnNames = new String[1];
            this.columnNames[0] = columnName;
        } else {

            // Create temp Object to hold current columns data plus one new
            // empty element
            Object temp[] = new Object[columnNames.length + 1];

            //
            // Copy all current Column data to temp
            System.arraycopy(columnNames, 0, temp, 0, columnNames.length);

            //
            // Added the new column name to the temp Object
            temp[temp.length - 1] = columnName;

            //
            // Rebuild the Instance Column object with all of the new data
            this.columnNames = new String[temp.length];
            System.arraycopy(temp, 0, columnNames, 0, columnNames.length);
        }
    }

    /**
     * Overrides javax.swing.table.AbstractTableModel.getColumnName(int)
     * @see javax.swing.table.AbstractTableModel#getColumnName(int)
     */
    public String getColumnName(int col) {
        return columnNames[col];
    }

    /**
     * @see javax.swing.table.TableModel#getValueAt(int, int)
     */
    public Object getValueAt(int row, int col) {
        return data[row][col];
    }

    /**
     * JTable uses this method to determine the default renderer/
editor for
     * each cell. If we didn't implement this method, then the last
column would
     * contain text ("true"/"false"), rather than a check box.
     *
     * @see javax.swing.table.AbstractTableModel#getColumnClass(int)
     */
    public Class getColumnClass(int c) {

        Class value = null;
        try  {
            value = getValueAt(0, c).getClass();
        } catch (Exception e) {
            // TODO: handle exception
        }
        return  value;
    }

    /**
     * Don't need to implement this method unless your table's editable.
     *
     * @see javax.swing.table.AbstractTableModel#isCellEditable(int, int)
     */
    public boolean isCellEditable(int row, int col) {
        // Note that the data/cell address is constant,
        // no matter where the cell appears onscreen.
        if (col < 2) {
            return false;
        }
        return true;
    }

    /**
     * Don't need to implement this method unless your table's data can
change.
     * Overrides javax.swing.table.AbstractTableModel.setValueAt(Object
value, int row, int col)
     * @see
javax.swing.table.AbstractTableModel#setValueAt(java.lang.Object, int, int)
     */
    public void setValueAt(Object value, int row, int col) {

        if (DEBUG){
            out.println("Setting value at " + row + "," + col + " to "
                    + value + " (an instance of " + value.getClass() +
")");
        }
        data[row][col] = value;
        fireTableCellUpdated(row, col);

        if (DEBUG) printDebugData(this.data);
    }

    /**
     * I added Methods to add row data conforms to DefaultTableModel.
     * DefaultTableModel uses a addRow(int row, Object[] data)
     * (I only append the row data)
     *
     * @param data  a one dimension row element
     */
    protected void addRow(Object[] data) {

        if (this.data == null) {
            this.data = new Object[1][data.length];
            //
            // loop and add the new first data row elements
            for (int j = 0; j < data.length; j++) {
                this.data[0][j] = data[j];
            }
        } else {
            //
            // Create temp Object to hold current columns data plus one new
            // empty element
            Object temp[][] = new Object[this.data.length +
1][data.length];

            //
            // Copy all current Column data to temp
            copyObjects(this.data, temp);

            //
            // Add the new column data elements
            for (int outer = 0; outer < data.length; outer++){
                temp[temp.length - 1][outer] = data[outer];
            }
            //
            // Rebuild the Instance data object with all of the new data
            this.data = new Object[temp.length][data.length];
            copyObjects(temp, this.data);

            //
            // Display the data if un debug mode
            if (DEBUG) printDebugData(this.data);

            //
            // Update the JTable display with new data
            fireTableDataChanged();
        }
    }

    /**
     * I added this Method as a helper to manage the data[][] expansion
     *
     * @param fromdata    the data[]][] object to copy from
     * @param todata      the data[]][] object build target
     *
     * @return Object[][] return the build data[][] object
     */
    protected Object[][] copyObjects(Object[][] fromdata, Object[][]
todata) {

        for (int outer = 0; outer < fromdata.length; outer++) {
            for (int inner = 0; inner < fromdata[outer].length; inner++){
                todata[outer][inner] = fromdata[outer][inner];
            }
        }
        return todata;
    }

    private void printDebugData(Object[][] data) {

        int numRows = data.length;
        int numCols = data[0].length;

        out.println();

        for (int i = 0; i < numRows; i++) {
            out.print("    row " + i + ":");
            for (int j = 0; j < numCols; j++) {
                out.print("  " + data[i][j]);
            }
            out.println();
        }
    }
 }

Signature

Thanks in Advance...
IchBin, Pocono Lake, Pa, USA
http://weconsultants.servebeer.com/JHackerAppManager
__________________________________________________________________________

'If there is one, Knowledge is the "Fountain of Youth"'
-William E. Taylor,  Regular Guy (1952-)

Carsten Hammer - 14 May 2006 20:38 GMT
The TableSorter class from Sun is indeed incomplete for real world
problems.

One example to map back to the original tablemodel is used in the
SelectedPages plugin of http://www.lowagie.com/iText/itext.jnlp.
There you can open a pdf file. A JTable showing the content (pages) of
the pdf file comes up and you can sort the pages according to the width
or height and independent of the shown order the selected pages are
computed right.

To find out what tablerows in the original tablemodel are selected this
method is used(PageSelectionTableDialog.java, look in
http://itext.cvs.sourceforge.net/itext/src/com/lowagie/tools/arguments/):

    TableSorter mysorter = (TableSorter) jTable1.getModel();
    int[] values = jTable1.getSelectedRows();
    int max = jTable1.getSelectedRowCount();
    int[] swappedvalues = new int[max];

    if (jToggleButton1.getModel().isSelected()) {
      for (int i = 0; i < max; i+=2) {
        int second=(i+1)<max?i+1:i;
        swappedvalues[i] = mysorter.getModelrow(values[second]) + 1;
        swappedvalues[second] = mysorter.getModelrow(values[i]) + 1;
      }
    }
    else {
      for (int i = 0; i < max; i++) {
        swappedvalues[i] = mysorter.getModelrow(values[i]) + 1;
      }

    }
  }

Therefore it uses a slightly changed TableSorter class.
Best regards,
Carsten

IchBin schrieb:
> To use the TableSorter class from Sun, referenced in the JTable tutorial
> http://java.sun.com/docs/books/tutorial/uiswing/components/table.html. I
[quoted text clipped - 316 lines]
>     }
>  }
IchBin - 15 May 2006 19:21 GMT
> The TableSorter class from Sun is indeed incomplete for real world
> problems.
[quoted text clipped - 29 lines]
>     }
>   }

[snip code]

Thanks Carsten for your response. I am looking at the code you mentioned.

I am still having a problem with it. It is something stupid sitting
right in front of me. I am using seven JTables that are each embedded
into an instance TableSorter. What I wanted to do is only cosmetic after
all of the JTables have been loaded. That is, correct the widths of all
the columns size to the largest data element in that column. I have code
that does that and I know it works. Just need to get it working with the
seven JTables in this app.

Also, if any one wants to use the MyTableModel.java with Sun's
TableSorter.java(I posted in the first msg of this thread). You need to
do the following as I mentioned before:

    TableSorter sorter = new TableSorter(new MyTableModel());
    JTable table = new JTable(sorter);
    sorter.setTableHeader(table.getTableHeader());

But also add this line of code after the above code:
//
// Need to force the sorting status so that the column values will be
// repainted correctly (0 = sortAsending)
jBookMarksTableSorter.setSortingStatus(firstColumn,0);

Thanks in Advance...
IchBin, Pocono Lake, Pa, USA
http://weconsultants.servebeer.com/JHackerAppManager
__________________________________________________________________________

'If there is one, Knowledge is the "Fountain of Youth"'
-William E. Taylor,  Regular Guy (1952-)
IchBin - 15 May 2006 19:30 GMT
> The TableSorter class from Sun is indeed incomplete for real world
> problems.
[quoted text clipped - 51 lines]
>>     JTable table = new JTable(sorter);
>>     sorter.setTableHeader(table.getTableHeader());

[snip code]

Thanks Carsten for your response. I am looking at the code you mentioned.

I am still having a problem with it. It is something stupid sitting
right in front of me. I am using seven JTables that are each embedded
into an instance TableSorter. What I wanted to do is only cosmetic after
all of the JTables have been loaded. That is, correct the widths of all
the columns size to the largest data element in that column. I have code
that does that and I know it works. Just need to get it working with the
seven JTables in this app.

Also, if any one wants to use the MyTableModel.java with Sun's
TableSorter.java(I posted in the first msg of this thread). You need to
do the following as I mentioned before:

    TableSorter sorter = new TableSorter(new MyTableModel());
    JTable table = new JTable(sorter);
    sorter.setTableHeader(table.getTableHeader());

But also add this line of code after the above code:
//
// Need to force the sorting status so that the column values will be
// repainted correctly (0 = sort ascending)
   sorter.setSortingStatus(firstColumn,0);

Thanks in Advance...
IchBin, Pocono Lake, Pa, USA
http://weconsultants.servebeer.com/JHackerAppManager
__________________________________________________________________________

'If there is one, Knowledge is the "Fountain of Youth"'
-William E. Taylor,  Regular Guy (1952-)
hilizbabe@yahoo.com - 15 May 2006 22:33 GMT
There are lot of gotchas with the JTable sorting provided in the sun
website. I would suggest you to use free QuickTable java component
(http://quicktable.org) which is an implementation on top of JTable ,
but hides all the complexities and allows to use the JTable methods. So
you can just replace Jtable with QuickTable

In this component, clicking on the table header does the sorting for
you. You don't need to write a single line of code. All the problems
with selection etc are already taken care of. In addition you can also
do sorting programtically


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.