2
votes

I've got a JTable displaying more than 200 rows. I'd like to show all the rows in a JPanel so that the user doesn't have to scroll down.

I've tried to get the number of visible rows in my first table and add another JTable with remaining rows, using viewport as shown in https://coderanch.com/t/340707/java/find-visible-row-count-JTable.
However, the method returns the number of visible rows only after the panel is painted and visible to users. So I can't add another JTable dynamically to the same panel.

Following is the code I've used to achieve the above requirement, but the new table is added only when button is clicked. I tried to add tables dynamically based on visible rows in lastTable, but as explained above, I don't get the correct numbers of visible rows until the table appears in viewport.


    import java.awt.BorderLayout;
    import java.awt.Dimension;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.util.ArrayList;
    import java.util.List;

    import javax.swing.BoxLayout;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JTable;
    import javax.swing.JViewport;
    import javax.swing.ScrollPaneConstants;
    import javax.swing.table.AbstractTableModel;

    public class DataPanel  extends JPanel{

        /**
         * 
         */
        private static final long serialVersionUID = 1L;

        List data = new ArrayList();
        JScrollPane scrollPane;
        JTable table, lastTable;
        JPanel boxPanel;
        int rows = 0;

        public DataPanel()
        {
            for (int i = 0; i  newData = getData(rows);
                DataModel newModel = new DataModel(newData);
                JTable newTable = new JTable(newModel);
                lastTable = newTable;
                JScrollPane newScrollPane = new JScrollPane(newTable);
                newScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
                boxPanel.add(newScrollPane);
            }
        }

        private List getData(int rows) {
            // TODO Auto-generated method stub
            List newData = new ArrayList();
            for(int i=0; i= rows)
                {
                    newData.add(data.get(i));
                }
            }
            return newData;
        }

        private int getVisibleRowCount(JTable table)
        {
            JViewport viewport = (JViewport) table.getParent();
            Dimension extentSize = viewport.getExtentSize();     // JViewport
            int visibleRows = extentSize.height/table.getRowHeight();
            return visibleRows;
        }

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

        private class DataModel extends AbstractTableModel{

            static final int COL1_INDEX = 0;
            static final int COL2_INDEX = 1;

            private final String[] COLUMN_NAMES = new String[]
                    {"ID", "Name"};

            private List data = new ArrayList();

            public DataModel(List newData)
            {
                data = newData;
            }

            public List getData() {
                return data;
            }

            public void setData(List data) {
                this.data = data;
            }

            @Override
            public int getColumnCount() {
                // TODO Auto-generated method stub
                return COLUMN_NAMES.length;
            }

            @Override
            public int getRowCount() {
                // TODO Auto-generated method stub
                if (null == data)
                    return 0;
                return data.size();
            }

            @Override
            public Object getValueAt(int row, int col) {
                // TODO Auto-generated method stub
                System.out.println("Requesting Row :" + row + " and Column : " + col);
                if (col == COL1_INDEX)
                {
                    return row;
                }else
                {
                    return data.get(row);
                }
            }

            @Override
            public String getColumnName(int column) {
                // TODO Auto-generated method stub
                return COLUMN_NAMES[column];
            }

        }

    }

Any help in solving this issue is much appreciated. Thanks in advance.

Horizontally Flowing JTable
1

1 Answers

0
votes

I've figured out a way to solve the above issue. I've added a component listener to the frame and whenever its size changes, I've looped through the tables and changed the DataModel of those tables to show only visible rows.

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ScrollPaneConstants;
import javax.swing.table.AbstractTableModel;

public class DataPanel  extends JPanel{

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    private static final int ROW_HEIGHT = 18;

    List<String> data = new ArrayList<String>();
    List<JTable> tables = new ArrayList<JTable>();
    JScrollPane scrollPane;
    JTable table, lastTable;
    JPanel boxPanel;
    JFrame f;
    int rows = 0;

    public DataPanel()
    {
        for (int i = 0; i < 50; i++)
            data.add("Blah " + i);
        DataModel tableData = new DataModel(data);
        tableData.setData(data);
        setLayout(new BorderLayout());
        /*JButton btn = new JButton("Action");
        btn.addActionListener(new ActionListener()
        {

            @Override
            public void actionPerformed(ActionEvent e) {
                // TODO Auto-generated method stub
                addTable();
            }

        });
        add(btn, BorderLayout.NORTH);*/
        boxPanel = new JPanel();
        boxPanel.setLayout(new BoxLayout(boxPanel, BoxLayout.X_AXIS));
        addTable();
        add(boxPanel, BorderLayout.CENTER);
        f = new JFrame();
        f.getContentPane().add(this);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setSize(500,500);
        f.setVisible(true);
        f.addComponentListener(adapter);
    }

    protected void addTable() {
        // TODO Auto-generated method stub
        while (rows < data.size())
        {
            System.out.println("Querying " + rows);
            List<String> newData = getData(rows);
            rows += getVisibleRowCount();
            DataModel newModel = new DataModel(newData);
            JTable newTable = new JTable(newModel);
            lastTable = newTable;
            newTable.setRowHeight(ROW_HEIGHT);
            JScrollPane newScrollPane = new JScrollPane(newTable);
            tables.add(newTable);
            newScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
            boxPanel.add(newScrollPane);
            System.out.println("Now " + rows);
        }
    }

    private ComponentAdapter adapter = new ComponentAdapter()
    {

        @Override
        public void componentResized(ComponentEvent arg0) {
            // TODO Auto-generated method stub
            //super.componentResized(arg0);
            rows = 0;
            for (JTable eachTable : tables)
            {
                List<String> newData = getData(rows);
                rows += getVisibleRowCount();
                DataModel newModel = new DataModel(newData);
                eachTable.setModel(newModel);
                ((DataModel)eachTable.getModel()).fireTableDataChanged();
            }
        }

    };

    private List<String> getData(int rows) {
        // TODO Auto-generated method stub
        List<String> newData = new ArrayList<String>();
        int j = 0;
        for(int i=0; i<data.size() && j < getVisibleRowCount(); i++)
        {
            if (i >= rows)
            {
                newData.add(data.get(i));
                j++;
            }
        }
        return newData;
    }

    private int getVisibleRowCount()
    {
        Dimension extentSize = null;
        int visibleRows = 12;
        if (null != f)
        {
            extentSize = f.getSize();
            visibleRows = (extentSize.height - 50)/ROW_HEIGHT;
        }
        return visibleRows;
    }

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

    private class DataModel extends AbstractTableModel{

        static final int COL1_INDEX = 0;
        static final int COL2_INDEX = 1;

        private final String[] COLUMN_NAMES = new String[]
                //LM2 - B & O abbreviations to be replaced by B & S. - HP   17e9355d63
                //LM2 - brokers should be able to see trader names in the order panel - HP  e4fbaa791a
                {"ID", "Name"};

        private List<String> data = new ArrayList<String>();

        public DataModel(List<String> newData)
        {
            data = newData;
        }

        public List<String> getData() {
            return data;
        }

        public void setData(List<String> data) {
            this.data = data;
        }

        @Override
        public int getColumnCount() {
            // TODO Auto-generated method stub
            return COLUMN_NAMES.length;
        }

        @Override
        public int getRowCount() {
            // TODO Auto-generated method stub
            if (null == data)
                return 0;
            return data.size();
        }

        @Override
        public Object getValueAt(int row, int col) {
            // TODO Auto-generated method stub
            if (col == COL1_INDEX)
            {
                return row;
            }else
            {
                return data.get(row);
            }
        }

        @Override
        public String getColumnName(int column) {
            // TODO Auto-generated method stub
            return COLUMN_NAMES[column];
        }

    }

}

I'm not sure if this is an efficient way, but it works and that's what I need for now. Please let me know if there's a better way to solve this issue.
Thanks again.