Java GUI创建JTables表的最佳方法是什么?

时间:2017-09-21 00:23:17

标签: java layout jframe jtable tablemodel

[UPDATE !!!!] 这是完成产品:

:)

enter image description here enter image description here 所以我正在制作一个程序,帮助我组织和打印晚餐座位。我有一个学生班,其实例变量包括FirstName,LastName等。我还有一个DinnerTable类,其中包含Student和String teacherName。我创建了一个GUI,以便更容易分配不同的席位。我已经在JTabbedPane上有一个标签,用于组织学生信息(如果它们可用或不可用)并随机化他们所在的表格。现在,为了更好地可视化表格并使每个学生更容易分配到特定的座位,我需要做这样的事情: enter image description here 我想在TableModel中使用实际的DinnerTable对象,这样每当我在此Frame上编辑某些内容时,更改都会转换为对象。但是,我不确定该怎么做。我应该:

1.创建表(每个DinnerTable的一个JTable)嵌套在一个更大的JTable的单元格中?但是,如何在DinnerTable之间执行诸如滑动学生之类的操作?要么 2.在GridLayout或GridBagLayout中对齐JTable?但同样,我怎么能交换学生?

谢谢!       包DinnerList;

  public class Student 
  {
  private String lastName;
  private String firstName;
  private int grade;
  private int table;
  private boolean gender;//Male=true, female=false;
  private boolean available; //true=available;

public Student()
{
    lastName="";
    firstName="";
    grade=0;
    table=0;
    gender=true;
    available=true;
}
public Student(String l, String f, int i, boolean g, boolean a)
{

    lastName=l;
    firstName=f;
    grade=i;
    gender=g;
    available=a;
    //table is not written back to the txt.
    table=0;
}
//Getters

  public String getLastName()
   {
    return lastName;
  }
  public String getFirstName()
{
    return firstName;
}
public int getGrade()
{
    return grade;
}       
public int getTable()
{
    return table;
}
  public boolean getGender()
{
    return gender;
}
public boolean getAvailable()
{
    return available;
}

//Setters
public void setLastName(String s)
{
    this.lastName=s;
}
public void setFirstName(String s)
{
    firstName=s;
}
public void setGrade(int i)

{
    grade=i;
}
public void setTable(int hiahia)
{
    table=hiahia;
}
public void setGender(boolean b)
{
    gender=b;
}
public void setAvailable(boolean b)
{
    available=b;
}

//Miscellaneous
  public String toString()
  {
    String a="";

     a=lastName+","+firstName+","+Integer.toString(grade)+","+Boolean.toString(gender)+","+Boolean.toString(available);
    return a;
    }
 }

///////////////////////////////////

 package DinnerList;

   import java.util.ArrayList;
   import java.util.List;

  public class DinnerTable 
{
    private List<Student> members= new ArrayList<Student>();
    private int tableNumber=0;
    private int capacity=0;
    private String teacherName="";
    private boolean available=true;

public DinnerTable(int a, int b, String c, boolean d)
{
    tableNumber=a;
    capacity=b;
    teacherName=c;
    available=d;
}

public void setTableNumber(int a) {tableNumber=a;}
public void setCapacity(int a) {capacity=a;}
public void setTeacherName(String a) {teacherName=a;}
public void setAvailable(boolean b) {available=b;}
public void add(Student s)
{
    if(available&&(members.size()<capacity))
    { this.members.add(s); }
    else if(!available)
    { System.out.println("Adding Student failed, table "+tableNumber+" not available");}
    else
    { System.out.println("Adding Student failed, table "+tableNumber+" is full");}
}

public int getTableNumber() 
{return tableNumber;}
public int getCapacity() {return this.capacity;}
public String getTeacherName() {return teacherName;}
public boolean getAvailable() {return available;}
public List<Student> getMembers(){return members;}
public void remove(Student s) 
{
    if(members.contains(s))
    {
        members.remove(s);
    }
    else
    {
        System.out.println("Failed to remove student from table because it wasn't there");
    }
  }
}

/////////////////////

package DinnerList;

import java.awt.Component;

import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;

public class DinnerTableCellRenderer extends DefaultTableCellRenderer implements TableCellRenderer {

@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
          boolean hasFocus, int row, int column)
{
    Object huahua =table.getModel().getValueAt(row, column);
    String ppp="";
    if(huahua!=null)
    {
        if(huahua instanceof Student)
        {
            ppp=((Student) huahua).getLastName()+", "+((Student)huahua).getFirstName();
        }
        else if(huahua instanceof String)
        {
            ppp=(String)huahua;
        }
        else
        {
            System.out.println("Error: DinnerTableCellRenderer intakes unknown data type");
        }
    }
    else
    {
        ppp="";
    }
    JLabel label = (JLabel)super.getTableCellRendererComponent(table, ppp,isSelected, hasFocus,row, column);
    return label;
    }

}

//////////

package DinnerList;

import java.util.ArrayList;
import java.util.List;

import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;

public class DinnerTableModel extends AbstractTableModel implements TableModel
 {
    private final String[] columnNames={"","","",""};
    private List<DinnerTable> tableCollection= new ArrayList<DinnerTable>();


public DinnerTableModel(List<DinnerTable> huhu)
{
    tableCollection.addAll(huhu);
}
public int getColumnCount() 
{
    return columnNames.length;
}

public int getRowCount() 
{
        if(tableCollection.size()%4==0)
        {
            return tableCollection.size()/4;
        }
        else
        {
            return (int)(tableCollection.size()/4)+1;
        }
}

public String getColumnName(int col) 
{
    return columnNames[col];
}

public DinnerTable getTableAt(int row, int column)
{
        if(tableCollection.size()>=(Integer)((row)/8)+column+1)
        {
            return tableCollection.get((Integer)((row)/8)+column);
        }
        else
        {
            return null;
        }

}
public Object getValueAt(int rowIndex, int colIndex) 
{
    DinnerTable dd= this.getTableAt(rowIndex, colIndex);
    String ss= "";
    if(dd==null)
    {
            return "";
    }
    else if(rowIndex%8==0)
    {
            return (dd.getTableNumber()+". "+dd.getTeacherName());
    }
    else if(dd.getMembers().size()>=rowIndex%8)
    {
            return dd.getMembers().get(rowIndex%8);
    }
    else
    {
            return "";
    }
}


public Class getColumnClass(int c) 
{
    return getValueAt(0, c).getClass();
}
public boolean isCellEditable(int row, int col) 
{
        if(this.getValueAt(row, col) instanceof Student)
        {
            return true;
        }
        else
        {
            return false;
        }
}
    public void setValueAt(Object aValue, int rowIndex, int columnIndex)
    {

  if(aValue instanceof Student)
  {
        if(rowIndex%8!=0)
        {
            if(null!=this.getTableAt(rowIndex,columnIndex))
            {
                this.getTableAt(rowIndex,columnIndex).getMembers().set(rowIndex%8-1, (Student)aValue);
            }
            else
            {
                System.out.println("error: Attempting to put student in nonexistent table in table list gui");
            }
        }
        else
        {
            System.out.println("error: Attempting to put student in a string in table list gui");
        }
  }
  else if(aValue instanceof String)
  {
        System.out.println("error: Attempting to change teacher name in tablelist gui");
  }
  else
  {
        System.out.println("error: Attempting to set unknown object type in tablelist gui");
  }
}

}

//// //// ****************

JTable tableTable= new JTable(new DinnerTableModel(tables));
for(int hihihi=0;hihihi<tableTable.getColumnCount();hihihi++)
{
  tableTable.getColumnModel().getColumn(hihihi).setCellRenderer(new   DinnerTableCellRenderer());
}
JScrollPane scrollpaneB1= new JScrollPane();
scrollpaneB1.add(tableTable);
panelB.add(scrollpaneB1);

1 个答案:

答案 0 :(得分:1)

  

我是编程新手并且有很多问题。你这么耐心,真是太好了! :)但是,我有另一个JTable进入另一个TableModel类。我运行测试,看起来模型确实会在原始对象发生变化时发生变化,即使我没有使用任何propertychangelisteners。这让我很困惑......

JTable是API中较复杂的组件之一(JTree,文字组件是其中之一),如果您对此感到满意,那么您将会有很长的路要走使用整体API。

您可以通过多种方式通知TableModel某个对象已更改,但最好的方法之一是以解耦方式执行,因此您不必维护对TableModel对象可能发生变化的Student的引用。

这表明Student对象本身应该生成某种更改事件,感兴趣的各方(如TabelModel)可以在发生时监听并采取措施。

通过这种方式,您可以在代码中的任何位置更改Student对象,而无需关心谁可能需要知道对象已更改。

现在,这基本上归结为一个观察者模式,Swing在它的听众中实现了这种功能,ChangeListener让人想起可能的候选人,但是PropertyChangeListener更多功能强大的选项,因为它根据已更改的属性生成事件。

在某些情况下,您可能无法关注属性的变化,但在TableModel的情况下,它非常有用。

这是一个简单的概念演示,使用两个表。您可以编辑任一表中的任何值,并在提交值时更新相对的表。现在,您还可以在代码中修改Student的实例,并获得相同的结果,但这只是一个简单的示例。

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.AbstractTableModel;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                Student student = new Student("Skywalker", "Luke", 0, true, true);
                StudentTabelModel leftModel = new StudentTabelModel(student);
                StudentTabelModel rightModel = new StudentTabelModel(student);

                JTable leftTable = new JTable(leftModel);
                leftTable.setGridColor(Color.GRAY);
                JTable rightTable = new JTable(rightModel);
                rightTable.setGridColor(Color.GRAY);

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new GridLayout(0, 2));
                frame.add(new JScrollPane(leftTable));
                frame.add(new JScrollPane(rightTable));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class StudentTabelModel extends AbstractTableModel {

        private List<Student> students = new ArrayList<>(25);
        private PropertyChangeListener propertyChangeListener;

        public StudentTabelModel(Student... students) {
            propertyChangeListener = new StudentPropertyChangeListener();
            add(students);
        }

        public void add(Student... students) {
            if (students != null && students.length > 0) {
                int startRow = this.students.size();
                for (Student student : students) {
                    student.addPropertyChangeListener(propertyChangeListener);
                    this.students.add(student);
                }
                fireTableRowsInserted(startRow, this.students.size() - 1);
            }
        }

        public void remove(Student ...students) {
            if (students != null && students.length > 0) {
                for (Student student : students) {
                    int index = this.students.indexOf(student);
                    if (index != -1) {
                        student.removePropertyChangeListener(propertyChangeListener);
                        this.students.remove(student);
                        fireTableRowsDeleted(index, index);
                    }
                }
            }
        }

        @Override
        public boolean isCellEditable(int rowIndex, int columnIndex) {
            return true;
        }

        @Override
        public int getRowCount() {
            return students.size();
        }

        @Override
        public int getColumnCount() {
            return 6;
        }

        @Override
        public Class<?> getColumnClass(int columnIndex) {
            switch (columnIndex) {
                case 0:
                case 1:
                    return String.class;
                case 2:
                case 3:
                    return Integer.class;
                case 4:
                case 5:
                    return Boolean.class;
            }
            return Object.class;
        }

        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
            Student student = students.get(rowIndex);
            switch (columnIndex) {
                case 0:
                    return student.getLastName();
                case 1:
                    return student.getFirstName();
                case 2:
                    return student.getGrade();
                case 3:
                    return student.getTable();
                case 4:
                    return student.getGender();
                case 5:
                    return student.getAvailable();
            }
            return "??";
        }

        @Override
        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
            Student student = students.get(rowIndex);
            switch (columnIndex) {
                case 0:
                    student.setLastName(aValue == null ? null : aValue.toString());
                    break;
                case 1:
                    student.setFirstName(aValue == null ? null : aValue.toString());
                    break;
                case 2:
                    if (aValue instanceof Integer) {
                        student.setGrade((Integer) aValue);
                    }
                    break;
                case 3:
                    if (aValue instanceof Integer) {
                        student.setTable((Integer) aValue);
                    }
                    break;
                case 4:
                    if (aValue instanceof Boolean) {
                        student.setGender((Boolean) aValue);
                    }
                    break;
                case 5:
                    if (aValue instanceof Boolean) {
                        student.setAvailable((Boolean) aValue);
                    }
                    break;
            }
        }

        protected class StudentPropertyChangeListener implements PropertyChangeListener {

            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                if (evt.getSource() instanceof Student) {
                    Student student = (Student) evt.getSource();
                    int row = students.indexOf(student);
                    if (row != -1) {
                        switch (evt.getPropertyName()) {
                            case "lastName":
                                fireTableCellUpdated(row, 0);
                                break;
                            case "firstName":
                                fireTableCellUpdated(row, 1);
                                break;
                            case "grade":
                                fireTableCellUpdated(row, 2);
                                break;
                            case "table":
                                fireTableCellUpdated(row, 3);
                                break;
                            case "gender":
                                fireTableCellUpdated(row, 4);
                                break;
                            case "avaliable":
                                fireTableCellUpdated(row, 5);
                                break;
                        }
                    }
                }
            }

        }

    }

    public class Student {

        private String lastName;
        private String firstName;
        private int grade;
        private int table;
        private boolean gender;//Male=true, female=false;
        private boolean available; //true=available;

        private PropertyChangeSupport propertyChangeSupport;

        public Student() {
            this("", "", 0, false, true);
        }

        public Student(String l, String f, int i, boolean g, boolean a) {

            lastName = l;
            firstName = f;
            grade = i;
            gender = g;
            available = a;
            //table is not written back to the txt.
            table = 0;
            propertyChangeSupport = new PropertyChangeSupport(this);
        }

        public void addPropertyChangeListener(PropertyChangeListener listener) {
            propertyChangeSupport.addPropertyChangeListener(listener);
        }

        public void removePropertyChangeListener(PropertyChangeListener listener) {
            propertyChangeSupport.removePropertyChangeListener(listener);
        }
//Getters

        public String getLastName() {
            return lastName;
        }

        public String getFirstName() {
            return firstName;
        }

        public int getGrade() {
            return grade;
        }

        public int getTable() {
            return table;
        }

        public boolean getGender() {
            return gender;
        }

        public boolean getAvailable() {
            return available;
        }

//Setters
        public void setLastName(String s) {
            String old = lastName;
            this.lastName = s;
            propertyChangeSupport.firePropertyChange("lastName", old, lastName);
        }

        public void setFirstName(String s) {
            String old = firstName;
            firstName = s;
            propertyChangeSupport.firePropertyChange("firstName", old, firstName);
        }

        public void setGrade(int i) {
            int old = grade;
            grade = i;
            propertyChangeSupport.firePropertyChange("grade", old, grade);
        }

        public void setTable(int hiahia) {
            int old = table;
            table = hiahia;
            propertyChangeSupport.firePropertyChange("table", old, table);
        }

        public void setGender(boolean b) {
            boolean old = gender;
            gender = b;
            propertyChangeSupport.firePropertyChange("gender", old, gender);
        }

        public void setAvailable(boolean b) {
            boolean old = available;
            available = b;
            propertyChangeSupport.firePropertyChange("available", old, available);
        }

//Miscellaneous
        @Override
        public String toString() {
            String a = "";

            a = lastName + "," + firstName + "," + Integer.toString(grade) + "," + Boolean.toString(gender) + "," + Boolean.toString(available);
            return a;
        }
    }
}

请记住,这依赖于Student已共享的实例,如果您创建Student对象的两个不同实例并期望一个实例中的更改将反映在另一个实例中,那么您会很失望的