为什么我无法使用鼠标可靠地取消选择/选择JTable布尔字段

时间:2018-04-11 17:40:53

标签: java swing jtable

为什么我无法使用鼠标可靠地取消选择/选择JTable布尔字段,如果我使用键盘进入字段,我总是可以使用空格键取消选择/选择。但是有时鼠标会起作用,有时甚至不起作用。

为了使事情进一步复杂化,IS_COMPILATION布尔字段的基础数据为true / false,但对于所有其他基础字段为1/0,IS_COMPILATION字段似乎始终正常,但其他字段是零星的。

尝试在没有太多运气的情况下评论各种代码。我在这里发布了JTable和TableModel子类。

import com.jthink.songkong.text.TextLabel;

import javax.swing.*;
import javax.swing.table.TableCellRenderer;
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.*;
import java.io.IOException;
import java.util.ArrayList;

public class EditSongsTable extends JTable
{
    public EditSongsTable()
    {
        //Disable F2 key for editing and replace with Enter character.
        getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(java.awt.event.
                KeyEvent.VK_F2, 0), "none");
        getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(java.awt.event.
                KeyEvent.VK_ENTER, 0), "startEditing");

        //Changes Editor for Strings
        setDefaultEditor(Object.class, new TextFieldCellEditor());

        CopyAction copy   = new CopyAction(this);
        PasteAction paste = new PasteAction(this);

        //Add Copy/Paste Popup Menu
        final JPopupMenu pm = new JPopupMenu();
        pm.add(copy);
        pm.add(paste);

        //Replace default table actions with our copy/paste actions
        getActionMap().put("copy", copy);
        getActionMap().put("paste", paste);


        addMouseListener(new MouseAdapter()
        {
            @Override
            public void mouseClicked(MouseEvent e)
            {
                if (e.isPopupTrigger())
                {
                    highlightCells(e);
                    doPopup(e);
                }
            }

            @Override
            public void mouseReleased(MouseEvent e)
            {
                if (e.isPopupTrigger())
                {
                    highlightCells(e);
                    doPopup(e);
                }
            }

            protected void doPopup(MouseEvent e)
            {
                pm.show(e.getComponent(), e.getX(), e.getY());
            }

            /**
             * Highlight cell if nothing selected
             *
             * @param e
             */
            protected void highlightCells(MouseEvent e)
            {
                JTable table = (JTable) e.getSource();
                if(table.getSelectedRows().length==0 || table.getSelectedColumns().length==0)
                {
                    Point point = e.getPoint();
                    int row = table.rowAtPoint(point);
                    int col = table.columnAtPoint(point);

                    table.setRowSelectionInterval(row, row);
                    table.setColumnSelectionInterval(col, col);
                }
            }
        });
    }



    /**
     * RowNo column needs a different renderer from default
     *
     * @param row
     * @param column
     * @return the row label renderer
     */
    @Override
    public TableCellRenderer getCellRenderer(int row, int column)
    {
        if (column == 0)
        {
            return TableRowLabelRenderer.getInstanceOf();
        }
        else
        {
            return super.getCellRenderer(row, column);
        }
    }


    class CopyAction extends AbstractAction
    {

        private JTable table;

        public CopyAction(JTable table)
        {
            this.table = table;
            putValue(NAME, TextLabel.COPYBUTTON.getMsg());
            putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_C, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
        }

        @Override
        public void actionPerformed(ActionEvent e)
        {
            Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
            java.util.List<Object> data = new ArrayList<>();
            final int[] rows = getSelectedRows();
            for (int row : rows)
            {
                final int[] cols = getSelectedColumns();
                for (int col : cols)
                {
                    data.add(table.getValueAt(row, col));
                }
            }
            cb.setContents(new CellTransferable(data), null);
        }
    }

    class PasteAction extends AbstractAction
    {

        private JTable table;

        public PasteAction(JTable tbl)
        {
            putValue(NAME, TextLabel.PASTEBUTTON.getMsg());
            putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_V, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
            table = tbl;

            final Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();

            cb.addFlavorListener(new FlavorListener()
            {
                @Override
                public void flavorsChanged(FlavorEvent e)
                {
                    setEnabled(cb.isDataFlavorAvailable(CellTransferable.CELL_DATA_FLAVOR)
                            || cb.isDataFlavorAvailable(DataFlavor.stringFlavor));
                }
            });
            setEnabled(cb.isDataFlavorAvailable(CellTransferable.CELL_DATA_FLAVOR)
                    || cb.isDataFlavorAvailable(DataFlavor.stringFlavor));
        }

        @Override
        public void actionPerformed(ActionEvent e)
        {
            Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
            if (cb.isDataFlavorAvailable(CellTransferable.CELL_DATA_FLAVOR))
            {
                try
                {
                    int i =0;
                    java.util.List<Object> values = (java.util.List<Object>) cb.getData(CellTransferable.CELL_DATA_FLAVOR);
                    final int[] rows = getSelectedRows();
                    for (int row : rows)
                    {
                        final int[] cols = getSelectedColumns();
                        for (int col : cols)
                        {
                            if(i>=values.size())
                            {
                                i=0;
                            }
                            if(table.getColumnClass(col)==Boolean.class)
                            {
                                if(values.get(i) instanceof Boolean)
                                {
                                    table.setValueAt(values.get(i), row, col);
                                    i++;
                                }
                            }
                            else
                            {
                                if(values.get(i) instanceof Boolean)
                                {
                                    table.setValueAt(((Boolean)values.get(i)).toString(), row, col);
                                }
                                else
                                {
                                    table.setValueAt(values.get(i), row, col);
                                }
                                i++;
                            }
                        }
                    }
                }
                catch (UnsupportedFlavorException | IOException ex)
                {
                    ex.printStackTrace();
                }
            }
            else if(cb.isDataFlavorAvailable(DataFlavor.stringFlavor))
            {
                try
                {
                    String data = (String)cb.getData(DataFlavor.stringFlavor);
                    final int[] rows = getSelectedRows();
                    for (int row : rows)
                    {
                        final int[] cols = getSelectedColumns();
                        for (int col : cols)
                        {

                            table.setValueAt(data, row, col);
                        }
                    }
                }
                catch (UnsupportedFlavorException | IOException ex)
                {
                    ex.printStackTrace();
                }
            }
        }

    }


    public static class CellTransferable implements Transferable
    {

        public static final DataFlavor CELL_DATA_FLAVOR = new DataFlavor(Object.class, "application/x-cell-value");

        private Object cellValue;

        public CellTransferable(Object cellValue)
        {
            this.cellValue = cellValue;
        }

        @Override
        public DataFlavor[] getTransferDataFlavors()
        {
            return new DataFlavor[]{CELL_DATA_FLAVOR};
        }

        @Override
        public boolean isDataFlavorSupported(DataFlavor flavor)
        {
            return CELL_DATA_FLAVOR.equals(flavor);
        }

        @Override
        public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException
        {
            if (!isDataFlavorSupported(flavor))
            {
                throw new UnsupportedFlavorException(flavor);
            }
            return cellValue;
        }
    }
}

表格型号

import com.google.common.collect.ArrayTable;
import com.google.common.collect.Table;
import com.jthink.songkong.text.SongFieldDataType;
import com.jthink.songkong.text.SongFieldName;
import com.jthink.songlayer.Song;
import com.jthink.songlayer.SongFieldKey;

import javax.swing.table.DefaultTableModel;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.Vector;

import static com.jthink.songkong.analyse.toplevelanalyzer.EditSongsController.EDIT_MULTI_VALUE;

    /**
     * Edit Songs table model
     *
     */
    public class EditSongsTableModel extends DefaultTableModel
    {
        private Table<Song, SongFieldName, String> edits = null;
        private List<SongFieldName> fields;
        private List<Song>         songs;

        public EditSongsTableModel(Set<SongFieldName> fields, List<Song> songs)
        {
            super(songs.size(), fields.size());
            this.fields= new ArrayList<>(fields);
            this.songs=songs;
            edits = ArrayTable.create(songs, fields);

            for(Song song:songs)
            {
                song.setNewFilename(song.getFilename());
            }

            Vector<String> columnNames = new Vector<>();
            columnNames.add("#");
            for (SongFieldName next : fields)
            {
                columnNames.add(next.getName());
            }
            this.setColumnIdentifiers(columnNames);
        }

        /**
         * Get the value relating this table field, making adjustments for certain fields for display
         *
         * @param row
         * @param column
         * @return
         */
        public Object getValueAt(int row, int column)
        {


            if(column==0)
            {
                return String.valueOf(row + 1);
            }
            else
            {
                SongFieldName sfn = fields.get(column -1);
                Song song = songs.get(row);

                if(sfn.getSongFieldKey()== SongFieldKey.FILENAME)
                {
                    return song.getNewFilename();
                }
                else if (sfn.getDataType() == SongFieldDataType.BOOLEAN)
                {
                    if(sfn==SongFieldName.IS_COMPILATION)
                    {
                        return Boolean.valueOf(song.getFieldValueOrEmptyString(sfn.getSongFieldKey()));
                    }
                    else
                    {
                        if(song.getFieldValueOrEmptyString(sfn.getSongFieldKey()).equals("1"))
                        {
                            return Boolean.TRUE;
                        }
                        else
                        {
                            return Boolean.FALSE;
                        }
                    }
                }
                else
                {
                    return song.getFieldValueTripleSemiColonSeparatedOrEmptyString(sfn.getSongFieldKey());
                }
            }
        }

        @Override
        public void setValueAt(Object val, int row, int column)
        {
            SongFieldName sfn = fields.get(column - 1);
            Song song = songs.get(row);

            if(edits.get(song,sfn)==null)
            {
                //Save Original Value
                edits.put(song, sfn, song.getFieldValueOrEmptyString(sfn.getSongFieldKey()));
            }

            if(sfn.getSongFieldKey()== SongFieldKey.FILENAME)
            {
                song.setNewFilename((String) val);
            }
            else if(sfn.getDataType()== SongFieldDataType.BOOLEAN)
            {
                if(sfn==SongFieldName.IS_COMPILATION)
                {
                    song.setField(sfn.getSongFieldKey(), ((Boolean) val).toString());
                }
                else
                {
                    if(val==Boolean.TRUE)
                    {
                        song.setField(sfn.getSongFieldKey(), "1");
                    }
                    else
                    {
                        song.setField(sfn.getSongFieldKey(), "0");
                    }
                }
            }
            else
            {
                song.setField(sfn.getSongFieldKey(),
                        ((String) val).replace(EDIT_MULTI_VALUE, "\0"));
            }
            fireTableCellUpdated(row, column);
        }

        public Class getColumnClass(int columnIndex)
        {
            if(columnIndex == 0)
            {
                return String.class;
            }
            else
            {
                SongFieldName sfn = fields.get(columnIndex - 1);
                if (sfn.getDataType() == SongFieldDataType.BOOLEAN)
                {
                    return Boolean.class;
                }
                else
                {
                    return super.getColumnClass((columnIndex));
                }
            }
        }

        /**
         * Cannot Edit table Row Header
         *
         * @param rowIndex
         * @param columnIndex
         * @return
         */
        public boolean isCellEditable(int rowIndex, int columnIndex)
        {
            return columnIndex > 0;
        }

        /**
         * Reset to original data
         *
         * @return
         */
        public boolean reset()
        {
            for(Table.Cell<Song, SongFieldName, String> cell:edits.cellSet())
            {
                if(cell.getValue()!=null)
                {
                    SongFieldName sfn = cell.getColumnKey();
                    if(sfn.getSongFieldKey()== SongFieldKey.FILENAME)
                    {
                        cell.getRowKey().setNewFilename(cell.getValue());
                    }
                    else
                    {
                        cell.getRowKey().setField(cell.getColumnKey().getSongFieldKey(), cell.getValue());
                    }
                }
            }
            fireTableDataChanged();
            return true;
        }
    }

TextFieldCellEditor

import javax.swing.*;
import javax.swing.text.Caret;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.util.EventObject;

/**
 * For String fields typing in keybaord when field has focus causes current value to be removed and editing to start
 * immediatley
 *
 */
public class TextFieldCellEditor extends DefaultCellEditor
{
    private EventObject event;

    public TextFieldCellEditor()
    {
        super(new JTextField());
    }

    public final Component getTableCellEditorComponent(final JTable table, final Object val,
                                                       final boolean isSelected,
                                                       final int row, final int column)
    {
        //If entered field using keyboard clear the current value
        final JTextField editField = (JTextField) super.getTableCellEditorComponent(table,
                val,
                isSelected,
                row,
                column);
        if (event instanceof KeyEvent)
        {
            final Caret caret = editField.getCaret();
            caret.setDot(0);
            editField.setText("");
        }
        return editField;
    }

    public boolean isCellEditable(EventObject anEvent)
    {
        event = anEvent;
        return super.isCellEditable(anEvent);
    }
}

1 个答案:

答案 0 :(得分:0)

问题是由于使用了来自https://tips4java.wordpress.com/2008/11/10/table-column-adjuster/的TableColumnAdjuster代码,该代码通常用作

TableColumnAdjuster tca = new TableColumnAdjuster(table);
tca.adjustColumns();

我无法解决TableColumnAdjuster的实际问题,但最后我从中提取了一些代码并添加了一个JTable的抽象子类,然后我为我的用例扩展。我需要它来设置合理的起始列宽度,我还调整为设置 preferredSize 而不是 size 除了某些特定的列。

这解决了这个问题,我现在可以使用鼠标可靠地禁用/启用复选框。

public class CorrectlySizedTable extends JTable
{
    public void adjustColumns()
    {
        TableColumnModel tcm = getColumnModel();

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

    public void adjustColumn(final int column)
    {
        TableColumn tableColumn = 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)
    {

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

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

        Component c = renderer.getTableCellRendererComponent(this, 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)
    {

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

        for (int row = 0; row < 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 = getCellRenderer(row, column);
        Component c = prepareRenderer(cellRenderer, row, column);
        int width = c.getPreferredSize().width + getIntercellSpacing().width;

        return width;
    }

    private void updateTableColumn(int column, int width)
    {
        final TableColumn tableColumn = getColumnModel().getColumn(column);
        MainWindow.logger.severe("ColumnWidth:"+width);
        tableColumn.setPreferredWidth(width);
        if(column==0 || getColumnClass(column)==Boolean.class)
        {
            tableColumn.setMaxWidth(width);
        }
    }

    public void setModel(TableModel dataModel) {
        super.setModel(dataModel);
        adjustColumns();
    }
}