14

JScrollPaneのビューポートで2番目のJTableを使用して、メインテーブルのRowHeaderを作成しています。メインテーブルのDragAndDropは無効になっています。行ヘッダーテーブルでDnDが有効になっています。

行ヘッダーのドラッグがユーザーによって開始された場合、ペイントされた行ヘッダーのドロップライン(画像の黒い線)をメインテーブル(画像の緑色の線のように)上に延長したいと思います。

メインテーブルのドロップライン

誰かアドバイスはありますか?
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

4 に答える 4

8

naugler、Xeon、Boroからの多大な貢献のおかげで、私は現在、これら3つの例を組み合わせて使用​​しています。次のようになります。

ファイナルテーブルのドロップライン

そしてここにコードがあります:

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
于 2012-05-30T13:33:34.773 に答える
7

大丈夫。告白の時間。これは、ここにあるいくつかの厄介な鈍器コードです。よりエレガントでクリーンなソリューションを作成できなかったことをお詫び申し上げます。私はスイングの深く暗いダンジョンでレベル1の観光客です。

このカスタムコードは、手っ取り早いカテゴリに分類されます。列では機能しません。すべてのエッジケースについてはわかりません。また、描画ルーチンの途中で別のコンポーネントのグラフィカルコンテキストを盗むことについてのルールもわかりません。結論:これは一例であり、完全な解決策ではありません。

ドラッグアンドドロップ用に別のテーブル(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);
        }
    }
}

このUIをrowTableに指定して、次のようにmainTableに描画できるようにする必要があります。

rowTable.setUI(new ExtendedDropLineTableUI(mainTable));

ドロップラインの描画をハイジャックするために、実際のソースコードに大きく依存しました。これは、そのようなものに関するメソッドがすべてプライベートであるためです。

編集余談ですが、rowTableのセルをドラッグして、mainTableの行全体を再配置しようとしているのではないかと心配しています。このソリューションもそれを考慮しておらず、線を引くだけです。そのためには、より洗練されたソリューション、またはmainTableの行をrowTableと同期して順序付けておくチェックが本当に必要になります。

于 2012-05-24T20:47:44.040 に答える
6

既存のコンポーネントの上にカスタムペイントを追加したいので、私のソリューションでは少し異なるアプローチを使用しています。そのため、そこで絵を描いて使うことGlassPaneにしました。このように、ハイライトは想像できるすべてのものであり、そのサイズは、たとえばセルレンダラーを使用するアプローチの場合のように、セルサイズに制限されません。

このサンプルを実行するには、このサイトからをダウンロードするFinalGlassPane必要があります。イベントをキャプチャする機能を使用するため、これが必要です(通常GlassPaneは消費されます)。ドラッグが最終的に終わったときにイベントをキャプチャする別の方法を知っていれば、それをすべて一緒に回避することができます。あなたが1つを知っているならば、共有してください。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.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
}
于 2012-05-25T14:08:48.937 に答える
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にもブール値を提供する必要があります。しかし、これを実装するのは大したことではありません。

お役に立てれば。

于 2012-05-24T21:02:29.213 に答える