Is there a generic TableModel we can use in JTable

2019-05-30 04:29发布

问题:

I'm now looking into JTables and have a bunch of business objects that I retrieve from the DB with Hibernate + Spring Data JPA.

I love that Spring Data JPA handles all the cumbersome implementation of the DAL and was wondering if there's something similar for TableModel.

Basically, I would have something along the lines of:

public class GenericTableModel<T> extends AbstractTableModel

And the GenericTableModel would use reflection and/or annotations to look into T.

Does something like this exist? I hope I don't have to have a TableModel for each object I want to display on a JTable..

回答1:

And the GenericTableModel would use reflection to look into T.

The Bean Table Model does this.



回答2:

http://java.net/projects/beansbinding/ Will let you bind business objects to view components (including tables) as long as you have Bean-Style getters and setters.



回答3:

I am in the process of writing a library for Swing Developers. Its a work in progress. But i have done what you are looking for. Take a look at the classes in this package:

http://code.google.com/p/swingobjects/source/browse/#git%2FSwingObjects%2Fsrc%2Forg%2Faesthete%2Fswingobjects%2Fview%2Ftable

For an example of how to use this, please take a look at this class- Look at line numbers - 70-85

http://code.google.com/p/swingobjects/source/browse/SwingObjects/src/test/CompTest.java

I havent got the documentation written yet. But if you dont follow anything, please comment back here.

Update - Code sample

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

import javax.swing.JFrame;
import javax.swing.JScrollPane;

import org.aesthete.swingobjects.annotations.Column;
import org.aesthete.swingobjects.view.table.RowDataBean;
import org.aesthete.swingobjects.view.table.SwingObjTable;
import org.jdesktop.swingx.JXFrame;

public class TableDemo {

    public static void main(String[] args) {

        try {

            //For this demo the Framework need not be initialised.. If you plan on using the entire framework, then
            //its best you initialise it before working on anything...
//          SwingObjectsInit.init("/swingobjects.properties", "/error.properties");

            //Here's the data to show on the table
            final List<Row> rows = new ArrayList<Row>();
            rows.add(new Row("Data 1", "Data 2", "Yes", true));
            rows.add(new Row("Data 3", "Data 4", "No", false));


            //Create the swing table as below.. Provide the Row.class to say that the data in the rows
            // will be from this class
            final SwingObjTable<Row> table = new SwingObjTable<Row>(Row.class);
            table.setData(rows);
            table.setVisibleRowCount(4);

            //Make any column into a combo box by calling the below method.
            //A column can be automatically made into a checkbox, by defining your property in the Row class as a boolean
            table.makeColumnsIntoComboBox(new String[] { "Yes", "No" }, 2);

            //Initialise the frame and show it on the screen
            final JXFrame frame = new JXFrame();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setContentPane(new JScrollPane(table));
            frame.pack();
            frame.setVisible(true);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static class Row extends RowDataBean{

        @Column(index=0,name="Column 1",editable=true)
        private String column1;

        @Column(index=1,name="Column 2",editable=true)
        private String column2;

        @Column(index=2,name="Column 3",editable=true)
        private String column3;

        @Column(index=3,name="Column 4",editable=true)
        private boolean column4;

        public Row(String column1, String column2, String column3, boolean column4) {
            super();
            this.column1 = column1;
            this.column2 = column2;
            this.column3 = column3;
            this.column4 = column4;
        }
        public String getColumn1() {
            return column1;
        }
        public void setColumn1(String column1) {
            this.column1 = column1;
        }
        public String getColumn2() {
            return column2;
        }
        public void setColumn2(String column2) {
            this.column2 = column2;
        }
        public String getColumn3() {
            return column3;
        }
        public void setColumn3(String column3) {
            this.column3 = column3;
        }
        public boolean getColumn4() {
            return column4;
        }
        public void setColumn4(boolean column4) {
            this.column4 = column4;
        }
        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((column1 == null) ? 0 : column1.hashCode());
            result = prime * result + ((column2 == null) ? 0 : column2.hashCode());
            result = prime * result + ((column3 == null) ? 0 : column3.hashCode());
            result = prime * result + (column4 ? 1231 : 1237);
            return result;
        }
        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            Row other = (Row) obj;
            if (column1 == null) {
                if (other.column1 != null)
                    return false;
            } else if (!column1.equals(other.column1))
                return false;
            if (column2 == null) {
                if (other.column2 != null)
                    return false;
            } else if (!column2.equals(other.column2))
                return false;
            if (column3 == null) {
                if (other.column3 != null)
                    return false;
            } else if (!column3.equals(other.column3))
                return false;
            if (column4 != other.column4)
                return false;
            return true;
        }
    }
}

Update: Answer to queries in Comments

1) The table can be inserted in any Component, right? (JPanel, JScrollPane, etc.),

Yes. The table extends JXTable (swingx) which extends JTable. So it can be placed inside any component. You would ideally place into a JScrollPane though.

2) We have control over the column names? (my app is localized in several langs)

Thanks for this. I didnt think about localisation when I started making the framework. You pointed me in the right direction. I was able to modify the framework quickly to achieve this. Its easy actually:

To make use of l10n - Before you start coding, make sure you initialize the Swing Objects Framework with the below line. If you dont provide a Locale, the default Locale will be applied.

SwingObjectsInit.init("swingobjects", "application",new Locale("fr", "FR"));

You need to have to have 2 sets of properties file.

1) swingobjects - This provides the defaults for the swingobjects framework. The file is already provided in my code base. Just copy paste the file onto a classpath location.

2) application - This is where you will need to put in your application's GUI texts/messages. You will have to make a new application properties file for every Locale you need.

Then finally, instead of saying

 @Column(index=0,name="Column 1",editable=true)
 private String column1;

You will have to use:

@Column(index=0,key="test.column1",editable=true)
private String column1;

Change name to key. This will make it read the Resource Bundle and search for a property test.column1 rather than your hard coded column Name.

3) Does SwingObjTable require hashCode and equals to be implemented?

The equals and hashcode is required if you use the Swing Objects Framework in its entirety. The Swing Objects Framework, allows you to set data for the GUI elements in a bean in your model class - Read as in MVC. The framework, then automatically updates the GUI if the bean's value has changed. In order to check if the bean's value has indeed changed, it needs to call the equals method. Hence you need to override it. You can make Eclipse generate this for you. Or if you dont use anything in the framework, then just call super.equals() from there.

Just check out / clone the git repo and you'll have be access the TableDemo example..

git clone https://writetosethu@code.google.com/p/swingobjects/