【问题标题】:How to swap value of cell in jtable by drag and drop如何通过拖放交换jtable中单元格的值
【发布时间】:2014-06-24 08:39:00
【问题描述】:

我想在同一列中将我的表的数据从一个表交换到另一个表(注意:我只有两列)。

我的问题是我无法交换值。另外,我希望仅在同一列上启用交换,否则,表值将重置为其原始值。

这是我的代码:

    JTable table_1 = new JTable(model);
table_1.setPreferredScrollableViewportSize(new Dimension(300, 120));
table_1.setDragEnabled(true);  
table_1.setDropMode(DropMode.USE_SELECTION);  
table_1.setTransferHandler(new TransferHelper()); 
table_1.setRowSelectionAllowed(false);
table_1.setCellSelectionEnabled(true);

我的 TransferHelper 类:

class TransferHelper extends TransferHandler {  

    private static final long serialVersionUID = 1L;

    public TransferHelper() {  
    }  

    @Override  
    public int getSourceActions(JComponent c) {  
        return MOVE;  
    }  

    @Override  
    protected Transferable createTransferable(JComponent source) {  
        String data = (String) ((JTable) source).getModel().getValueAt(((JTable) source).getSelectedRow(), ((JTable) source).getSelectedColumn());
        return new StringSelection(data);  
    }  

    @Override  
    protected void exportDone(JComponent source, Transferable data, int action) {  
        ((JTable) source).getModel().setValueAt("", ((JTable) source).getSelectedRow(), ((JTable) source).getSelectedColumn());  
    }  

    @Override  
    public boolean canImport(TransferSupport support) {  
        return true;  
    }  

    @Override  
    public boolean importData(TransferSupport support) {  
        JTable jt = (JTable) support.getComponent();  
        try {
            jt.setValueAt(support.getTransferable().getTransferData(DataFlavor.stringFlavor), jt.getSelectedRow(), jt.getSelectedColumn());  
        } catch (UnsupportedFlavorException ex) {  

        } catch (IOException ex) {  

        }  
        return super.importData(support);  
    }  
}  

【问题讨论】:

    标签: java swing drag-and-drop


    【解决方案1】:

    拖放不是一个简单的过程,它相当复杂和复杂。这种复杂性带来了灵活性。

    以这种方式交换值与“移动”本身不同。移动某物时,您从源中取出它并将其放置在目标中,这里我们在源和目标之间交换值,这意味着我们需要比通常通过 API 获得的更多信息。

    首先,您将需要一个自定义类来保存要导出的数据,因为我们正在移动数据,这将需要一些额外的信息,特别是源组件...

    以下只是一个简单的包装器。我们可以完全导出JTable,但我想演示一个拖放的基本概念...

    import javax.swing.JTable;
    
    public class CellData {
        private JTable table;
    
        public CellData(JTable table) {
            this.table = table;
        }
    
        public int getColumn() {
            return table.getSelectedColumn();
        }
    
        public String getValue() {
            int row = table.getSelectedRow();
            int col = table.getSelectedColumn();
            return (String) table.getValueAt(row, col);
        }
    
        public JTable getTable() {
            return table;
        }
    
    }
    

    接下来,我们需要一个自定义的Transferable 来管理我们的数据...

    import java.awt.datatransfer.DataFlavor;
    import java.awt.datatransfer.Transferable;
    import java.awt.datatransfer.UnsupportedFlavorException;
    import java.io.IOException;
    
    public class CellDataTransferable implements Transferable {
    
        public static final DataFlavor CELL_DATA_FLAVOR = createConstant(CellData.class, "application/x-java-celldata");
        private CellData cellData;
    
        public CellDataTransferable(CellData cellData) {
            this.cellData = cellData;
        }
    
        @Override
        public DataFlavor[] getTransferDataFlavors() {
            return new DataFlavor[]{CELL_DATA_FLAVOR};
        }
    
        @Override
        public boolean isDataFlavorSupported(DataFlavor flavor) {
            boolean supported = false;
            for (DataFlavor available : getTransferDataFlavors()) {
                if (available.equals(flavor)) {
                    supported = true;
                }
            }
            return supported;
        }
    
        @Override
        public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
            return cellData;
        }
    
        static protected DataFlavor createConstant(Class clazz, String name) {
            try {
                return new DataFlavor(clazz, name);
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    
    }
    

    最后,TransferHandler....

    public class TransferHelper extends TransferHandler {
    
        private static final long serialVersionUID = 1L;
    
        public TransferHelper() {
        }
    
        @Override
        public int getSourceActions(JComponent c) {
            return MOVE;
        }
    
        @Override
        protected Transferable createTransferable(JComponent source) {
            // Create the transferable
            // Because I'm hacking a little, I've included the source table...
            JTable table = (JTable) source;
            return new CellDataTransferable(new CellData(table));
        }
    
        @Override
        protected void exportDone(JComponent source, Transferable data, int action) {
        }
    
        @Override
        public boolean canImport(TransferSupport support) {
            // Reject the import by default...
            boolean canImport = false;
            // Can only import into another JTable
            Component comp = support.getComponent();
            if (comp instanceof JTable) {
                JTable table = (JTable) comp;
                // Need the location where the drop might occur
                DropLocation dl = support.getDropLocation();
                Point dp = dl.getDropPoint();
                // Get the column at the drop point
                int dragColumn = table.columnAtPoint(dp);
                try {
                    // Get the Transferable, we need to check
                    // the constraints
                    Transferable t = support.getTransferable();
                    CellData cd = (CellData) t.getTransferData(CellDataTransferable.CELL_DATA_FLAVOR);
                    // Make sure we're not dropping onto ourselves...
                    if (cd.getTable() != table) {
                        // Do the columns match...?
                        if (dragColumn == cd.getColumn()) {
                            canImport = true;
                        }
                    }
                } catch (UnsupportedFlavorException | IOException ex) {
                    ex.printStackTrace();
                }
            }
            return canImport;
        }
    
        @Override
        public boolean importData(TransferSupport support) {
            // Import failed for some reason...
            boolean imported = false;
            // Only import into JTables...
            Component comp = support.getComponent();
            if (comp instanceof JTable) {
                JTable target = (JTable) comp;
                // Need to know where we are importing to...
                DropLocation dl = support.getDropLocation();
                Point dp = dl.getDropPoint();
                int dropCol = target.columnAtPoint(dp);
                int dropRow = target.rowAtPoint(dp);
                try {
                    // Get the Transferable at the heart of it all
                    Transferable t = support.getTransferable();
                    CellData cd = (CellData) t.getTransferData(CellDataTransferable.CELL_DATA_FLAVOR);
                    if (cd.getTable() != target) {
                        // Make sure the columns match
                        if (dropCol == cd.getColumn()) {
                            // Get the data from the "dropped" table
                            String exportValue = (String) target.getValueAt(dropRow, dropCol);
                            // Get the data from the "dragged" table
                            String importValue = cd.getValue();
                            // This is where we swap the values...
                            // Set the target/dropped tables value
                            target.setValueAt(importValue, dropRow, dropCol);
    
                            // Set the source/dragged tables values
                            JTable source = cd.getTable();
                            int row = source.getSelectedRow();
                            int col = source.getSelectedColumn();
                            source.setValueAt(exportValue, row, col);
    
                            imported = true;
                        }
                    }
                } catch (UnsupportedFlavorException | IOException ex) {
                    ex.printStackTrace();
                }
    
            }
            return imported;
        }
    }
    

    阅读 cmets :P

    最后,一个可运行的例子……

    import java.awt.Component;
    import java.awt.EventQueue;
    import java.awt.GridLayout;
    import java.awt.Point;
    import java.awt.datatransfer.DataFlavor;
    import java.awt.datatransfer.Transferable;
    import java.awt.datatransfer.UnsupportedFlavorException;
    import java.io.IOException;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import javax.swing.DropMode;
    import javax.swing.JComponent;
    import javax.swing.JFrame;
    import javax.swing.JScrollPane;
    import javax.swing.JTable;
    import javax.swing.TransferHandler;
    import static javax.swing.TransferHandler.MOVE;
    import javax.swing.TransferHandler.TransferSupport;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    import javax.swing.table.DefaultTableModel;
    
    public class TableSwap {
    
        public static void main(String[] args) {
            new TableSwap();
        }
    
        public TableSwap() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    }
    
                    JTable t1 = createTable(0);
                    JTable t2 = createTable(20);
    
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setLayout(new GridLayout(0, 2));
                    frame.add(new JScrollPane(t1));
                    frame.add(new JScrollPane(t2));
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        protected JTable createTable(int startAt) {
    
            DefaultTableModel model = new DefaultTableModel(0, 2);
            for (int index = 0; index < 10; index++) {
                model.addRow(new Object[]{"0x" + (index + startAt), "1x" + (index + startAt)});
            }
    
            JTable table = new JTable(model);
            table.setDragEnabled(true);
            table.setDropMode(DropMode.USE_SELECTION);
            table.setTransferHandler(new TransferHelper());
            table.setRowSelectionAllowed(false);
            table.setCellSelectionEnabled(true);
    
            return table;
        }
    
    }
    

    更新为仅支持单个表格

    import java.awt.Component;
    import java.awt.EventQueue;
    import java.awt.GridLayout;
    import java.awt.Point;
    import java.awt.datatransfer.DataFlavor;
    import java.awt.datatransfer.Transferable;
    import java.awt.datatransfer.UnsupportedFlavorException;
    import java.io.IOException;
    import javax.swing.DropMode;
    import javax.swing.JComponent;
    import javax.swing.JFrame;
    import javax.swing.JScrollPane;
    import javax.swing.JTable;
    import javax.swing.TransferHandler;
    import static javax.swing.TransferHandler.MOVE;
    import javax.swing.TransferHandler.TransferSupport;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    import javax.swing.table.DefaultTableModel;
    
    public class TableSwap {
    
        public static void main(String[] args) {
            new TableSwap();
        }
    
        public TableSwap() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    }
    
                    JTable t1 = createTable(0);
    
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.add(new JScrollPane(t1));
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        protected JTable createTable(int startAt) {
    
            DefaultTableModel model = new DefaultTableModel(0, 2);
            for (int index = 0; index < 10; index++) {
                model.addRow(new Object[]{"0x" + (index + startAt), "1x" + (index + startAt)});
            }
    
            JTable table = new JTable(model);
            table.setDragEnabled(true);
            table.setDropMode(DropMode.USE_SELECTION);
            table.setTransferHandler(new TransferHelper());
            table.setRowSelectionAllowed(false);
            table.setCellSelectionEnabled(true);
    
            return table;
        }
    
        public class CellData {
    
            private final Object value;
            private final int col;
            private final JTable table;
            private final int row;
    
            public CellData(JTable source) {
                this.col = source.getSelectedColumn();
                this.row = source.getSelectedRow();
                this.value = source.getValueAt(row, col);
                this.table = source;
            }
    
            public int getColumn() {
                return col;
            }
    
            public Object getValue() {
                return value;
            }
    
            public JTable getTable() {
                return table;
            }
    
            public boolean swapValuesWith(int targetRow, int targetCol) {
    
                boolean swapped = false;
    
                if (targetCol == col) {
    
                    Object exportValue = table.getValueAt(targetRow, targetCol);
                    table.setValueAt(value, targetRow, targetCol);
                    table.setValueAt(exportValue, row, col);
                    swapped = true;
    
                }
    
                return swapped;
    
            }
    
        }
    
        public static final DataFlavor CELL_DATA_FLAVOR = createConstant(CellData.class, "application/x-java-celldata");
    
        public class CellDataTransferable implements Transferable {
    
            private CellData cellData;
    
            public CellDataTransferable(CellData cellData) {
                this.cellData = cellData;
            }
    
            @Override
            public DataFlavor[] getTransferDataFlavors() {
                return new DataFlavor[]{CELL_DATA_FLAVOR};
            }
    
            @Override
            public boolean isDataFlavorSupported(DataFlavor flavor) {
                boolean supported = false;
                for (DataFlavor available : getTransferDataFlavors()) {
                    if (available.equals(flavor)) {
                        supported = true;
                    }
                }
                return supported;
            }
    
            @Override
            public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
                return cellData;
            }
    
        }
    
        static protected DataFlavor createConstant(Class clazz, String name) {
            try {
                return new DataFlavor(clazz, name);
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    
        public class TransferHelper extends TransferHandler {
    
            private static final long serialVersionUID = 1L;
    
            public TransferHelper() {
            }
    
            @Override
            public int getSourceActions(JComponent c) {
                return MOVE;
            }
    
            @Override
            protected Transferable createTransferable(JComponent source) {
                // Create the transferable
                JTable table = (JTable) source;
                int row = table.getSelectedRow();
                int col = table.getSelectedColumn();
                Object value = table.getValueAt(row, col);
                return new CellDataTransferable(new CellData(table));
            }
    
            @Override
            protected void exportDone(JComponent source, Transferable data, int action) {
            }
    
            @Override
            public boolean canImport(TransferSupport support) {
                // Reject the import by default...
                boolean canImport = false;
                // Can only import into another JTable
                Component comp = support.getComponent();
                if (comp instanceof JTable) {
                    JTable target = (JTable) comp;
                    // Need the location where the drop might occur
                    DropLocation dl = support.getDropLocation();
                    Point dp = dl.getDropPoint();
                    // Get the column at the drop point
                    int dragColumn = target.columnAtPoint(dp);
                    try {
                        // Get the Transferable, we need to check
                        // the constraints
                        Transferable t = support.getTransferable();
                        CellData cd = (CellData) t.getTransferData(CELL_DATA_FLAVOR);
                        // Make sure we're not dropping onto ourselves...
                        if (cd.getTable() == target) {
                            // Do the columns match...?
                            if (dragColumn == cd.getColumn()) {
                                canImport = true;
                            }
                        }
                    } catch (UnsupportedFlavorException | IOException ex) {
                        ex.printStackTrace();
                    }
                }
                return canImport;
            }
    
            @Override
            public boolean importData(TransferSupport support) {
                // Import failed for some reason...
                boolean imported = false;
                // Only import into JTables...
                Component comp = support.getComponent();
                if (comp instanceof JTable) {
                    JTable target = (JTable) comp;
                    // Need to know where we are importing to...
                    DropLocation dl = support.getDropLocation();
                    Point dp = dl.getDropPoint();
                    int dropCol = target.columnAtPoint(dp);
                    int dropRow = target.rowAtPoint(dp);
                    try {
                        // Get the Transferable at the heart of it all
                        Transferable t = support.getTransferable();
                        CellData cd = (CellData) t.getTransferData(CELL_DATA_FLAVOR);
                        if (cd.getTable() == target) {
                            if (cd.swapValuesWith(dropRow, dropCol)) {
                                imported = true;
                            }
                        }
                    } catch (UnsupportedFlavorException | IOException ex) {
                        ex.printStackTrace();
                    }
    
                }
                return imported;
            }
        }
    
    }
    

    【讨论】:

    • 顺便说一句,为什么这行代码显示错误-> public static final DataFlavor CELL_DATA_FLAVOR = createConstant(CellData.class, "application/x-java-celldata");java-celldata; class=tableswap.CellData");
    • 但我只有 1 个有 2 列的表.. 我只需要在同一列上拖放
    • 抱歉,打错了。好的,那应该会容易得多
    • @MadProgrammer 我没有完全相同的问题(不想交换数据,但需要数据来源),您的回答对我来说是一个完美的方法。感谢您的精彩解释! :)
    • 谢谢@MadProgrammer !!,我调整了它以与 JButton 在交换时交换他们的文本,你认为可以实现自动滚动吗?我不能:(再次感谢您的回答!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多