简体   繁体   English

Java DefaultTableModel从多个表收集数据

[英]Java DefaultTableModel gather data from multiple tables

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. 在Internet上进行长时间搜索后,我决定通过扩展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 类人TM

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 课堂课程TM

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

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 类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: 所以我的问题是:

  1. How am I supposesd to appear a JTable with all columns from Person and Courses? 我应该如何显示“个人”和“课程”中所有列的JTable? Should I do this through Attends and how? 我应该通过与会者来做到这一点吗?

  2. How am I gathering data from Person and Course in AttendsTM? 如何从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 DefaultTableModel you'd most probably use the constructor DefaultTableModel(Object[][] data, Object[] columnNames) . 如果使用的是DefaultTableModel ,则很可能会使用构造函数DefaultTableModel(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, eg 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. 另外,您只需要根据需要传递列名,例如,如果2D数组中每行的第一个元素包含人的名字,则您将传递“ name”之类的内容作为列名数组中的第一个元素。

The layout of your 2D array depends on how you want to display your data. 2D阵列的布局取决于您要如何显示数据。 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. 如果要将一个人的所有课程都放在一个单元格中,则可以使用预格式化的字符串(AFAIK,默认渲染器可以显示html格式的文本),也可以提供自己的渲染器。

Example for the simple approach using duplicate cells: 使用重复单元格的简单方法示例:

Object[][] data = new Object[numrows][];
int curRow = 0;
for( Person p : persons ) { //assuming you have loaded the persons already
  for( Course c : p.getCourses() ) { //loop over all courses a person has taken
    Object[] row = new Object[numcols];  //create a new row array

    //just an example of how to fill the elements
    row[0] = p.getName(); //column 1 will contain the person's name
    row[1] = c.getCourseName(); //column 2 will contain the course name
    ...

    data[curRow] = row;
    curRow++; 
  }
}

Then you just pass that array to the DefaultTableModel constructor. 然后,您只需将该数组传递给DefaultTableModel构造函数即可。 The result might look like this: 结果可能如下所示:

+-------------+------------------------+
| Person name |  Course                |
+=============+========================+
| Vassilis De | Java Programming       |
+-------------+------------------------+
| Thomas      | Java Programming       |
+-------------+------------------------+
| Thomas      | How to answer in SO    |
+-------------+------------------------+
| Thomas      | Writing good examples  |
+-------------+------------------------+
| Thomas      | Being polite           |
+-------------+------------------------+

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. 如何加载数据将取决于您的应用程序,但是在示例中,我假定您正在使用JPA或类似的东西。

Update: 更新:

If I understand your comment correctly, there are two basic questions: 如果我正确理解您的评论,则有两个基本问题:

  1. where to load the data 在哪里加载数据
  2. how to add new columns 如何添加新列

I'd do both in a controller class which then just passes the data to the table model, ie you might not even need AttendsTM etc. Have a look at the MVC pattern for more information on how to create and use controllers. 我将在控制器类中做这两种事情,然后将数据传递到表模型,即,您甚至可能不需要AttendsTM等。有关如何创建和使用控制器的更多信息,请查看MVC模式。

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 (eg 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 override getValueAt() etc. in order to hide certain columns. 使用自定义表模型的原因可能有一个(例如,作为DefaultTableModel的子类):如果要向模型添加一些键,这些键允许您标识实体,但不应在表中显示,则可以覆盖getValueAt()等以隐藏某些列。

    Vector<Object> columnNames = new Vector<Object>();
    Vector<Object> data = new Vector<Object>();    

Assume you get a Table1List from database, Table1 consist Table2 object as well. 假设您从数据库中获得一个Table1List,Table1也包含Table2对象。 In my example I am using JPA 在我的示例中,我正在使用JPA
// Get column names //获取列名

  columnNames.addElement("Table1 Attribute 1"); columnNames.addElement("Table1 Attribute 2"); columnNames.addElement("Table1 Attribute 3"); columnNames.addElement("Other Table Attribute 1"); columnNames.addElement("Other Table Attribute 2"); 
            // Display Row value
            for (Table1 Table1Obj: Table1List) {
                Vector<Object> row = new Vector<Object>();
                Table2 Table2Obj = getTable2DataFromDatabase(Table1Obj.getTable1Id());
                row.addElement(Table1Obj.getTable1 Name());
                row.addElement(Table1Obj.getTable1 Email());
                row.addElement(Table1Obj.getTable1 Phone());
                row.addElement(Table2Obj.getTable1 ID());
                row.addElement(Table1Obj.getTable1 Name());

                data.addElement(row);

// Create table with database data

final DefaultTableModel model = new DefaultTableModel(data, columnNames) {

    private static final long serialVersionUID = 1L;

    @Override
    public Class getColumnClass(int column) {
        for (int row = 0; row < getRowCount(); row++) {
            Object o = getValueAt(row, column);
            if (o != null) {
                return o.getClass();
            }
        }

        return Object.class;
    }
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM