How to paint the Dropline of a RowHeader-JTable on the Main-JTable during a DragAndDrop?

后端 未结 4 1459
盖世英雄少女心
盖世英雄少女心 2021-02-07 15:16

I\'m using a second JTable in the Viewport of a JScrollPane to build a RowHeader for a main table. DragAndDrop on the main table is disabled. On the rowheader table DnD is enabl

相关标签:
4条回答
  • 2021-02-07 15:37

    Alright. Confession time. This is some gnarly, blunt-instrument code right here. I apologize for not being able to produce a more elegant or clean solution. I am a level 1 tourist in the deep dark dungeons of swing.

    This custom code falls into the quick-and-dirty category. It will not work with columns, I'm not sure about all the edge cases, and I don't know the rules about stealing another components graphical context in the middle of the draw routine. Bottom line: this is an example, not a full solution.

    Because you are using a separate table for dragging and dropping (your rowTable), there is no nice way for that table to draw to the mainTable. It should be noted that there may be a slick and shiny path using PropertyChangeListeners or something to fire an event to the mainTable, but I didn't manage it. Here is a custom extension of the BasicTableUI:

    public class ExtendedDropLineTableUI extends BasicTableUI {
    
            private JTable drawTable;
            private Integer oldRow;
    
            //We give this UI instance a reference to a separate table for drawing
            public ExtendedDropLineTableUI(JTable drawTable) {
                this.drawTable = drawTable;
            }
    
            @Override
            public void paint(Graphics g, JComponent c) {
                super.paint(g, c);
                paintExtendedDropLine();
            }
    
            private void paintExtendedDropLine() {
                JTable.DropLocation loc = table.getDropLocation();
                if (loc == null) {
                    drawTable.repaint();
                    return;
                }
    
                //get the correct line color. no color? no line!
                Color color = UIManager.getColor("Table.dropLineColor");
                if (color == null) {
                    return;
                }
    
                //try to repaint the draw table only if the row changes
                if (oldRow != null && oldRow != loc.getRow()) {
                    drawTable.repaint();
                }
                oldRow = loc.getRow();
                //get location of cell rectangle
                int row = loc.getRow();
                int col = loc.getColumn();
                if (col >= table.getColumnCount()) {
                    col--;
                }
                Rectangle rect = table.getCellRect(row, col, true);
                //adjust rectangle to fit between the cells
                if (rect.y == 0) {
                    rect.y = -1;
                } else {
                    rect.y -= 2;
                }
                //what's a line but a really thin rectangle?
                rect.height = 3;
                //extend the rectangle to the width of the drawing table
                rect.width = drawTable.getWidth();
                //draw the rectangle
                Graphics g = drawTable.getGraphics();
                g.setColor(color);
                g.fillRect(rect.x, rect.y, rect.width, rect.height);
            }
        }
    }
    

    You will need to give this UI to your rowTable so it can draw to the mainTable, like this:

    rowTable.setUI(new ExtendedDropLineTableUI(mainTable));
    

    I leaned heavily on actual source code to hijack the drawing of the drop lines, because the methods concerning that stuff are all private.

    EDIT: I forgot to mention as an aside that I'm worried you may be trying to re-arrange the entire row in the mainTable by dragging the cell in the rowTable. This solution does not account for that either, it just draws the line. For that you really will need a more elegant solution, or a check which keeps the rows in the mainTable ordered in sync with the rowTable.

    0 讨论(0)
  • 2021-02-07 15:40

    I suggest you to do like this (using Swing's drag & drop functionality):

        RowHeaderTable rowTable = new RowHeaderTable(mainTable);
        rowTable.setAutoscrolls(true);
        rowTable.setDragEnabled(true);
        rowTable.setTransferHandler(new RowHeaderTransferHandler(mainTable));
        rowTable.setDropMode(DropMode.INSERT_ROWS);
        try {
            DropTarget dropTarget = rowTable.getDropTarget();
            dropTarget.addDropTargetListener(rowTable);
        }
        catch(TooManyListenersException e) {
            e.printStackTrace();
        }
    

    Now you have to implement DropTargetListener:

    public class RowHeaderTable extends JTable implements ChangeListener, PropertyChangeListener, DropTargetListener {
    

    These are 2 methods that you should be interested in:

        @Override
        public void dragEnter(DropTargetDragEvent dtde) { shouldPaint = true }
    
        @Override
        public void dragExit(DropTargetEvent dte) { shouldPaint = false }
    

    Now you should manipulate your mainTable (to paint this "green line") using your TranserHandler:

        @Override
        public boolean canImport(TransferSupport supp) {
            DropLocation location = supp.getDropLocation();
            if(location instanceof javax.swing.JTable.DropLocation && shouldPaint) {
                javax.swing.JTable.DropLocation tableLocation = (javax.swing.JTable.DropLocation) location;
                int rowToInsert = tableLocation.getRow();
                //paint somehow the "green line"
                //remember that canImport is invoked when you move your mouse
            }
            return true;
        }
    

    Basically you should implement your own row renderer or something similar (like in @naugler answer). You should somehow provide boolean shouldPaint to your TransferHandler as well. But this is not a big deal to implement.

    Hope this helps.

    0 讨论(0)
  • 2021-02-07 15:47

    Thanks to the great contributions from naugler, Xeon and Boro, I'm now using a combination of their 3 examples. It looks like this:

    the final table dropline

    And here's the code:

    import java.awt.AlphaComposite;
    import java.awt.Color;
    import java.awt.Component;
    import java.awt.EventQueue;
    import java.awt.Font;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.Rectangle;
    import java.awt.datatransfer.StringSelection;
    import java.awt.datatransfer.Transferable;
    import java.beans.PropertyChangeEvent;
    import java.beans.PropertyChangeListener;
    import javax.swing.DropMode;
    import javax.swing.JComponent;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JTable;
    import javax.swing.JTable.DropLocation;
    import javax.swing.JViewport;
    import javax.swing.RootPaneContainer;
    import javax.swing.SwingUtilities;
    import javax.swing.TransferHandler;
    import javax.swing.UIManager;
    import javax.swing.event.ChangeEvent;
    import javax.swing.event.ChangeListener;
    import javax.swing.table.DefaultTableCellRenderer;
    import javax.swing.table.JTableHeader;
    import javax.swing.table.TableColumn;
    
    
    public class DNDLinePainterSolutionMain
    {
      public static void main(String[] args)
      {
        EventQueue.invokeLater(new Runnable()
        {
          @Override
          public void run()
          {
            JFrame f = new MainFrame();
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.pack();
            f.setVisible(true);
          }
        });
      }
    }//public class DNDLinePainterSolutionMain
    
    
    class MainFrame extends JFrame
    {
      public MainFrame()
      {
        JTable mainTable = new JTable(4, 3);
        mainTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
    
        JTable rowTable = new RowHeaderTable(mainTable);
        rowTable.setAutoscrolls(true);
        rowTable.setDragEnabled(true);
        rowTable.setTransferHandler(new RowHeaderTransferHandler());
        rowTable.setDropMode(DropMode.INSERT_ROWS);
    
        //install the DropLocation-Extension:
        rowTable.addPropertyChangeListener("dropLocation",
            new DropLocationRepainter(this));
    
        JScrollPane scrollPane = new JScrollPane(mainTable);
        scrollPane.setRowHeaderView(rowTable);
        scrollPane.setCorner(JScrollPane.UPPER_LEFT_CORNER,
            rowTable.getTableHeader());
        this.add(scrollPane);
      }
    }//class MainFrame
    
    
    class RowHeaderTransferHandler extends TransferHandler
    {
      @Override
      public int getSourceActions(JComponent c)
      {
        return COPY_OR_MOVE;
      }
    
      @Override
      protected Transferable createTransferable(JComponent c)
      {
        return new StringSelection(c.getName());
      }
    
      @Override
      public boolean canImport(TransferSupport supp)
      {
        return true;
      }
    }//class RowHeaderTransferHandler
    
    
    /**
     * Listens to a dropLocation-PropertyChange and repaints the DropLine.
     */
    class DropLocationRepainter implements PropertyChangeListener
    {
      private static RowHeaderDropLineGlassPane glassPane;
      private final RootPaneContainer           rootPaneContainer;
    
      public DropLocationRepainter(RootPaneContainer dndLinePainterSolutionMain)
      {
        this.rootPaneContainer = dndLinePainterSolutionMain;
      }
    
      @Override
      public void propertyChange(PropertyChangeEvent pce)
      {
        String propertyName = pce.getPropertyName();
        if ("dropLocation".equals(propertyName) && pce.getNewValue() != null)
        {
          if (glassPane == null)
          {
            rootPaneContainer.getRootPane().setGlassPane(
                glassPane = new RowHeaderDropLineGlassPane((RowHeaderTable) pce
                    .getSource()));
          }
          rootPaneContainer.getRootPane().getGlassPane().setVisible(true);
    
          repaintDropLocation(((JTable) pce.getSource()).getDropLocation());
        }
        else
          if ("dropLocation".equals(propertyName))
            rootPaneContainer.getRootPane().getGlassPane().setVisible(false);
      }
    
      private void repaintDropLocation(DropLocation loc)
      {
        Component c = rootPaneContainer.getRootPane().getGlassPane();
        if (c instanceof RowHeaderDropLineGlassPane)
        {
          RowHeaderDropLineGlassPane glassPane = (RowHeaderDropLineGlassPane) c;
          glassPane.repaint();
        }
      }
    }//class DropLocationRepainter
    
    
    class RowHeaderDropLineGlassPane extends JPanel
    {
      private RowHeaderTable table;
    
      public RowHeaderDropLineGlassPane(RowHeaderTable table)
      {
        this.table = table;
        setOpaque(false);
      }
    
      @Override
      public void paintComponent(Graphics g)
      {
        Graphics2D g2 = (Graphics2D) g;
        g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f));
        Rectangle rect = table.getDropLineRect();
        if (rect != null)
        {
          Rectangle r = SwingUtilities.convertRectangle(table, rect, this);
          g2.setColor(new Color(40, 80, 0));
          g2.fill(r);
        }
      }
    }//class RowHeaderDropLineGlassPane
    
    
    /**
     * Use a JTable as a renderer for row numbers of a given main table. This table
     * must be added to the row header of the scrollpane that contains the main
     * table. From: http://tips4java.wordpress.com/2008/11/18/row-number-table/
     * <p>
     * Added {@code getDropLineRect()} for DropLine extension over the maintable.
     * </p>
     */
    class RowHeaderTable extends JTable implements ChangeListener,
        PropertyChangeListener
    {
    
      private final JTable mainTable;
    
      public RowHeaderTable(JTable mainTable)
      {
        this.mainTable = mainTable;
        mainTable.addPropertyChangeListener(this);
    
        setFocusable(false);
        setAutoCreateColumnsFromModel(false);
    
        updateRowHeight();
        updateModel();
        updateSelectionModel();
    
        TableColumn column = new TableColumn();
        column.setHeaderValue("");
        addColumn(column);
        column.setCellRenderer(new RowNumberRenderer());
    
        getColumnModel().getColumn(0).setPreferredWidth(50);
        setPreferredScrollableViewportSize(getPreferredSize());
    
        getTableHeader().setReorderingAllowed(false);
      }
    
      /*
       * called from the class RowHeaderDropLineGlassPane
       */
      public Rectangle getDropLineRect()
      {
        DropLocation loc = getDropLocation();
        if (loc == null /* || !loc.isDropable() */)
          return null;
    
        final Rectangle lineRect = new Rectangle();
    
        int index = loc.getRow();
        if (index < 0)
        {
          lineRect.setRect(0, 0, 0, 0);
          return null;
        }
    
        Rectangle r = getCellRect(index, 0, true);
        if (index == getRowCount())
          r.height = getCellRect(index - 1, 0, true).height;//if the last line is the DropTarget a height of 0 (of a non-existing Cell after the last row) is returned.
    
        lineRect.setRect(r.x, r.y - (r.height / 4d), getVisibleRect().width
            + mainTable.getWidth(), r.height / 2d - 1);
        return lineRect;
      }
    
      @Override
      public void addNotify()
      {
        super.addNotify();
        Component c = getParent();
        // Keep scrolling of the row table in sync with the main table.
        if (c instanceof JViewport)
        {
          JViewport viewport = (JViewport) c;
          viewport.addChangeListener(this);
        }
      }
    
      /*
       * Delegate method to main table
       */
      @Override
      public int getRowCount()
      {
        return mainTable.getRowCount();
      }
    
      @Override
      public int getRowHeight(int row)
      {
        return mainTable.getRowHeight(row);
      }
    
      /*
       * This table does not use any data from the main TableModel, so just return a
       * value based on the row parameter.
       */
      @Override
      public Object getValueAt(int row, int column)
      {
        return Integer.toString(row + 1);
      }
    
      /*
       * Don't edit data in the main TableModel by mistake
       */
      @Override
      public boolean isCellEditable(int row, int column)
      {
        return false;
      }
    
      // implements ChangeListener
      @Override
      public void stateChanged(ChangeEvent e)
      {
        // Keep the scrolling of the row table in sync with main table
        JViewport viewport = (JViewport) e.getSource();
        JScrollPane scrollPane = (JScrollPane) viewport.getParent();
        scrollPane.getVerticalScrollBar().setValue(viewport.getViewPosition().y);
      }
    
      // implements PropertyChangeListener
      @Override
      public void propertyChange(PropertyChangeEvent e)
      {
        // Keep the row table in sync with the main table
        if ("rowHeight".equals(e.getPropertyName()))
          updateRowHeight();
    
        if ("selectionModel".equals(e.getPropertyName()))
          updateSelectionModel();
    
        if ("model".equals(e.getPropertyName()))
          updateModel();
      }
    
      private void updateRowHeight()
      {
        setRowHeight(mainTable.getRowHeight());
      }
    
      private void updateModel()
      {
        setModel(mainTable.getModel());
      }
    
      private void updateSelectionModel()
      {
        setSelectionModel(mainTable.getSelectionModel());
      }
    
    
      /*
       * Borrow the renderer from JDK1.4.2 table header
       */
      private class RowNumberRenderer extends DefaultTableCellRenderer
      {
        public RowNumberRenderer()
        {
          setHorizontalAlignment(JLabel.CENTER);
        }
    
        @Override
        public Component getTableCellRendererComponent(JTable table, Object value,
            boolean isSelected, boolean hasFocus, int row, int column)
        {
          if (table != null)
          {
            JTableHeader header = table.getTableHeader();
    
            if (header != null)
            {
              setForeground(header.getForeground());
              setBackground(header.getBackground());
              setFont(header.getFont());
            }
          }
    
          if (isSelected)
            setFont(getFont().deriveFont(Font.BOLD));
    
          setText((value == null) ? "" : value.toString());
          setBorder(UIManager.getBorder("TableHeader.cellBorder"));
    
          return this;
        }
      }//class RowNumberRenderer
    
    }//class RowHeaderTable
    
    0 讨论(0)
  • 2021-02-07 16:03

    My solution uses a slightly different approach since we want to add some custom painting on top of existing components. Therefore, I chose to use GlassPane and do the painting there. This way the highlight could be all you can imagine and its size is not limited to cell size, as it could be with an approach using, for example, a cell renderer.

    To run this sample you need to download the FinalGlassPane from this site. It is required since we use its capability to capture events (which with regular GlassPane would be consumed). It could be avoided all together if you know a different way to capture the event when the drag is finally over. If you know one please do share. For me this worked best plus I like to have a GlassPane which can capture events and doesn't consume them all.

    import java.awt.*;
    import java.awt.datatransfer.StringSelection;
    import java.awt.datatransfer.Transferable;
    import java.awt.dnd.*;
    import java.awt.event.AWTEventListener;
    import java.awt.event.MouseEvent;
    import java.beans.PropertyChangeEvent;
    import java.beans.PropertyChangeListener;
    import javax.swing.*;
    import javax.swing.event.ChangeEvent;
    import javax.swing.event.ChangeListener;
    import javax.swing.table.DefaultTableCellRenderer;
    import javax.swing.table.JTableHeader;
    import javax.swing.table.TableColumn;
    
    public class DNDLinePainterExampleMain extends JFrame {
    
        public int x = -1;
        public int y = -1;
        private boolean isDragged = false;
        public FinalGlassPane glassPane;
        private boolean isOutsideTable = false;
    
        public DNDLinePainterExampleMain() {
            final JTable mainTable = new JTable(4, 3);
            mainTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
    
            final JTable rowTable = new RowHeaderTable(mainTable);
            rowTable.setAutoscrolls(true);
            rowTable.setDragEnabled(true);
            rowTable.setTransferHandler(new RowHeaderTransferHandler());
            rowTable.setDropMode(DropMode.INSERT_ROWS);
            final JScrollPane scrollPane = new JScrollPane(mainTable);
            scrollPane.setRowHeaderView(rowTable);
            scrollPane.setCorner(JScrollPane.UPPER_LEFT_CORNER,
                    rowTable.getTableHeader());
    
            final JPanel panel = new JPanel();
    
            DragSourceMotionListener dsml = new DragSourceMotionListener() {
    
                @Override
                public void dragMouseMoved(DragSourceDragEvent dsde) {
                    isDragged = true;
                    isOutsideTable = true;
                    Component source = dsde.getDragSourceContext().getComponent();
                    //the coordinates of the drag event in screen coords
                    Point toConvert = new Point(dsde.getX(), dsde.getY());
                    //convert to source coords
                    SwingUtilities.convertPointFromScreen(toConvert, source);
                    int rowMargin = rowTable.getRowMargin();
                    Point toTest = new Point(toConvert.x, toConvert.y);
                    for (int i = 0; i < rowTable.getRowCount(); i++) {
                        Rectangle bounds = rowTable.getCellRect(i, 0, true);
                        boolean isIn = bounds.contains(toTest);
    //                    System.out.println("bounds = "+bounds+";  rowMargin = "+rowMargin+";  i = "+i+";  isIn = "+isIn);
                        if (isIn) {
                            isOutsideTable = false;
                            int hHalf = bounds.height / 2;
                            int hIn = toTest.y - bounds.y;
                            boolean isTop = false;
                            if (hIn < hHalf) {
                                isTop = true;
                            }
                            x = bounds.width;
                            y = bounds.y - rowMargin;
                            if (!isTop) {
                                y += bounds.height;
                            }
                            //now convert the point to the glass pane coordinates
                            Point c = SwingUtilities.convertPoint(rowTable, x, y, glassPane);
                            x = c.x;
                            y = c.y;
    //                        System.out.println("hIn = "+hIn+";  isTop = "+isTop + "");
                        }
                    }
                    glassPane.repaint();
                }
            };
            DragSource ds = new DragSource();
            ds.addDragSourceMotionListener(dsml);
    
    
            this.setContentPane(panel);
            panel.add(new JButton("Oi for testing"));
            panel.add(scrollPane);
    
    
            DragSource dragSource = DragSource.getDefaultDragSource();
            dragSource.addDragSourceMotionListener(dsml);
            glassPane = new FinalGlassPane(this) {
    
                @Override
                public void eventDispatched(AWTEvent event) {
                    super.eventDispatched(event);
                    if (event instanceof MouseEvent) {
                        //after drag is relesed we are back here with mouse entered event
                        if (isDragged) {
                            isDragged = false;
                            repaint();
                        }
                    }
                }
    
                @Override
                protected void paintComponent(Graphics g) {
                    Graphics2D g2 = (Graphics2D) g;
                    if (isDragged && !isOutsideTable) {
                        g2.setPaint(Color.GREEN);
                        g2.drawLine(x + 2, y + 1, x + mainTable.getWidth() - 4, y + 1);
                        g2.drawLine(x, y, x + mainTable.getWidth(), y);
                        g2.drawLine(x + 2, y - 1, x + mainTable.getWidth() - 4, y - 1);
                    }
                }
            };
            AWTEventListener al = (AWTEventListener) glassPane;
            Toolkit.getDefaultToolkit().addAWTEventListener(al,
                    AWTEvent.MOUSE_MOTION_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK);
    
            this.setGlassPane(glassPane);
            glassPane.setVisible(true);
        }
    
        public static void main(String[] args) {
            EventQueue.invokeLater(new Runnable() {
    
                @Override
                public void run() {
                    JFrame f = new DNDLinePainterExampleMain();
                    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    f.pack();
                    f.setVisible(true);
                }
            });
        }
    
    
        /*
         * Use a JTable as a renderer for row numbers of a given main table. This
         * table must be added to the row header of the scrollpane that contains the
         * main table. from:
         * http://tips4java.wordpress.com/2008/11/18/row-number-table/
         */
        public class RowHeaderTable extends JTable implements ChangeListener,
                PropertyChangeListener {
    
            private final JTable table;
    
            public RowHeaderTable(JTable table) {
                this.table = table;
                table.addPropertyChangeListener(this);
    
                setFocusable(false);
                setAutoCreateColumnsFromModel(false);
    
                updateRowHeight();
                updateModel();
                updateSelectionModel();
    
                TableColumn column = new TableColumn();
                column.setHeaderValue("");
                addColumn(column);
                column.setCellRenderer(new RowNumberRenderer());
    
                getColumnModel().getColumn(0).setPreferredWidth(50);
                setPreferredScrollableViewportSize(getPreferredSize());
    
                getTableHeader().setReorderingAllowed(false);
            }
    
            @Override
            public void addNotify() {
                super.addNotify();
                Component c = getParent();
                // Keep scrolling of the row table in sync with the main table.
                if (c instanceof JViewport) {
                    JViewport viewport = (JViewport) c;
                    viewport.addChangeListener(this);
                }
            }
    
            /*
             * Delegate method to main table
             */
            @Override
            public int getRowCount() {
                return table.getRowCount();
            }
    
            @Override
            public int getRowHeight(int row) {
                return table.getRowHeight(row);
            }
    
            /*
             * This table does not use any data from the main TableModel, so just
             * return a value based on the row parameter.
             */
            @Override
            public Object getValueAt(int row, int column) {
                return Integer.toString(row + 1);
            }
            /*
             * Don't edit data in the main TableModel by mistake
             */
    
            @Override
            public boolean isCellEditable(int row, int column) {
                return false;
            }
            // implements ChangeListener
    
            @Override
            public void stateChanged(ChangeEvent e) {
                // Keep the scrolling of the row table in sync with main table
                JViewport viewport = (JViewport) e.getSource();
                JScrollPane scrollPane = (JScrollPane) viewport.getParent();
                scrollPane.getVerticalScrollBar().setValue(viewport.getViewPosition().y);
            }
            // implements PropertyChangeListener
    
            @Override
            public void propertyChange(PropertyChangeEvent e) {
                // Keep the row table in sync with the main table
                if ("rowHeight".equals(e.getPropertyName())) {
                    updateRowHeight();
                }
    
                if ("selectionModel".equals(e.getPropertyName())) {
                    updateSelectionModel();
                }
    
                if ("model".equals(e.getPropertyName())) {
                    updateModel();
                }
            }
    
            private void updateRowHeight() {
                setRowHeight(table.getRowHeight());
            }
    
            private void updateModel() {
                setModel(table.getModel());
            }
    
            private void updateSelectionModel() {
                setSelectionModel(table.getSelectionModel());
            }
            /*
             * Borrow the renderer from JDK1.4.2 table header
             */
    
            private class RowNumberRenderer extends DefaultTableCellRenderer {
    
                public RowNumberRenderer() {
                    setHorizontalAlignment(JLabel.CENTER);
                }
    
                @Override
                public Component getTableCellRendererComponent(JTable table,
                        Object value, boolean isSelected, boolean hasFocus, int row,
                        int column) {
                    if (table != null) {
                        JTableHeader header = table.getTableHeader();
    
                        if (header != null) {
                            setForeground(header.getForeground());
                            setBackground(header.getBackground());
                            setFont(header.getFont());
                        }
                    }
                    if (isSelected) {
                        setFont(getFont().deriveFont(Font.BOLD));
                    }
                    setText((value == null) ? "" : value.toString());
                    setBorder(UIManager.getBorder("TableHeader.cellBorder"));
                    return this;
                }
            }//class RowNumberRenderer
        }//class RowHeaderTable
    
        public class RowHeaderTransferHandler extends TransferHandler {
    
            @Override
            public int getSourceActions(JComponent c) {
                return COPY_OR_MOVE;
            }
    
            @Override
            protected Transferable createTransferable(JComponent c) {
                return new StringSelection(c.getName());
            }
    
            @Override
            public boolean canImport(TransferSupport supp) {
                return true;
            }
        }//class RowHeaderTransferHandler
    }
    
    0 讨论(0)
提交回复
热议问题