HowTos - Display: Tables

Create a Table

Description:
A Table normally is used to display the content of a data container like a Catalog or a CountingStock. To make your own datastrucure fully compatible to the framework, it is quite important to understand which classes participate in the displaying and editing process.

All these parts are already defined for the default data structure of the Framework. There are SingleTableFormSheets and TwoTableFormSheets (FormSheets with two SingleTables on them and some more functionality) which have static create methods where you only have to add a caption, a DataBasket and the data container(s) you want to be displayed while the Framework puts everything together. You then only have to define the buttons and at the TwoTableFormSheets the MoveStrategy for the interaction between the two SingleTables.

As example a SingleTableFormSheet displaying a Catalog is presented.

Used classes:

Related topics:

ToDo:

  1. First alternative:
    Call SingleTableFormSheet.create(String caption, Catalog c, Gate g) to initialize the SingleTableFormSheet and assign it to the UIGate.
  2. Second alternative that enables you to redefine any part of the Table to fit to your own data structure:
    1. Initialize a new JAbstractTable with
    2. the TableModel (here it is a CatalogTableModel) containing
    3. the Catalog
    4. a DataBasket (if needed) and
    5. a Comparator (if needed (if the data container isn't sorted or the display shall be orderd differently)) and
    6. a new TableEntryDescriptor (here it is a DefaultCatalogItemTED, because it is specialized on processing CatalogItems, which are contained in the Catalog)
    7. Put the JComponent on the FormSheet.
    8. Assign the FormSheet to the UIGate.

Example Source Code:

 
    1
        SingleTableFormSheet stfs =
            SingleTableFormSheet.create(
                    // the FormSheet's caption
                    "Display a Catalog",
                    // the Catalog to be displayed
                    (Catalog) catalog,
                    // the Gate at which to display the FormSheet
                    (UIGate) uig_initial,
                    // the TableEntryDescriptor that displays a Catalog
                    new DefaultCatalogItemTED());
			
			
			
    2
        2 a
        JAbstractTable abstractTable =
            new JAbstractTable(
                    2 b
                    new CatalogTableModel(
                            2 c
                            (Catalog) catalog,
                            2 d
                            (DataBasket) null,
                            2 e
                            (Comparator<CatalogItem>) null,
                            2 f
                            new DefaultCatalogItemTED())
                    );
        2 g
        FormSheet formSheet = new FormSheet(
                "Display a Catalog",
                abstractTable);
        2 h
        uig_initial.setFormSheet(formSheet);
		

Back to:


Create a sorted Table

Description:
Sorted tables are like normal ones, except that they have a certain order for displaying the content.
This example is almost the same as in Create a Table. Only the Comparator is new, which is necessary to define the sort order for the table. To do so, you have to implement the method public int compare(Object object1, Object object2), which shall return an int value corresponding to your desired sort order. As described in the Java API, the int should be negative if the second Object is of a higher value, zero if the Objects are "equal" and of positive if the first Object shall be on top. For more information on the Interface java.uitl.Comparator, please refer to the latest API.

Used classes:

Related topics:

ToDo:

  1. Initialize the Gate where the FormSheet shall be displayed in.
  2. Get the Catalog the content shall be displayed of.
  3. Create the Comparator and implement the method public int compare(Object object1, Object object2) to return an integer suiteable to the order of the compared elements.
  4. Call SingleTableFormSheet.create(String caption, Catalog c, Gate g, Compatator co, TableEntryDescriptor ted) to initialize the SingleTableFormSheet and assign it to the UIGate.

Example Source Code:

 
        1
        UIGate uig = new UIGate(null, null);
			
        2
        Catalog catalog = Shop.getTheShop().getCatalog("SimpleCatalog");
			
        3
        // the implemenatation of the used Comparator
        Comparator<CatalogItem> comparator = new Comparator<CatalogItem>()
        {
            // the method used for comparison
            public int compare(CatalogItem item1, CatalogItem item2)
            {
                // get the first CatalogItem's Value
                // get the second CatalogItem's Value
                NumberValue numValue2 = (NumberValue) item2.getValue();
                // convert Values to int
                int intValue1 = numValue1.getValue().intValue();
                int intValue2 = numValue2.getValue().intValue();
                // compare Values
                return intValue1 - intValue2;
            }
        };
			
        4
        SingleTableFormSheet stfs =
            SingleTableFormSheet.create(
                    "VideoCatalog",
                    catalog,
                    uig,
                    comparator,
                    new DefaultCatalogItemTED());
		

Back to:


Define a TableCellEditor

Description:
A TableCellEditor is needed to define the Component that displays the entry of a cell in a JTable, to check wether an edited value is valid and to inform it's parent table that an editing event finished.
Our CellEditor will have a util.swing.JTextInput as the Component to display and edit the entry. The validity of a initial cell value is being tested in public Object getCellEditorValue() by simply trying to parse it to a Currency. If parsing fails, zero will be returned and thereby no wrong value may be put into the cell and cause any trouble.
The validity of an edited cell value is being checked in public boolean stopCellEditing, which informs the calling member that a correct value has been entered. It checks the value just like getCellEditorValue() by trying to parse it. If it fails, there will be an error message and editing cannot be stoped until a valid value is being entered or editing is being aborted by pressing the escape key.

Used classes:

Related topics:

ToDo:

  1. Create a class extending DefaultCellEditor.
  2. Initialize the attributes in the constructor.
  3. Define how to get the CellEditors Component and its initial value to display and check its validity. In our case we return a util.swing.JTextInput for reasons of serializability with the initial value being checked by trying to parse it. If that fails, zero will be returned.
  4. Define how to resolve the value of the cell. This is needed in case of table or window updating.
  5. Define how to indicate the successful attempt of editing a cell. Here we, too, try to parse the entered value, but do not return zero if it fails. There will be an error message instead and the return of false, which prevents the editing to stop until a valid value is being entered or it is being aborted.

Example Source Code:

 
1
public class DisplayCellEditor extends DefaultCellEditor
{
    // needed for the JTextInput
    private String[] result;
			
    2
    public DisplayCellEditor(String[] result, String init)
    {
        super(new JTextInput(result, init));
        this.result = result;
    }
			
    3
    // define the Component and the value it shall display first
    public Component getTableCellEditorComponent(
            JTable jTable,
            Object value,
            boolean isSelected,
            int row,
            int column)
    {
        // fetch the Component and the initial value
        Component component = super.getTableCellEditorComponent(
                jTable,
                value,
                isSelected,
                row,
                column);
        // initialize the JTextInput, which is needed for editing
        // and used because it is serializable
        ((JTextInput)component).setText(
                ((Currency<CurrencyItem>) Shop.getTheShop().getCatalog(EuroCatalog)).toString((NumberValue) value)
                );
        // and return it
        return component;
    }
            
    4
    public Object getCellEditorValue()
    {
        // parse the value of the JTextInput
        try
        {
            return ((Currency<CurrencyItem>) Shop.getTheShop().getCatalog(EuroCatalog)).parse(result[0]);
        }
        catch (ParseException pexc)
        {
        // return zero if it fails
            return new IntegerValue(0);
        }
    }
            
    5
    // indicate wether an editing was successful or not
    public boolean stopCellEditing()
    {
        try
        {
            ((Currency<CurrencyItem>) Shop.getTheShop().getCatalog(EuroCatalog)).parse(result[0]);
        }
        catch (ParseException pexc)
        {
            // create an error message if parsing fails
            JOptionPane.showMessageDialog(null, "Incorrect value entered, has to be " Euro"");
            // return fals to stay in edit mode
            return false;
        }
        return super.stopCellEditing();
    }
}
		

Back to:


Define a new TableLayout

Description:
The TableLayout is the definition of how the information provided by the entries of a data container, which in tables are being represented as records, shall be split and put into the cells. As it is described in Create a Table, this is what a TableEntryDescriptor deals with. It defines the number of columns the table shall have, the headers of the columns, which TableCellRenderer or TableCellEditor shall be used and which value goes into a column.
The most important thing in a TED is to return the right Classes, CellRenderer or CellEditors for each column, because the displayed value is being visualized by a JComponent and the different types are being processed by the Renderer or Editor in very different ways to cast them. Mistakes will oftenly cause ClassCastExceptions, followed by huge error messages concerning the table rendering.
All this is defined columnwise, because the framework processes the records and fills each row, representing a record, column by column, representing values from the record.
This example is taken from the DefaultCatalogItemTED of the framework. It is called ..CatalogItem.. because it deals with the entries of a Catalog, which are CatalogItems. So it is normally used with a CatalogTableModel. For more information on this, please refer to Create a Table.

Used classes:

Related topics:

ToDo:

  1. Extend the AbstractTableEntryDescriptor which implements most of the methods of the interface TableEntryDescriptor quite sufficiently, so we only have to redefine those which do not fit to our data structure.
  2. Call the superclass in the Constructor in order to initialize the TED properly.
  3. Define the number of columns needed by redefining the method public int getColumnCount(). In this case it returns 2, because this TED only displays the name and value of the CatalogItem.
  4. Define the header of the columns with the method public String getColumnName(int index). Here an array of Strings is being used, but this can be done by anything that returns the right caption to the given index, beginning with '0' for the first column (if, selectCase or like in this example, an array).
  5. Define the class which each column shall deal with, ie. the class of the entrie's value that goes in that column, like in this case a String in the first and a value in the second one. Here, too, anything does, as long as it returns the right class to the right index.
  6. Define the entry that goes into each column of a line in public Object getValueAt(Object data, int index). The returned Object is of course the value to be written into column number 'index'. data is the data container entry, which is the record associated to the processed line. As it is a CatalogItem in this case, it is casted to it and then it's metods are being used to resolve the input for the cells.

Example Source Code:

 
1
public class DisplayCatalogItemTED extends AbstractTableEntryDescriptor
{
			
    2
    public DisplayCatalogItemTED()
    {
        super();
    }
			
    3
    // here we need only two columns, one for the name of the CatalogItem and one for it's value
    public int getColumnCount()
    {
        return 2;
    }
			
    4
    // the header of the columns, "Name" for the first, "Value" for the second one
    public String getColumnName(int index)
    {
        String[] names = {"Name", "Value"};
        return names[index];
    }
			
    5
    // The first column deals with Strings and the second one with Values.
    // This is rather important, because wrong definitions will cause ClassCastExceptions.
    public Class<?> getColumnClass(int index)
    {
        Class[] classes = {String.class, Value.class};
        return classes[index];
    }
			
    6
    // Here the cell-entry is being resolved, column by column,
    // taken from the Object data, which is a CagtalogItem in this case
    // The returned Object's class has to fit to the definition above.
    public Object getValueAt(Object data, int index)
    {
        if(index == 0)
        {
            return ((CatalogItem) data).getName();
        }
        else
        {
            return ((QuoteValue) ((CatalogItem) data).getValue()).getBid();
        }
    }
}
		

Back to:


Create an editable Table

Description:
Tables are not only useful to display the content of data containers, but also to edit it.
To do so, you may define certain columns as editable. The processing of a cell in a column is then being done by a javax.swing.table.TableCellEditor, which you add in the TableEntryDescriptor of your editable table. As you can see, the TableCellEditor interface can be found in the javax package and is not part of the SalesPoint classes. There you can also find implementations of it, like the DefaultCellEditor, which provides three JComponents to edit the value of a cell: A JCheckBox, a JComboBox and a JTextField. For more information on the DefaultCellEditor, please refer to the Java API documentation.

In this example we use a simple CatalogItem with a name and a string value to edit. Therefor we have to define a TableCellEditor as well as a TableEntryDescriptor that allows us the editing.

Used classes:

Related topics:

ToDo:

  1. the CatalogItem
    (See also: Define a simple CatalogItem and Define an advanced CatalogItem)
    1. Create a subclass of CatalogItemImpl.
    2. Define a string variable that represents the string value. Add the constructor, call super with the item's name as attribute and set the string value.
    3. Create the protected CatalogItemImpl getShallowClone() method and return a item copy.
    4. Add the public String getStringValue() to return the string value.
    5. For setting a new string value we define a setter method: public void setValue(String value).
  2. the CellEditor
    (See also: Define a TableCellEditor)
    1. Create a class extending DefaultCellEditor.
    2. Initialize the attributes in the constructor.
    3. Define how to get the CellEditors Component and its initial value to display.
    4. Define how to resolve the value of the cell. This is needed in case of table or window updating.
    5. Define how to indicate the successful attempt of editing a cell. In this case we only call the super-method, but use this to eventually check the input values.
  3. the AbstractTableEntryDescriptor
    (See also: Define a new TableLayout)
    1. Create a subclass of AbstractTableEntryDescriptor.
    2. Add the Catalog and DataBasket variables to get them easier resolved later.
    3. Add the necessary TableCellRenderers to the attributes. We need one for the CataloItem's name and one for its string value.
    4. Add the constructor with the Catalog and DataBasket as arguments.
    5. Initialize the attributes.
    6. Set the number of cells. We need 2, one for name and one for value.
    7. Set the column's head. self-explanatory.
    8. Set the CellRenderers for each cell. index specifies the column, so ew return the on the beginning declared renderers for our 2 columns.
    9. Because of the TableCellRenderers there need no ColumnClasses to be defined. Otherwise you would return the classes of the column elements like the column heads, e.g. return new String[] { String.class, Integer.class }[index];.
    10. Define the editable columns. We only want column 1 with the string value be editable.
    11. Assign the TableCellEditors. For the editable column we use the newly created CellEditor that enables editing. The other column calls the super method and therefore is not editable.
    12. Define how to resolve the value to be put into the cells. Because we display our editable CatalogItems the Object record is cast to them. Then simply the get methods of our item are used.
    13. Define how to set the edited values to the CatalogItem they belong to. For identifying the item we cast the Object record to CatalogItem and get the name. Afterwards we get the item from the catalog set by the TED's constructor for editing and set the new string value. For getting the catalog handle the possible VetoException.

Example Source Code:

CatalogItem class:

 
1 a
public class DisplayEditableCatalogItem extends CatalogItemImpl
{
			
    1 b
    // define a string variable and add constructor
    private String value;

    public DisplayEditableCatalogItem(String name, String value)
    {
        super(name);
        this.value = value;
    }
			
    1 c
    // return item copy
    protected CatalogItemImpl getShallowClone()
    {
        return new DisplayEditableCatalogItem(this.getName(), this.value);
    }
			
    1 d
    // return method for the string value
    public String getStringValue()
    {
        return this.value;
    }
			
    1 e
    // setter method for the string value
    public void setValue(String value)
    {
        this.value = value;
    }
}
		

CellEditor class:

 
2 a
public class DisplayEditableCellEditor extends DefaultCellEditor
{
    // needed for the JTextInput
    private String[] result;
			
    2 b
    // initialize the attributes in the constructor
    public DisplayEditableCellEditor(String[] result, String init)
    {
        super(new JTextInput(result, init));
        this.result = result;
    }
			
    2 c
    public Component getTableCellEditorComponent(
            JTable jTable,
            Object value,
            boolean isSelected,
            int row,
            int column)
    {
        // fetch the component and tis initial value
        Component component = super.getTableCellEditorComponent(
                jTable,
                value,
                isSelected,
                row,
                column);
        // initialize the JTextInput
        ((JTextInput)component).setText(value.toString());
        return component;
    }
			
    2 d
    // define how to resolve the value of the cell
    public Object getCellEditorValue()
    {
        return result[0];
    }
			
    2 e
    // define how to indicate the successful attempt of editing a cell
    public boolean stopCellEditing()
    {
        return super.stopCellEditing();
    }
}
		

AbstractTableEntryDescriptor class:

 
3 a
public class DisplayEditableTED extends AbstractTableEntryDescriptor
{
    3 b
    // Add Catalog and DataBasket variables
    private DataBasket dataBasket;
    private Catalog catalog;
			
    3 c
    // add TableCellRenderers
    private TableCellRenderer rendererName;
    private TableCellRenderer rendererValue;
			
    3 d
    // add constructor
    public DisplayEditableTED(Catalog catalog, DataBasket dataBasket)
    {
		
        3 e
        // initialize the Catalog and DataBasket
        this.catalog = catalog;
        this.dataBasket = dataBasket;
        // initialize the TableCellRenderers with DefaultTableCellRenderer
        rendererName = new DefaultTableCellRenderer();
        rendererValue = new DefaultTableCellRenderer();
        // set the align of the values cell to center. this is just optical baublery.
        ((DefaultTableCellRenderer) rendererValue).setHorizontalAlignment(
                SwingConstants.CENTER);
    }
			
    3 f
    // set column count
    public int getColumnCount()
    {
        return 2;
    }
			
    3 g
    // set column heads
    public String getColumnName(int index)
    {
        String[] names = new String[]{
                "Name",
                "Value"};
        return names[index];
    }
			
    3 h
    // assign the cell renderers
    public TableCellRenderer getCellRenderer(int index)
    {
        switch(index)
        {
            // displays the items name
            case 1:
                return rendererValue;
            // displays the items string value
            default:
                return rendererName;
        }
    }
			
    3 i
    // returns null, because the TableCellRenderer is already defined
    public Class<?> getColumnClass(int index)
    {
        return null;
    }
			
    3 j
    // set column 1 editable
    public boolean isElementEditable(Object record, int index)
    {
        return (index == 1);
    }
			
    3 k
    // assign CellEditors
    public TableCellEditor getCellEditor(int index)
    {
        if(index == 1)
            return new DisplayEditableCellEditor(new String[1], "");
        else
            return super.getCellEditor(index);
    }
			
    3 l
    // define how to resolve the entries of a row, column by column
    public Object getValueAt(Object record, int index)
    {
        // cast the record to our CatalogItem
        DisplayEditableCatalogItem item = (DisplayEditableCatalogItem) record;
        // returne the values corresponding to the column
        switch(index)
        {
            case 0:
                return item.getName();
            case 1:
                return item.getStringValue();
            default:
                return null;
        }
    }
			
    3 m
    // define how to change the edited value in the CatalogItem
    public void setValueAt(Object record, int index, Object value)
    {
        // define a CatalogItem, initially set to null
        DisplayEditableCatalogItem item = null;
        // get the current item's identifier
        String name = ((CatalogItem) record).getName();
        try
        {
            // get the item from the catalog for editing
            item = (DisplayEditableCatalogItem) this.catalog.get(name, dataBasket, true);
            // set the items new string value
            item.setValue(value.toString());
        }
        // catch the relevant exception
        catch (VetoException e)
        {
            e.printStackTrace();
        }
    }
}
		

Back to:


previous Display: User ManagementLog management next



by Thomas Ryssel