0

JTable の幅と高さを計算する必要があるアプリケーションで作業しています。実行時にモデル データが変更され、列幅の調整後に幅と列が正しく計算されない場合。以下はサンプルコードです:-

**

  • 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

**

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

**

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;
    }
}

上記のコードから、モデル内の実際のデータは変更されません。ただし、変更ボタンの最初のクリックでは、テーブルの幅と高さが正しく計算されません。次に変更すると、変更されたテーブルの幅と高さが表示されます。私はこれに非常に慣れていません。

データがセルレンダラーから変更された場合、JTable の実際の幅と高さを取得するにはどうすればよいですか?

テーブルの幅と高さを正しく計算するにはどうすればよいですか。

4

1 に答える 1

2

ActionListenerのコードには

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

toを呼び出すとapp.adjustColumns()、新しいレイアウトのみがトリガーされます。調整された列は、イベントが完了した後、つまりメソッドが実行されて出力が書き込まれた後にのみ表示されます。

出力を別のイベントにカプセル化することで、簡単に確認できます。

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());
    }
});

これは

PRE  tableWidth:390tableHeight:80
POST tableWidth:710tableHeight:80
于 2013-03-07T14:37:00.967 に答える