在DragAndDrop中,如何在Main-JTable上绘制RowHeader-JTable的Dropline? [英] How to paint the Dropline of a RowHeader-JTable on the Main-JTable during a DragAndDrop?
问题描述
我在JScrollPane的Viewport中使用第二个JTable来构建主表的RowHeader。
主表上的DragAndDrop被禁用。在行头表DnD已启用。
I'm using a second JTable in the Viewport of a JScrollPane to build a RowHeader for a main table. DragAndDrop on the main table is disabled. On the rowheader table DnD is enabled.
如果用户启动了行头上的拖动,我想在主表上扩展绘制的行头标头(图像中的黑线)(如图片中的绿线)。
If a Drag on the rowheader is started by the user, I want to extend the painted rowheader dropline (the black line in the image) over the main table (like the green line in the image).
有人对我有建议吗?
这是SSCCE:
Does anybody have an advice for me?
Here's the 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
推荐答案
我建议你这样做(使用Swing的拖放功能):
I suggest you to do like this (using Swing's drag & drop functionality):
RowHeaderTable rowTable = new RowHeaderTable(mainTable);
rowTable.setAutoscrolls(true);
rowTable.setDragEnabled(true);
rowTable.setTransferHandler(new RowHeaderTransferHandler(mainTable));
rowTable.setDropMode(DropMode.INSERT_ROWS);
try {
DropTarget dropTarget = rowTable.getDropTarget();
dropTarget.addDropTargetListener(rowTable);
}
catch(TooManyListenersException e) {
e.printStackTrace();
}
现在你必须实现 DropTargetListener
Now you have to implement DropTargetListener
:
public class RowHeaderTable extends JTable implements ChangeListener, PropertyChangeListener, DropTargetListener {
这是您应该感兴趣的两种方法:
These are 2 methods that you should be interested in:
@Override
public void dragEnter(DropTargetDragEvent dtde) { shouldPaint = true }
@Override
public void dragExit(DropTargetEvent dte) { shouldPaint = false }
现在你应该操纵你的 mainTable
(来画这个绿线)使用您的TranserHandler:
Now you should manipulate your mainTable
(to paint this "green line") using your TranserHandler:
@Override
public boolean canImport(TransferSupport supp) {
DropLocation location = supp.getDropLocation();
if(location instanceof javax.swing.JTable.DropLocation && shouldPaint) {
javax.swing.JTable.DropLocation tableLocation = (javax.swing.JTable.DropLocation) location;
int rowToInsert = tableLocation.getRow();
//paint somehow the "green line"
//remember that canImport is invoked when you move your mouse
}
return true;
}
基本上你应该实现自己的行渲染器或类似的东西(像在@naugler回答)。您应该以某种方式向您的TransferHandler提供布尔值 shouldPaint
。但是这不是一个很大的实现。
Basically you should implement your own row renderer or something similar (like in @naugler answer). You should somehow provide boolean shouldPaint
to your TransferHandler as well. But this is not a big deal to implement.
希望这有帮助。
这篇关于在DragAndDrop中,如何在Main-JTable上绘制RowHeader-JTable的Dropline?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!