简体   繁体   English

如果从cellrenderer更改数据,如何计算列调整后的jTable宽度和高度

[英]How to calculate jTable width and Height after column adjustment if data is changed from a cellrenderer

I am working on an application in which I have to calculate JTable width and height, if model data gets changed at runtime and after column width adjustment, width and column is not calculated properly. 我正在开发一个应用程序,我必须计算JTable的宽度和高度,如果模型数据在运行时更改,并且在列宽调整后,宽度和列未正确计算。 Following is the sample code:- 以下是示例代码: -

** **

  • SimpleTableDemo.java SimpleTableDemo.java

** **

     package com.swing.data;

import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.TableModel;

public class SimpleTableDemo extends JPanel implements ActionListener {
    private boolean DEBUG = false;
    private JTable table = null;
    private TableColumnAdjuster app = null;
    String[] columnNames = {"First Name",
            "Last Name",
            "Sport",
            "# of Years",
            "Vegetarian"};
    Object[][] data = {
            {"Kathy", "Smith",
             "Snowboarding", new Integer(5), new Boolean(false)},
            {"John", "Doe",
             "Rowing", new Integer(3), new Boolean(true)},
            {"Sue", "Black",
             "Knitting", new Integer(2), new Boolean(false)},
            {"Jane", "White",
             "Speed reading", new Integer(20), new Boolean(true)},
            {"Joe", "Brown",
             "Pool", new Integer(10), new Boolean(false)}
            };
    CutomTableCellRenderer renderer = null;
    public SimpleTableDemo() {
        super(new GridLayout(1,0));
        table = new JTable(data, columnNames);
        table.setPreferredScrollableViewportSize(new Dimension(500, 70));
        table.setFillsViewportHeight(true);

        if (DEBUG) {
            table.addMouseListener(new MouseAdapter() {
                public void mouseClicked(MouseEvent e) {
                    printDebugData(table);
                }
            });
        }
        renderer = new CutomTableCellRenderer(table.getDefaultRenderer(Object.class));
        table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
        table.setDefaultRenderer(Object.class, renderer);
        //table.setSelectionMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS);
        JScrollPane scrollPane = new JScrollPane(table);
        app = new TableColumnAdjuster(table);
        app.adjustColumns();
       // scrollPane.setRowHeaderView(jRowTable);
        //scrollPane.setCorner(JScrollPane.UPPER_LEFT_CORNER,jRowTable.getTableHeader());
        //scrollPane.setSize(300,300);
        //Create the scroll pane and add the table to it.

        //Add the scroll pane to this panel.
        add(scrollPane);
        JButton button = new JButton("Change");
        add(button);
        button.addActionListener(this);

    }

    private void printDebugData(JTable table) {
        int numRows = table.getRowCount();
        int numCols = table.getColumnCount();
        javax.swing.table.TableModel model = table.getModel();

        System.out.println("Value of data: ");
        for (int i=0; i < numRows; i++) {
            System.out.print("    row " + i + ":");
            for (int j=0; j < numCols; j++) {
                System.out.print("  " + model.getValueAt(i, j));
            }
            System.out.println();
        }
        System.out.println("--------------------------");
    }

    /**
     * Create the GUI and show it.  For thread safety,
     * this method should be invoked from the
     * event-dispatching thread.
     */
    private static void createAndShowGUI() {
        //Create and set up the window.
        JFrame frame = new JFrame("SimpleTableDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Create and set up the content pane.
        SimpleTableDemo newContentPane = new SimpleTableDemo();
        newContentPane.setOpaque(true); //content panes must be opaque
        frame.setContentPane(newContentPane);

        //Display the window.
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        renderer.setText("Modified.............................");  
        app.adjustColumns();
        System.out.println("tableWidth:" + table.getWidth() + "tableHeight:" + table.getHeight());
    }
}

** **

  • TableColumnAdjuster.java TableColumnAdjuster.java

** **

package com.swing.data;

import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;

/*
 *  Class to manage the widths of colunmns in a table.
 *
 *  Various properties control how the width of the column is calculated.
 *  Another property controls whether column width calculation should be dynamic.
 *  Finally, various Actions will be added to the table to allow the user
 *  to customize the functionality.
 *
 *  This class was designed to be used with tables that use an auto resize mode
 *  of AUTO_RESIZE_OFF. With all other modes you are constrained as the width
 *  of the columns must fit inside the table. So if you increase one column, one
 *  or more of the other columns must decrease. Because of this the resize mode
 *  of RESIZE_ALL_COLUMNS will work the best.
 */
public class TableColumnAdjuster implements PropertyChangeListener, TableModelListener
{
    private JTable table;
    private int spacing;
    private boolean isColumnHeaderIncluded;
    private boolean isColumnDataIncluded;
    private boolean isOnlyAdjustLarger;
    private boolean isDynamicAdjustment;
    private Map<TableColumn, Integer> columnSizes = new HashMap<TableColumn, Integer>();

    /*
     *  Specify the table and use default spacing
     */
    public TableColumnAdjuster(JTable table)
    {
        this(table, 6);
    }

    /*
     *  Specify the table and spacing
     */
    public TableColumnAdjuster(JTable table, int spacing)
    {
        this.table = table;
        this.spacing = spacing;
        setColumnHeaderIncluded( true );
        setColumnDataIncluded( true );
        setOnlyAdjustLarger( true );
        setDynamicAdjustment( false );
        installActions();
    }

    /*
     *  Adjust the widths of all the columns in the table
     */
    public void adjustColumns()
    {
        TableColumnModel tcm = table.getColumnModel();

        for (int i = 0; i < tcm.getColumnCount(); i++)
        {
            adjustColumn(i);
        }
    }

    /*
     *  Adjust the width of the specified column in the table
     */
    public void adjustColumn(final int column)
    {
        TableColumn tableColumn = table.getColumnModel().getColumn(column);

        if (! tableColumn.getResizable()) return;

        int columnHeaderWidth = getColumnHeaderWidth( column );
        int columnDataWidth   = getColumnDataWidth( column );
        int preferredWidth    = Math.max(columnHeaderWidth, columnDataWidth);

        updateTableColumn(column, preferredWidth);
    }

    /*
     *  Calculated the width based on the column name
     */
    private int getColumnHeaderWidth(int column)
    {
        if (! isColumnHeaderIncluded) return 0;

        TableColumn tableColumn = table.getColumnModel().getColumn(column);
        Object value = tableColumn.getHeaderValue();
        TableCellRenderer renderer = tableColumn.getHeaderRenderer();

        if (renderer == null)
        {
            renderer = table.getTableHeader().getDefaultRenderer();
        }

        Component c = renderer.getTableCellRendererComponent(table, value, false, false, -1, column);
        return c.getPreferredSize().width;
    }

    /*
     *  Calculate the width based on the widest cell renderer for the
     *  given column.
     */
    private int getColumnDataWidth(int column)
    {
        if (! isColumnDataIncluded) return 0;

        int preferredWidth = 0;
        int maxWidth = table.getColumnModel().getColumn(column).getMaxWidth();

        for (int row = 0; row < table.getRowCount(); row++)
        {
            preferredWidth = Math.max(preferredWidth, getCellDataWidth(row, column));

            //  We've exceeded the maximum width, no need to check other rows

            if (preferredWidth >= maxWidth)
                break;
        }

        return preferredWidth;
    }

    /*
     *  Get the preferred width for the specified cell
     */
    private int getCellDataWidth(int row, int column)
    {
        //  Inovke the renderer for the cell to calculate the preferred width

        TableCellRenderer cellRenderer = table.getCellRenderer(row, column);
        Component c = table.prepareRenderer(cellRenderer, row, column);
        int width = c.getPreferredSize().width + table.getIntercellSpacing().width;

        return width;
    }

    /*
     *  Update the TableColumn with the newly calculated width
     */
    private void updateTableColumn(int column, int width)
    {
        final TableColumn tableColumn = table.getColumnModel().getColumn(column);

        if (! tableColumn.getResizable()) return;

        width += spacing;

        //  Don't shrink the column width

        if (isOnlyAdjustLarger)
        {
            width = Math.max(width, tableColumn.getPreferredWidth());
        }

        columnSizes.put(tableColumn, new Integer(tableColumn.getWidth()));
        table.getTableHeader().setResizingColumn(tableColumn);
        tableColumn.setWidth(width);
    }

    /*
     *  Restore the widths of the columns in the table to its previous width
     */
    public void restoreColumns()
    {
        TableColumnModel tcm = table.getColumnModel();

        for (int i = 0; i < tcm.getColumnCount(); i++)
        {
            restoreColumn(i);
        }
    }

    /*
     *  Restore the width of the specified column to its previous width
     */
    private void restoreColumn(int column)
    {
        TableColumn tableColumn = table.getColumnModel().getColumn(column);
        Integer width = columnSizes.get(tableColumn);

        if (width != null)
        {
            table.getTableHeader().setResizingColumn(tableColumn);
            tableColumn.setWidth( width.intValue() );
        }
    }

    /*
     *  Indicates whether to include the header in the width calculation
     */
    public void setColumnHeaderIncluded(boolean isColumnHeaderIncluded)
    {
        this.isColumnHeaderIncluded = isColumnHeaderIncluded;
    }

    /*
     *  Indicates whether to include the model data in the width calculation
     */
    public void setColumnDataIncluded(boolean isColumnDataIncluded)
    {
        this.isColumnDataIncluded = isColumnDataIncluded;
    }

    /*
     *  Indicates whether columns can only be increased in size
     */
    public void setOnlyAdjustLarger(boolean isOnlyAdjustLarger)
    {
        this.isOnlyAdjustLarger = isOnlyAdjustLarger;
    }

    /*
     *  Indicate whether changes to the model should cause the width to be
     *  dynamically recalculated.
     */
    public void setDynamicAdjustment(boolean isDynamicAdjustment)
    {
        //  May need to add or remove the TableModelListener when changed

        if (this.isDynamicAdjustment != isDynamicAdjustment)
        {
            if (isDynamicAdjustment)
            {
                table.addPropertyChangeListener( this );
                table.getModel().addTableModelListener( this );
            }
            else
            {
                table.removePropertyChangeListener( this );
                table.getModel().removeTableModelListener( this );
            }
        }

        this.isDynamicAdjustment = isDynamicAdjustment;
    }
//
//  Implement the PropertyChangeListener
//
    public void propertyChange(PropertyChangeEvent e)
    {
        //  When the TableModel changes we need to update the listeners
        //  and column widths

        if ("model".equals(e.getPropertyName()))
        {
            TableModel model = (TableModel)e.getOldValue();
            model.removeTableModelListener( this );

            model = (TableModel)e.getNewValue();
            model.addTableModelListener( this );
            adjustColumns();
        }
    }
//
//  Implement the TableModelListener
//
    public void tableChanged(TableModelEvent e)
    {
        if (! isColumnDataIncluded) return;

        //  A cell has been updated

        if (e.getType() == TableModelEvent.UPDATE)
        {
            int column = table.convertColumnIndexToView(e.getColumn());

            //  Only need to worry about an increase in width for this cell

            if (isOnlyAdjustLarger)
            {
                int row = e.getFirstRow();
                TableColumn tableColumn = table.getColumnModel().getColumn(column);

                if (tableColumn.getResizable())
                {
                    int width = getCellDataWidth(row, column);
                    updateTableColumn(column, width);
                }
            }

            //  Could be an increase of decrease so check all rows

            else
            {
                adjustColumn( column );
            }
        }

        //  The update affected more than one column so adjust all columns

        else
        {
            adjustColumns();
        }
    }

    /*
     *  Install Actions to give user control of certain functionality.
     */
    private void installActions()
    {
        installColumnAction(true,  true,  "adjustColumn",   "control ADD");
        installColumnAction(false, true,  "adjustColumns",  "control shift ADD");
        installColumnAction(true,  false, "restoreColumn",  "control SUBTRACT");
        installColumnAction(false, false, "restoreColumns", "control shift SUBTRACT");

        installToggleAction(true,  false, "toggleDynamic",  "control MULTIPLY");
        installToggleAction(false, true,  "toggleLarger",   "control DIVIDE");
    }

    /*
     *  Update the input and action maps with a new ColumnAction
     */
    private void installColumnAction(
        boolean isSelectedColumn, boolean isAdjust, String key, String keyStroke)
    {
        Action action = new ColumnAction(isSelectedColumn, isAdjust);
        KeyStroke ks = KeyStroke.getKeyStroke( keyStroke );
        table.getInputMap().put(ks, key);
        table.getActionMap().put(key, action);
    }

    /*
     *  Update the input and action maps with new ToggleAction
     */
    private void installToggleAction(
        boolean isToggleDynamic, boolean isToggleLarger, String key, String keyStroke)
    {
        Action action = new ToggleAction(isToggleDynamic, isToggleLarger);
        KeyStroke ks = KeyStroke.getKeyStroke( keyStroke );
        table.getInputMap().put(ks, key);
        table.getActionMap().put(key, action);
    }

    /*
     *  Action to adjust or restore the width of a single column or all columns
     */
    class ColumnAction extends AbstractAction
    {
        private boolean isSelectedColumn;
        private boolean isAdjust;

        public ColumnAction(boolean isSelectedColumn, boolean isAdjust)
        {
            this.isSelectedColumn = isSelectedColumn;
            this.isAdjust = isAdjust;
        }

        @Override
        public void actionPerformed(ActionEvent e)
        {
            //  Handle selected column(s) width change actions

            if (isSelectedColumn)
            {
                int[] columns = table.getSelectedColumns();

                for (int i = 0; i < columns.length; i++)
                {
                    if (isAdjust)
                        adjustColumn(columns[i]);
                    else
                        restoreColumn(columns[i]);
                }
            }
            else
            {
                if (isAdjust)
                    adjustColumns();
                else
                    restoreColumns();
            }
        }
    }

    /*
     *  Toggle properties of the TableColumnAdjuster so the user can
     *  customize the functionality to their preferences
     */
    class ToggleAction extends AbstractAction
    {
        private boolean isToggleDynamic;
        private boolean isToggleLarger;

        public ToggleAction(boolean isToggleDynamic, boolean isToggleLarger)
        {
            this.isToggleDynamic = isToggleDynamic;
            this.isToggleLarger = isToggleLarger;
        }

        @Override
        public void actionPerformed(ActionEvent e)
        {
            if (isToggleDynamic)
            {
                setDynamicAdjustment(! isDynamicAdjustment);
                return;
            }

            if (isToggleLarger)
            {
                setOnlyAdjustLarger(! isOnlyAdjustLarger);
                return;
            }
        }
    }
}

** **

  • CutomTableCellRenderer.java CutomTableCellRenderer.java

** **

package com.swing.data;

import java.awt.Color;
import java.awt.Component;

import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
public class CutomTableCellRenderer extends DefaultTableCellRenderer 
{   
    private TableCellRenderer mWrappedRenderer; 
    private String text = "Original";
    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public CutomTableCellRenderer(TableCellRenderer pWrappedRenderer) { 
        mWrappedRenderer = pWrappedRenderer; 
        } 

    public Component getTableCellRendererComponent
       (JTable table, Object value, boolean isSelected,
       boolean hasFocus, int row, int column) 
    {
        Component cell = mWrappedRenderer.getTableCellRendererComponent(table, value, isSelected,
                   hasFocus, row, column); 


            if( row == 1 )
            {

                JLabel label = (JLabel)cell;
                label.setText(text);
            }
            else
            {
                cell.setBackground( Color.white );
            }

        return cell;
    }
}

From the above code the actual data in the model doesn't gets changed. 从上面的代码中,模型中的实际数据不会改变。 But table width and height is not calculated correctly on first click of change button. 但是,首次单击更改按钮时,无法正确计算表格宽度和高度。 On next change click the modified table width and height is shown. 在下一次更改时,单击已修改的表格宽度和高度。 I am very new to this. 我对此很新。

How can I retrieve the actual width and height of JTable if data is changed from cell renderer? 如果从单元格渲染器更改数据,如何检索JTable的实际宽度和高度?

How can I calculate table width and height properly. 如何正确计算桌子的宽度和高度。

In the ActionListener's code you have 在ActionListener的代码中

renderer.setText("Modified.............................");
app.adjustColumns();
System.out.println("tableWidth:" + table.getWidth() + "tableHeight:" + table.getHeight());

The call to app.adjustColumns() only triggers the new layout, the adjusted columns are only visible after the event is completed, ie after the method is done and the output is written. app.adjustColumns()的调用仅触发新布局,调整后的列仅在事件完成后可见,即在方法完成并写入输出之后。

You may easliy verify it by encapsulating the output into another event: 您可以通过将输出封装到另一个事件中来轻松验证它:

System.out.println("PRE  tableWidth:" + table.getWidth() + "tableHeight:" + table.getHeight());
SwingUtilities.invokeLater(new Runnable() {
    @Override
    public void run() {
        System.out.println("POST tableWidth:" + table.getWidth() + "tableHeight:" + table.getHeight());
    }
});

which yields 产量

PRE  tableWidth:390tableHeight:80
POST tableWidth:710tableHeight:80

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

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