当前位置: 首页 > 知识库问答 >
问题:

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

经兴安
2023-03-14

为什么我不能用鼠标取消选择/选择JTable布尔字段,如果我使用键盘进入字段,我总是可以用空格键取消选择/选择。但在鼠标上,它有时起作用,有时不起作用。

更复杂的是,is_compilitation布尔字段的基础数据为true/false,但所有其他基础字段的基础数据为1/0,is_compilitation字段似乎总是正常工作,但其他字段是零星的。

试着注释出不同的代码,但运气不佳。我在这里发布了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个答案

孙梓
2023-03-14

该问题是由于使用了https://tips4java.wordpress.com/2008/11/10/table-columnadjuster/中的TableColumnAdjuster代码造成的,该代码通常用作

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

我无法弄清楚TableColumnAdjorster的实际问题是什么,但最后我从它提取了一些代码,并为它添加了一个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();
    }
}
 类似资料:
  • 本文向大家介绍RadioButton实现选择后可取消选择,包括了RadioButton实现选择后可取消选择的使用技巧和注意事项,需要的朋友参考一下 Radiobutton是一种单选按钮,是由于RadioGroup管理下的一组按钮,所以一旦其中的一个button选中,再点击,就不能取消,想要取消调用Radiobutton的setchecked(boolean isChecked)的方法。 在网上找了

  • 目前正在使用React Native,并尝试使用React Native nfc ios和React national nfc,以便我可以在ios和Android之间进行跨设备通信。我发现他们无法沟通,但我认为这是由于一个更广泛的问题(因为其他现有的应用程序也无法工作)。 如果我在iPhone7上下载NFC阅读器应用程序,在Android上下载NFC写入器应用程序,它们就无法通信。这是为什么呢?

  • 如果你曾经使用过构建工具,你可能会对遇到的问题感到很沮丧,构建工具不是应该自动帮你完成项目的构建吗?你不得不向性能、扩展性等妥协。 比如你在构建一个项目的发布版本时,你要把一个文件拷贝到指定的位置,你在项目的元数据那里添加了版本的描述,如果版本号匹配一个特定的数字时,就把文件从A拷贝到B处。如果你依赖XML来构建,你要实现这个任务就像噩梦一样,你只能通过非标准的机制来添加一些脚本到构建中,结果就是

  • 来源:https://github.com/atom-china/manual 这个世界上有那么多种编辑器,为什么你要花时间学习和使用 Atom 呢? 虽然 Sublime 和 TextMate 之类的编辑器已经非常好用了,但它们仅提供了很有限的拓展性。而在另一个极端,Emacs 和 Vim 提供了灵活的拓展性,但它们并不是很友好,需要使用专用的编程语言来配置和拓展。 我们觉得我们可以做得更好。我

  • 为什么选择 NuxtJS

  • Nginx 是一个高性能的 Web 和反向代理服务器, 它具有有很多非常优越的特性: 作为 Web 服务器:相比 Apache,Nginx 使用更少的资源,支持更多的并发连接,体现更高的效率,这点使 Nginx 尤其受到虚拟主机提供商的欢迎。能够支持高达 50,000 个并发连接数的响应,感谢 Nginx 为我们选择了 epoll and kqueue 作为开发模型. 作为负载均衡服务器:Ngin