2012-05-22 12 views
13

मैं एक मुख्य तालिका के लिए RowHeader बनाने के लिए JSCrollPane के व्यूपोर्ट में दूसरा JTable का उपयोग कर रहा हूं। मुख्य तालिका पर DragAndDrop अक्षम है। पंक्तिबद्ध तालिका डीएनडी सक्षम है।ड्रैग एंडड्रॉप के दौरान मुख्य-जेटीबल पर रोहेडर-जेटीबल की ड्रॉपलाइन को कैसे पेंट करें?

यदि उपयोगकर्ता द्वारा पंक्तिबद्ध पर ड्रैग किया जाता है, तो मैं मुख्य तालिका (चित्र में हरे रंग की रेखा) पर चित्रित पंक्तिबद्ध ड्रॉपलाइन (छवि में काली रेखा) का विस्तार करना चाहता हूं।

dropline for the maintable

किसी को भी मेरे लिए एक सलाह है?

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

मैं सुझाव है कि आप इस तरह करने के लिए (स्विंग के ड्रैग & ड्रॉप कार्यक्षमता का उपयोग):

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

इन 2 तरीकों है कि आप होना चाहिए:

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 है इसमें रुचि रखते हैं:

@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 प्रदान करना चाहिए। लेकिन यह लागू करने के लिए एक बड़ा सौदा नहीं है।

उम्मीद है कि इससे मदद मिलती है।

+0

महान जवाब! मैं इसे स्वीकार करूंगा, क्योंकि अब मैं आपके स्रोत कोड में एक 'ड्रॉपटाइटललिस्ट' नहीं बल्कि 'ड्रॉप चेंजेशन' पर' प्रॉपर्टी चेंज लिस्टर ') के समान विचार का उपयोग कर रहा हूं। आपको लगता है कि 'ट्रांसफरहैंडलर' के 'canImport()' में पेंटिंग करना अच्छा विचार क्यों है? मैं एक ग्लासपैन का उपयोग कर रहा हूं जो श्रोता से दिखाई देता है। – bobndrew

+0

ट्रांसफरहैंडलर में चित्रकला को सीधे करना अच्छा नहीं है। मुझे कुछ ऐसा लगता है: घटक जोड़ें/एल एंड एफ यूआई/परतों/आदि का उपयोग करें।और उसके बाद – Xeon

7

ठीक है:
यहाँ SSCCE है। कन्फेशन समय यह यहां कुछ गड़बड़, ब्लंट-वाद्य कोड है। मैं अधिक सुरुचिपूर्ण या साफ समाधान तैयार करने में सक्षम नहीं होने के लिए क्षमा चाहता हूं। मैं स्विंग के गहरे अंधेरे अंधेरे में एक स्तर 1 पर्यटक हूं।

यह कस्टम कोड त्वरित और गंदे श्रेणी में आता है। यह कॉलम के साथ काम नहीं करेगा, मैं सभी किनारे के मामलों के बारे में निश्चित नहीं हूं, और मुझे ड्रॉ रूटीन के बीच में एक और घटक ग्राफिकल संदर्भ चोरी करने के नियमों को नहीं पता है। निचली पंक्ति: यह एक उदाहरण है, पूर्ण समाधान नहीं।

क्योंकि आप ड्रैगिंग और ड्रॉप (अपनी पंक्तिटेबल) के लिए एक अलग तालिका का उपयोग कर रहे हैं, तो उस तालिका के मुख्य मेन्यू को आकर्षित करने का कोई अच्छा तरीका नहीं है। यह ध्यान दिया जाना चाहिए कि PropertyChangeListeners का उपयोग करके एक स्लिम और चमकदार पथ हो सकता है या किसी ईवेंट को मुख्यटेबल में आग लगाने के लिए कुछ हो सकता है, लेकिन मैंने इसे प्रबंधित नहीं किया। यहाँ 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)); 

मैं वास्तविक source code पर भारी झुक ड्रॉप लाइनों के चित्र को हाइजैक करने के लिए, क्योंकि उस सामान से संबंधित विधियां सभी निजी हैं।

संपादित: मुझे लगता है कि मैं चिंतित आप rowTable में सेल खींचकर mainTable में पूरी पंक्ति फिर से व्यवस्थित करने की कोशिश कर किया जा सकता है कर रहा हूँ एक तरफ एक के रूप में उल्लेख करना भूल गया। यह समाधान उस के लिए जिम्मेदार नहीं है, यह सिर्फ रेखा खींचता है। इसके लिए आपको वास्तव में एक अधिक सुरुचिपूर्ण समाधान की आवश्यकता होगी, या एक चेक जो मुख्यटेबल में पंक्तियों को पंक्तिटेबल के साथ समन्वयित करने का आदेश देता है।

+0

@Xeon और इन बहुत ही उपयोगी है जब मैं समस्या का दरवाजा खटखटाया दिलचस्प सुझाव के लिए naugler धन्यवाद। (+1) आप लोगों के लिए। – Boro

+0

आपके उत्तर के लिए धन्यवाद! मैं आपको सबसे तेज़, पूर्ण कामकाजी उदाहरण के लिए बक्षीस दूंगा। इससे मुझे लाइन-पेंटिंग अधिकार के लिए गणना प्राप्त करने में मदद मिली और मैं सराहना करता हूं कि यह एक "एक-लाइनर और एक वर्ग" -उज़ोल्यूशन है। लेकिन ... मुझे यह भी लगता है कि BasicTableUI का विस्तार बहुत जोखिम भरा है ;-) इसके कारण मैं @Xeon का जवाब स्वीकार करूंगा। – bobndrew

+0

ओह, और मैं आपके ** EDIT ** का जवाब देना भूल गया: 2 टेबल पहले से ही हमारे प्रोग्राम में सिंक हो चुके हैं और डीएनड्रॉपिंग के बाद पहले से ही पंक्ति-डेटा की पुन: व्यवस्था कर रही है। मैं बस रेखा खींचने के लिए प्रबंधन नहीं किया था। – bobndrew

6

मेरा समाधान थोड़ा अलग दृष्टिकोण का उपयोग करता है क्योंकि हम मौजूदा घटकों के शीर्ष पर कुछ कस्टम पेंटिंग जोड़ना चाहते हैं। इसलिए, मैंने GlassPane का उपयोग करना चुना और वहां पेंटिंग करें। इस तरह हाइलाइट आप कल्पना कर सकते हैं और इसका आकार सेल आकार तक सीमित नहीं है, क्योंकि यह एक दृष्टिकोण के साथ हो सकता है, उदाहरण के लिए, एक सेल रेंडरर।

इस नमूने को चलाने के लिए आपको the FinalGlassPane from this site डाउनलोड करने की आवश्यकता है। यह आवश्यक है क्योंकि हम घटनाओं को कैप्चर करने की अपनी क्षमता का उपयोग करते हैं (जो नियमित GlassPane के साथ उपभोग किया जाएगा)। यदि ड्रैग अंत में खत्म हो जाता है तो ईवेंट को कैप्चर करने के लिए एक अलग तरीका पता है, तो इसे सभी को एक साथ टाला जा सकता है। यदि आप जानते हैं तो कृपया साझा करें। मेरे लिए यह सबसे अच्छा काम करता है मुझे 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 
} 
+0

पुन: वैध/पुन: प्रकाशित करें, अच्छा जवाब, धन्यवाद। 'ग्लासपेन' का उपयोग करने के लिए +1, इस तरह दोनों टेबल्स पर एक पारदर्शी ड्रॉपलाइन को पेंट करना संभव है। लेकिन मुझे नहीं लगता कि इसे 'फाइनल ग्लासपेन' होना चाहिए और मुझे लगता है कि 'ड्रॉपलाक्शन' के लिए 'प्रॉपर्टी चेंज लिस्टर' अधिक विशिष्ट है। DropLine-Rectangle की गणना करने के लिए RowHeader-Table में getDropLocation() का उपयोग करने के तरीके के लिए कृपया मेरे उत्तर में नवीनतम कोड देखें। – bobndrew

+0

@bobndrew धन्यवाद। तुम सही हो। इसलिए, मैं आपसे पूछना चाहता हूं कि क्या आप इस्तेमाल किए गए समाधान को प्रकाशित कर सकते हैं? उदाहरण के लिए, इसे अपने प्रश्न में संपादित करें, बहुत नीचे ** शीर्षक - समाधान ** शीर्षक वाला एक अनुभाग जोड़ें जिसके तहत समाधान होगा। – Boro

6

naugler, जिऑन और बोरो से महान योगदान के लिए धन्यवाद, मैं अब अपने 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 
+2

इसे यहां प्रकाशित करने का निर्णय लेने के लिए धन्यवाद। मुझे समाधान बहुत पसंद है। चीयर्स फिर से 'बॉबंड्रू' और चूंकि आपने इसे एक उत्तर के रूप में जोड़ा ... क्या बिल्ली ... +1 :) – Boro

संबंधित मुद्दे

 संबंधित मुद्दे