Вопрос по swing, java – Как нарисовать Dropline RowHeader-JTable на Main-JTable во время DragAndDrop?

13

Я использую вторую JTable в области просмотра JScrollPane, чтобы создать RowHeader для главной таблицы. DragAndDrop на главной таблице отключен. В таблице заголовков строк DnD включен.

Если пользователь перетаскивает верхний колонтитул, я хочу расширить нарисованную прямую линию верхнего колонтитула (черная линия на изображении) поверх основной таблицы (как зеленая линия на изображении).

dropline for the maintable

У кого-нибудь есть совет для меня?
Вот SSCCE:

import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Font;
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.JScrollPane;
import javax.swing.JTable;
import javax.swing.JViewport;
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 DNDLinePainterExampleMain extends JFrame {

  public DNDLinePainterExampleMain() {
    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);

    JScrollPane scrollPane = new JScrollPane(mainTable);
    scrollPane.setRowHeaderView(rowTable);
    scrollPane.setCorner(JScrollPane.UPPER_LEFT_CORNER,
        rowTable.getTableHeader());
    this.add(scrollPane);
  }

  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


}//class DNDLinePainterExampleMain

Ваш Ответ

4   ответа
6

Xeon и Boro я теперь использую комбинацию их 3 примеров. Это выглядит так:

the final table dropline

А вот и код:

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
Error: User Rate Limit ExceededbobndrewError: User Rate Limit Exceeded
6

так как мы хотим добавить некоторые пользовательские рисунки поверх существующих компонентов. Поэтому я решил использоватьGlassPane и сделать картину там. Таким образом, выделение может быть всем, что вы можете себе представить, и его размер не ограничен размером ячейки, как это может быть при подходе, использующем, например, средство визуализации ячейки.

Для запуска этого образца вам необходимо скачатьFinalGlassPane from this site, Это необходимо, так как мы используем его возможность для захвата событий (которые с регулярнымGlassPane будет потребляться). Этого можно избежать, если вы знаете другой способ записи события, когда перетаскивание, наконец, закончено.If you know one please do share. Для меня это сработало лучше, плюс мне нравится иметьGlassPane который может захватывать события и не поглощать их все.

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.setDra,gEnabled(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
}
Error: User Rate Limit ExceededEDIT - SOLUTIONError: User Rate Limit Exceeded
Error: User Rate Limit ExceededGlassPaneError: User Rate Limit ExceededFinalGlassPaneError: User Rate Limit ExceededPropertyChangeListenerError: User Rate Limit ExceededdropLocationError: User Rate Limit Exceeded bobndrew
4

аскивания и удаления Swing):

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

Теперь вы должны реализоватьDropTargetListener:

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

Это 2 метода, которые вас должны заинтересовать:

    @Override
    public void dragEnter(DropTargetDragEvent dtde) { shouldPaint = true }

    @Override
    public void dragExit(DropTargetEvent dte) { shouldPaint = false }

Теперь вы должны манипулироватьmainTable (чтобы нарисовать эту «зеленую линию») с помощью вашего 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;
    }

По сути, вы должны реализовать свой собственный рендерер строк или что-то подобное (как в ответе @naugler). Вы должны как-то предоставить логическое значениеshouldPaint к вашему TransferHandler, а также. Но это не имеет большого значения для реализации.

Надеюсь это поможет.

Error: User Rate Limit ExceededDropTargetListenerError: User Rate Limit ExceededPropertyChangeListenerError: User Rate Limit ExceededdropLocationError: User Rate Limit ExceededcanImport()Error: User Rate Limit ExceededTransferHandlerError: User Rate Limit Exceeded bobndrew
Error: User Rate Limit Exceeded
7

мо здесь. Я извиняюсь за то, что не смог придумать более элегантного или чистого решения. Я турист первого уровня в глубоких темных подземельях свинга.

Этот пользовательский код попадает в категорию быстрых и грязных. Он не будет работать со столбцами, я не уверен во всех случаях с краями, и я не знаю правил кражи графического контекста других компонентов в середине процедуры отрисовки. Итог: это пример, а не полное решение.

Поскольку вы используете отдельную таблицу для перетаскивания (ваш rowTable), у этой таблицы нет хорошего способа отрисовки в mainTable. Следует отметить, что может быть гладкий и блестящий путь с использованием PropertyChangeListeners или что-то другое для запуска события в mainTable, но я не справился с этим. Вот собственное расширение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);
        }
    }
}

Вам нужно будет передать этот интерфейс вашему rowTable, чтобы он мог переходить к mainTable, например так:

rowTable.setUI(new ExtendedDropLineTableUI(mainTable));

Я сильно опирался на реальныйисходный код угнать рисунок линий отбрасывания, потому что все методы, относящиеся к этому, являются частными.

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.

Error: User Rate Limit ExceededEDITError: User Rate Limit Exceeded bobndrew
Error: User Rate Limit Exceeded bobndrew
Error: User Rate Limit Exceeded

Похожие вопросы