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.
-
JAbstractTable:
First of all there is theJAbstractTable
, which just displays any table. To let it know, which kind of data it shall display and how to do this, it needs anAbstractTableModel
, which is being added in the constructor. -
AbstractTableModel:
TheAbstractTableModel
deals with technical issues, like the properities of the cells of each column, for example the ability to edit them or how the data shall fit into the rows. This is also where the association of records to cells is being resolved. TheAbstractTableModel
itself needs aTableEntryDescriptor
to resolve the input of each cell from the given data container. -
TableEntryDescriptor:
As said above, aTableEntryDescriptor
handles the input of each cell and the association of records with them, processing each row and filling it column by column. A row represents an entry of the data container.
Here is the place, where the number of columns is being defined and which cells shall be editable. In such a case, theTableCellEditor
is being assigned to the cell. This is also the place where the most mistakes are being made, because you also have to define theCellRenderers
for each cell, which causes class CastExceptions when done wrong.
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:
- FormSheet
- SaleProcess
- SingleTableFormSheet
- AbstractTableEntryDescriptor
- AbstractTableModel
- JAbstractTable
- Catalog
- CatalogTableModel
- DefaultCatalogItemTED
Related topics:
ToDo:
-
First alternative:
CallSingleTableFormSheet.create(String caption, Catalog c, Gate g)
to initialize theSingleTableFormSheet
and assign it to theUIGate
. -
Second alternative that enables you to redefine any part of the Table to fit to your own data structure:
-
Initialize a new
JAbstractTable
with -
the
TableModel
(here it is aCatalogTableModel
) containing -
the
Catalog
-
a
DataBasket
(if needed) and -
a
Comparator
(if needed (if the data container isn't sorted or the display shall be orderd differently)) and -
a new
TableEntryDescriptor
(here it is aDefaultCatalogItemTED
, because it is specialized on processingCatalogItems
, which are contained in the Catalog) -
Put the
JComponent
on theFormSheet
. -
Assign the
FormSheet
to theUIGate
.
-
Initialize a new
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:
- FormSheet
- SaleProcess
- SingleTableFormSheet
- AbstractTableEntryDescriptor
- AbstractTableModel
- JAbstractTable
- Catalog
- CatalogTableModel
- DefaultCatalogItemTED
Related topics:
ToDo:
-
Initialize the
Gate
where theFormSheet
shall be displayed in. -
Get the
Catalog
the content shall be displayed of. -
Create the
Comparator
and implement the methodpublic int compare(Object object1, Object object2)
to return an integer suiteable to the order of the compared elements. -
Call
SingleTableFormSheet.create(String caption, Catalog c, Gate g, Compatator co, TableEntryDescriptor ted)
to initialize theSingleTableFormSheet
and assign it to theUIGate
.
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:
- none
ToDo:
-
Create a class extending
DefaultCellEditor
. - Initialize the attributes in the constructor.
-
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. - Define how to resolve the value of the cell. This is needed in case of table or window updating.
- 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:
-
Extend the
AbstractTableEntryDescriptor
which implements most of the methods of the interfaceTableEntryDescriptor
quite sufficiently, so we only have to redefine those which do not fit to our data structure. - Call the superclass in the Constructor in order to initialize the TED properly.
-
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 theCatalogItem
. -
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). - 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.
-
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 aCatalogItem
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:
-
the
CatalogItem
(See also: Define a simple CatalogItem and Define an advanced CatalogItem)-
Create a subclass of
CatalogItemImpl
. -
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. -
Create the
protected CatalogItemImpl getShallowClone()
method and return a item copy. -
Add the
public String getStringValue()
to return the string value. -
For setting a new string value we define a setter method:
public void setValue(String value)
.
-
Create a subclass of
-
the
CellEditor
(See also: Define a TableCellEditor)-
Create a class extending
DefaultCellEditor
. - Initialize the attributes in the constructor.
- Define how to get the CellEditors Component and its initial value to display.
- Define how to resolve the value of the cell. This is needed in case of table or window updating.
- 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.
-
Create a class extending
-
the
AbstractTableEntryDescriptor
(See also: Define a new TableLayout)-
Create a subclass of
AbstractTableEntryDescriptor
. -
Add the
Catalog
andDataBasket
variables to get them easier resolved later. -
Add the necessary
TableCellRenderers
to the attributes. We need one for theCataloItem's
name and one for its string value. -
Add the constructor with the
Catalog
andDataBasket
as arguments. - Initialize the attributes.
- Set the number of cells. We need 2, one for name and one for value.
- Set the column's head. self-explanatory.
-
Set the
CellRenderers
for each cell.index
specifies the column, so ew return the on the beginning declared renderers for our 2 columns. -
Because of the
TableCellRenderers
there need noColumnClasses
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];
. - Define the editable columns. We only want column 1 with the string value be editable.
-
Assign the
TableCellEditors
. For the editable column we use the newly createdCellEditor
that enables editing. The other column calls the super method and therefore is not editable. -
Define how to resolve the value to be put into the cells. Because we display our editable
CatalogItems
theObject record
is cast to them. Then simply the get methods of our item are used. -
Define how to set the edited values to the
CatalogItem
they belong to. For identifying the item we cast theObject record
toCatalogItem
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 possibleVetoException.
-
Create a subclass of
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:
Display: User Management | Log management |