I have a data relation
Person-Attends-Course
Person
-------
id: integer primary key
name: string
prename: string
age: integer
Course
-------
courseName: string primary key
hours: integer
Attends
--------
id: integer primary key references Person
courseName: string primary key references Course
I need to have a data validation. After a long search on the Internet, I decided to implement it by extending DefaultTableModel. So far I created the code below and I have some questions:
Class Person
class Person{
private String name, prename,id;
private int age;
public Person(){}
public String getName(){return this.name;}
public String getPrename(){return this.prename;}
public int getAge(){return this.age;}
public String getId(){return this.id;}
public void setName(String name){
try{
if(name.equals(""))
JOptionPane.showMessageDialog(null, "Must insert name");
else
this.name = name;
}
catch(NullPointerException e){
this.name = "";
}
}
public void setPrename(String prename){
if(prename.equals(""))
JOptionPane.showMessageDialog(null, "Must insert prename");
else
this.prename = prename;
}
public void setAge(int age){
try{
if(age <0 || age >=100)
JOptionPane.showMessageDialog(null, "Must insert valid age");
else
this.age = age;
}
catch(Exception e){
this.age = 0;
}
}
public void setId(String id){
this.id = id;
}
}
Class PersonTM
class PersonTM extends DefaultTableModel{
private final List<Person> personlist;
private final String[] columnNames = {"id", "name", "prename","age"};
private final Class[] columnClass = {String.class, String.class, String.class, Integer.class};
public PersonTM(){this.personlist = new ArrayList<>();}
@Override
public Class<?> getColumnClass(int columnIndex){
return columnClass[columnIndex];
}
@Override
public String getColumnName(int column){
return columnNames[column];
}
public String[] getColumnNames(){return this.columnNames;}
@Override
public int getColumnCount() {
return columnNames.length;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
Person row = personlist.get(rowIndex);
switch(columnIndex){
case 0:
return row.getId();
case 1:
return row.getName();
case 2:
return row.getPrename();
case 3:
return row.getAge();
default:
return null;
}
}
@Override
public void setValueAt(Object obj, int rowIndex, int columnIndex){
Person row = personlist.get(rowIndex);
switch(columnIndex){
case 0:
row.setId((String)obj);
break;
case 1:
row.setName((String)obj);
break;
case 2:
row.setPrename((String)obj);
break;
case 3:
row.setAge((Integer)obj);
break;
}
}
}
Class Course
class Courses{
private String courseName;
private int hours;
public Courses(){}
public String getCourseName(){return this.courseName;}
public int getHours() {return this.hours;}
public void setCourseName(String courseName){
if(courseName.equals(""))
JOptionPane.showMessageDialog(null, "Must insert courseName");
else
this.courseName = courseName;
}
public void setHours(int hours){
if(hours <=0 || hours >=50)
JOptionPane.showMessageDialog(null, "Must insert valid hours");
else
this.hours = hours;
}
}
Class CourseTM
class CoursesTM extends DefaultTableModel{
private final List<Courses> courseslist;
private final String[] columnNames = {"course name","hours"};
private final Class[] columnClass = {String.class,Integer.class};
public CoursesTM(){this.courseslist = new ArrayList<>();}
@Override
public Class<?> getColumnClass(int columnIndex){
return columnClass[columnIndex];
}
@Override
public String getColumnName(int column){
return columnNames[column];
}
public String[] getColumnNames(){return this.columnNames;}
@Override
public int getColumnCount() {
return columnNames.length;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
Courses row = courseslist.get(rowIndex);
switch(columnIndex){
case 0:
return row.getCourseName();
case 1:
return row.getHours();
default:
return null;
}
}
@Override
public void setValueAt(Object obj, int rowIndex, int columnIndex){
Courses row = courseslist.get(rowIndex);
switch(columnIndex){
case 0:
row.setCourseName((String)obj);
break;
case 1:
row.setHours((Integer)obj);
break;
}
}
}
Class Attends
//here I am a little confused
class Attends{
private final Person p;
private final Course c;
public Attends(Person p,Course c){
this.p = p;
this.c = c;
}
public Person getPerson(){return this.p;}
public Course getCourse(){return this.c;}
}
Class AttendsTM
class AttendsTM extends DefaultTableModel{
private final PersonTM p;
private final CoursesTM c;
private final Map<Person,List<Course>> attendslist;
private String[] columnNames;
private final Class[] columnClass = {Person.class,Courses.class};
public AttendsTM(Map<Person,List<Courses>> attendslist){
this.attendslist = attendslist;
this.p = new PersonTM();
this.c = new CoursesTM();
}
public void setColumnNames(){
for (int i = 0; i < p.getColumnCount(); i++)
columnNames[i] = p.getColumnName(i);
for (int i = p.getColumnCount(); i < c.getColumnCount(); i++)
columnNames[i] = c.getColumnName(i);
}
}
Class Viewer
class viewer extends JFrame{
private final JScrollPane scrollPane;
private final AttendsTM model;
private final JTable table;
public viewer(){
//collect data from db
Person p1 = new Person();
p1.setId("00001");
p1.setName("John");
p1.setPrename("Johnson");
p1.setAge(30);
Person p2 = new Person();
p2.setId("00002");
p2.setName("Jack");
p2.setPrename("Jackson");
p2.setAge(30);
Courses c1 = new Courses();
c1.setCourseName("History of art");
c1.setHours(25);
Courses c2 = new Courses();
c2.setCourseName("Music");
c2.setHours(15);
List<Courses> coursesList = new ArrayList<>();
coursesList.add(c1);
coursesList.add(c2);
Map<Person,List<Courses>> attendsMap = new LinkedHashMap<>();
attendsMap.put(p1, coursesList);
attendsMap.put(p2, coursesList);
model = new AttendsTM(attendsMap);
table = new JTable(model);
//add a blank row at the end of Jtable
model.addRow(new Object[model.getColumnCount()]);
table.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
table.setCellSelectionEnabled(true);
table.setColumnSelectionAllowed(false);
table.setRowSelectionAllowed(true);
//resize columns and use horizontal scroll bar to view data
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
//disable column dragging
table.getTableHeader().setReorderingAllowed(false);
scrollPane = new JScrollPane(table, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
}
public void initializeUI(){
add(scrollPane);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setSize(300,300);
setVisible(true);
}
}
Class TableModelExample
public class TableModelExample {
public static void main(String[] af){
Runnable runnable = new Runnable(){
@Override
public void run() {
new viewer().initializeUI();
}
};
EventQueue.invokeLater(runnable);
}
}
So my questions are:
How am I supposesd to appear a JTable with all columns from Person and Courses? Should I do this through Attends and how?
How am I gathering data from Person and Course in AttendsTM? Am I doing it right?
Any suggestion would be very wellcome. Thank you in advance.
I didn't thoroughly read your code (it's quite a lot) but basically you'd do the following:
If you're using
DefaultTableModelyou'd most probably use the constructorDefaultTableModel(Object[][] data, Object[] columnNames). In that case you'd load your persons and courses and build a 2D array of the data that you need to be displayed. Additionally you'd just pass column names as needed, e.g. if the first element of each row in your 2D array contains the person's name you'd pass something like "name" as the first element in the column name array.The layout of your 2D array depends on how you want to display your data. Each element of a row would correspond to a cell in the table. If you want to have a row per course and person you'd just generate multiple rows most probably getting redundant/duplicate cells. Of course you could just fill the first cells and empty any redundant elements in order to render empty cells where needed, but in that case you should not allow sorting.
If you want to put all courses a person takes into a single cell you could either use a pre-formatted string (AFAIK the default renderers can display html-formatted text) or provide your own renderer.
Example for the simple approach using duplicate cells:
Then you just pass that array to the
DefaultTableModelconstructor. The result might look like this:Please note that this just covers how to build the table model from already loaded data. How you load the data would depend on your application but in the examples I assume you're using JPA or something similar.
Update:
If I understand your comment correctly, there are two basic questions:
I'd do both in a controller class which then just passes the data to the table model, i.e. you might not even need
AttendsTMetc. Have a look at the MVC pattern for more information on how to create and use controllers.When saving entered data the controller would then read the data from the table model and interpret in a way that allows you to add new entries into your database. Again how this is done depends on your application.
There might be one reason to use a custom table model (e.g. as a subclass of
DefaultTableModel): if you want to add some keys to the model which allow you to identify entities but which should not be displayed in the table, you could then overridegetValueAt()etc. in order to hide certain columns.