Comment peindre la gouttelette D'un RowHeader-JTable sur le Main-JTable lors d'un DragAndDrop?
j'utilise un deuxième JTable dans le Viewport D'un JScrollPane pour construire un lecteur de RowHeader pour une table principale. DragAndDrop sur la table principale est désactivé. Sur la table rowheader le MDN est activé.
Si un Glisser sur le rowheader est lancé par l'utilisateur, je souhaite prolonger la peint rowheader dropline (la ligne noire dans l'image) au-dessus de la table (comme la ligne verte dans l'image).
est ce que quelqu'un a un conseil pour les moi?
Voici le 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 réponses
je vous suggère de faire comme ceci (à l'aide Swing de la fonction glisser & déposer):
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();
}
Maintenant vous devez implémenter DropTargetListener
:
public class RowHeaderTable extends JTable implements ChangeListener, PropertyChangeListener, DropTargetListener {
ce sont 2 méthodes que vous devriez être intéressé par:
@Override
public void dragEnter(DropTargetDragEvent dtde) { shouldPaint = true }
@Override
public void dragExit(DropTargetEvent dte) { shouldPaint = false }
Maintenant vous devriez manipuler votre mainTable
(pour peindre cette "ligne verte") en utilisant votre 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;
}
fondamentalement, vous devriez mettre en œuvre votre propre renderer de ligne ou quelque chose de similaire (comme dans la réponse @naugler). Vous devez en quelque sorte fournir boolean shouldPaint
à votre TransferHandler aussi. Mais ce n'est pas une grande affaire à mettre en œuvre.
J'espère que cela vous aidera.
Ok. La Confession de temps. C'est un sacré code d'instrument contondant. Je m'excuse de ne pas être en mesure de produire une solution plus élégante ou propre. Je suis un touriste de niveau 1 dans le donjon sombre de swing.
ce code personnalisé entre dans la catégorie "quick-and-dirty". Il ne fonctionnera pas avec les colonnes, Je ne suis pas sûr de tous les cas de bord, et je ne connais pas les règles sur le vol d'un autre contexte graphique composants au milieu de la routine De Tirage. Bas de ligne: ceci est un exemple, pas une solution complète.
parce que vous utilisez une table séparée pour glisser et déposer (votre rowTable), il n'y a pas de bonne façon pour cette table de tirer sur la table principale. Il convient de noter qu'il peut y avoir un chemin lisse et brillant en utilisant PropertyChangeListeners ou quelque chose pour lancer un événement à la table principale, mais je ne l'ai pas géré. Voici une extension personnalisée du 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);
}
}
}
vous aurez besoin de donner cette UI à votre rowTable de sorte qu'il peut tirer de la mainTable, comme ceci:
rowTable.setUI(new ExtendedDropLineTableUI(mainTable));
I se pencha fortement sur la réelle code source détourner le dessin des lignes de chute, parce que les méthodes concernant ce truc sont toutes privées.
EDIT: j'ai oublié de mentionner à part que j'ai peur que vous essayiez de réorganiser toute la rangée dans le maintenable en faisant glisser la cellule dans le rowTable. Cette solution ne tient pas compte de cela non plus, il est juste trace la ligne. Pour cela, vous aurez vraiment besoin d'une solution plus élégante, ou un contrôle qui maintient les lignes dans le maintenable ordonné en synchronisation avec le rowTable.
ma solution utilise une approche légèrement différente puisque nous voulons ajouter de la peinture sur mesure en plus des composants existants. Par conséquent, j'ai choisi d'utiliser GlassPane
et faire la peinture. De cette façon, le point culminant pourrait être tout ce que vous pouvez imaginer et sa taille n'est pas limitée à la taille de la cellule, comme il pourrait être avec une approche en utilisant, par exemple, un renderer de cellules.
Pour exécuter cet exemple, vous devez télécharger FinalGlassPane
à partir de ce site. Il est nécessaire, puisque nous utilisons sa capacité pour capturer des événements (qui avec GlassPane
serait consommée). Il pourrait être évitée si vous connaissez une autre façon de capturer l'événement lorsque le déplacement est enfin terminée. Si vous connaissez une, merci de le faire partager. Pour moi ce qui a le mieux fonctionné et j'aimerais avoir un GlassPane
qui peut capturer des événements et ne pas les consommer.
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
}
grâce aux grandes contributions de naugler, Xeon et Boro, j'utilise maintenant une combinaison de leurs 3 exemples. Il ressemble à ceci:
Et voici le code:
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.DropMode;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTable.DropLocation;
import javax.swing.JViewport;
import javax.swing.RootPaneContainer;
import javax.swing.SwingUtilities;
import javax.swing.TransferHandler;
import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumn;
public class DNDLinePainterSolutionMain
{
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
@Override
public void run()
{
JFrame f = new MainFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setVisible(true);
}
});
}
}//public class DNDLinePainterSolutionMain
class MainFrame extends JFrame
{
public MainFrame()
{
JTable mainTable = new JTable(4, 3);
mainTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
JTable rowTable = new RowHeaderTable(mainTable);
rowTable.setAutoscrolls(true);
rowTable.setDragEnabled(true);
rowTable.setTransferHandler(new RowHeaderTransferHandler());
rowTable.setDropMode(DropMode.INSERT_ROWS);
//install the DropLocation-Extension:
rowTable.addPropertyChangeListener("dropLocation",
new DropLocationRepainter(this));
JScrollPane scrollPane = new JScrollPane(mainTable);
scrollPane.setRowHeaderView(rowTable);
scrollPane.setCorner(JScrollPane.UPPER_LEFT_CORNER,
rowTable.getTableHeader());
this.add(scrollPane);
}
}//class MainFrame
class RowHeaderTransferHandler extends TransferHandler
{
@Override
public int getSourceActions(JComponent c)
{
return COPY_OR_MOVE;
}
@Override
protected Transferable createTransferable(JComponent c)
{
return new StringSelection(c.getName());
}
@Override
public boolean canImport(TransferSupport supp)
{
return true;
}
}//class RowHeaderTransferHandler
/**
* Listens to a dropLocation-PropertyChange and repaints the DropLine.
*/
class DropLocationRepainter implements PropertyChangeListener
{
private static RowHeaderDropLineGlassPane glassPane;
private final RootPaneContainer rootPaneContainer;
public DropLocationRepainter(RootPaneContainer dndLinePainterSolutionMain)
{
this.rootPaneContainer = dndLinePainterSolutionMain;
}
@Override
public void propertyChange(PropertyChangeEvent pce)
{
String propertyName = pce.getPropertyName();
if ("dropLocation".equals(propertyName) && pce.getNewValue() != null)
{
if (glassPane == null)
{
rootPaneContainer.getRootPane().setGlassPane(
glassPane = new RowHeaderDropLineGlassPane((RowHeaderTable) pce
.getSource()));
}
rootPaneContainer.getRootPane().getGlassPane().setVisible(true);
repaintDropLocation(((JTable) pce.getSource()).getDropLocation());
}
else
if ("dropLocation".equals(propertyName))
rootPaneContainer.getRootPane().getGlassPane().setVisible(false);
}
private void repaintDropLocation(DropLocation loc)
{
Component c = rootPaneContainer.getRootPane().getGlassPane();
if (c instanceof RowHeaderDropLineGlassPane)
{
RowHeaderDropLineGlassPane glassPane = (RowHeaderDropLineGlassPane) c;
glassPane.repaint();
}
}
}//class DropLocationRepainter
class RowHeaderDropLineGlassPane extends JPanel
{
private RowHeaderTable table;
public RowHeaderDropLineGlassPane(RowHeaderTable table)
{
this.table = table;
setOpaque(false);
}
@Override
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f));
Rectangle rect = table.getDropLineRect();
if (rect != null)
{
Rectangle r = SwingUtilities.convertRectangle(table, rect, this);
g2.setColor(new Color(40, 80, 0));
g2.fill(r);
}
}
}//class RowHeaderDropLineGlassPane
/**
* Use a JTable as a renderer for row numbers of a given main table. This table
* must be added to the row header of the scrollpane that contains the main
* table. From: http://tips4java.wordpress.com/2008/11/18/row-number-table/
* <p>
* Added {@code getDropLineRect()} for DropLine extension over the maintable.
* </p>
*/
class RowHeaderTable extends JTable implements ChangeListener,
PropertyChangeListener
{
private final JTable mainTable;
public RowHeaderTable(JTable mainTable)
{
this.mainTable = mainTable;
mainTable.addPropertyChangeListener(this);
setFocusable(false);
setAutoCreateColumnsFromModel(false);
updateRowHeight();
updateModel();
updateSelectionModel();
TableColumn column = new TableColumn();
column.setHeaderValue("");
addColumn(column);
column.setCellRenderer(new RowNumberRenderer());
getColumnModel().getColumn(0).setPreferredWidth(50);
setPreferredScrollableViewportSize(getPreferredSize());
getTableHeader().setReorderingAllowed(false);
}
/*
* called from the class RowHeaderDropLineGlassPane
*/
public Rectangle getDropLineRect()
{
DropLocation loc = getDropLocation();
if (loc == null /* || !loc.isDropable() */)
return null;
final Rectangle lineRect = new Rectangle();
int index = loc.getRow();
if (index < 0)
{
lineRect.setRect(0, 0, 0, 0);
return null;
}
Rectangle r = getCellRect(index, 0, true);
if (index == getRowCount())
r.height = getCellRect(index - 1, 0, true).height;//if the last line is the DropTarget a height of 0 (of a non-existing Cell after the last row) is returned.
lineRect.setRect(r.x, r.y - (r.height / 4d), getVisibleRect().width
+ mainTable.getWidth(), r.height / 2d - 1);
return lineRect;
}
@Override
public void addNotify()
{
super.addNotify();
Component c = getParent();
// Keep scrolling of the row table in sync with the main table.
if (c instanceof JViewport)
{
JViewport viewport = (JViewport) c;
viewport.addChangeListener(this);
}
}
/*
* Delegate method to main table
*/
@Override
public int getRowCount()
{
return mainTable.getRowCount();
}
@Override
public int getRowHeight(int row)
{
return mainTable.getRowHeight(row);
}
/*
* This table does not use any data from the main TableModel, so just return a
* value based on the row parameter.
*/
@Override
public Object getValueAt(int row, int column)
{
return Integer.toString(row + 1);
}
/*
* Don't edit data in the main TableModel by mistake
*/
@Override
public boolean isCellEditable(int row, int column)
{
return false;
}
// implements ChangeListener
@Override
public void stateChanged(ChangeEvent e)
{
// Keep the scrolling of the row table in sync with main table
JViewport viewport = (JViewport) e.getSource();
JScrollPane scrollPane = (JScrollPane) viewport.getParent();
scrollPane.getVerticalScrollBar().setValue(viewport.getViewPosition().y);
}
// implements PropertyChangeListener
@Override
public void propertyChange(PropertyChangeEvent e)
{
// Keep the row table in sync with the main table
if ("rowHeight".equals(e.getPropertyName()))
updateRowHeight();
if ("selectionModel".equals(e.getPropertyName()))
updateSelectionModel();
if ("model".equals(e.getPropertyName()))
updateModel();
}
private void updateRowHeight()
{
setRowHeight(mainTable.getRowHeight());
}
private void updateModel()
{
setModel(mainTable.getModel());
}
private void updateSelectionModel()
{
setSelectionModel(mainTable.getSelectionModel());
}
/*
* Borrow the renderer from JDK1.4.2 table header
*/
private class RowNumberRenderer extends DefaultTableCellRenderer
{
public RowNumberRenderer()
{
setHorizontalAlignment(JLabel.CENTER);
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column)
{
if (table != null)
{
JTableHeader header = table.getTableHeader();
if (header != null)
{
setForeground(header.getForeground());
setBackground(header.getBackground());
setFont(header.getFont());
}
}
if (isSelected)
setFont(getFont().deriveFont(Font.BOLD));
setText((value == null) ? "" : value.toString());
setBorder(UIManager.getBorder("TableHeader.cellBorder"));
return this;
}
}//class RowNumberRenderer
}//class RowHeaderTable