Code
class ColumnInsertLayerUI extends LayerUI<JScrollPane> {
private static final Color LINE_COLOR = new Color(0x00_78_D7);
private static final int LINE_WIDTH = 4;
private final Rectangle2D line = new Rectangle2D.Double();
private final Ellipse2D plus = new Ellipse2D.Double(0d, 0d, 10d, 10d);
@Override public void paint(Graphics g, JComponent c) {
super.paint(g, c);
if (c instanceof JLayer && !line.isEmpty()) {
JScrollPane scroll = (JScrollPane) ((JLayer<?>) c).getView();
JTableHeader header =
((JTable) scroll.getViewport().getView()).getTableHeader();
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(
RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Point pt0 = line.getBounds().getLocation();
Point pt1 = SwingUtilities.convertPoint(header, pt0, c);
g2.translate(pt1.getX() - pt0.getX(), pt1.getY() - pt0.getY());
// paint Insert Line
g2.setPaint(LINE_COLOR);
g2.fill(line);
// paint Plus Icon
g2.setPaint(Color.WHITE);
g2.fill(plus);
g2.setPaint(LINE_COLOR);
double cx = plus.getCenterX();
double cy = plus.getCenterY();
double w2 = plus.getWidth() / 2d;
double h2 = plus.getHeight() / 2d;
g2.draw(new Line2D.Double(cx - w2, cy, cx + w2, cy));
g2.draw(new Line2D.Double(cx, cy - h2, cx, cy + h2));
g2.draw(plus);
g2.dispose();
}
}
private void updateLineLocation(JScrollPane scroll, Point loc) {
JTable table = (JTable) scroll.getViewport().getView();
JTableHeader header = table.getTableHeader();
Rectangle rect = scroll.getVisibleRect();
JScrollBar bar = scroll.getHorizontalScrollBar();
int scrollHeight = bar.isVisible() ? bar.getHeight() : 0;
Dimension d = new Dimension(
LINE_WIDTH, rect.height - scrollHeight);
for (int i = 0; i < table.getColumnCount(); i++) {
if (canInsert(header, loc, i, d)) {
return;
}
}
}
private boolean canInsert(
JTableHeader header, Point loc, int i, Dimension d) {
Rectangle r = header.getHeaderRect(i);
Rectangle r1 = getWestRect(r, i);
Rectangle r2 = getEastRect(r);
boolean hit = false;
if (r1.contains(loc)) {
updateInsertLineLocation(r1, loc, d, header);
hit = true;
} else if (r2.contains(loc)) {
updateInsertLineLocation(r2, loc, d, header);
hit = true;
} else if (r.contains(loc)) {
line.setFrame(0d, 0d, 0d, 0d);
header.setCursor(Cursor.getDefaultCursor());
hit = true;
}
return hit;
}
private Rectangle getWestRect(Rectangle r, int i) {
Rectangle rect = r.getBounds();
Rectangle bounds = plus.getBounds();
if (i != 0) {
rect.x -= bounds.width / 2;
}
rect.setSize(bounds.getSize());
return rect;
}
private Rectangle getEastRect(Rectangle r) {
Rectangle rect = r.getBounds();
Rectangle bounds = plus.getBounds();
rect.x += rect.width - bounds.width / 2;
rect.setSize(bounds.getSize());
return rect;
}
private void updateInsertLineLocation(
Rectangle r, Point loc, Dimension d, Component c) {
if (r.contains(loc)) {
double cx = r.getCenterX();
double cy = r.getCenterY();
line.setFrame(
cx - d.getWidth() / 2d, r.getY(), d.width, d.height);
double pw = plus.getWidth() / 2d;
double ph = plus.getHeight() / 2d;
plus.setFrameFromCenter(cx, cy, cx - pw, cy - ph);
c.setCursor(Cursor.getDefaultCursor());
} else {
line.setFrame(0d, 0d, 0d, 0d);
c.setCursor(Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR));
}
}
@Override public void installUI(JComponent c) {
super.installUI(c);
if (c instanceof JLayer) {
((JLayer<?>) c).setLayerEventMask(
AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK);
}
}
@Override public void uninstallUI(JComponent c) {
if (c instanceof JLayer) {
((JLayer<?>) c).setLayerEventMask(0);
}
super.uninstallUI(c);
}
@Override protected void processMouseEvent(
MouseEvent e, JLayer<? extends JScrollPane> l) {
super.processMouseEvent(e, l);
if (e.getID() == MouseEvent.MOUSE_CLICKED) {
JScrollPane scroll = l.getView();
Point pt = e.getPoint();
if (plus.contains(pt) && !line.isEmpty()) {
JTable table = (JTable) scroll.getViewport().getView();
TableModel model = table.getModel();
int columnCount = table.getColumnCount();
int maxColumn = model.getColumnCount();
if (columnCount < maxColumn) {
int idx = table.columnAtPoint(
line.getBounds().getLocation());
TableColumn column = new TableColumn(columnCount);
column.setHeaderValue("Column" + columnCount);
table.addColumn(column);
table.moveColumn(columnCount, idx + 1);
updateLineLocation(scroll, pt);
}
}
l.repaint(scroll.getBounds());
}
}
@Override protected void processMouseMotionEvent(
MouseEvent e, JLayer<? extends JScrollPane> l) {
super.processMouseMotionEvent(e, l);
Component c = e.getComponent();
int id = e.getID();
JScrollPane scroll = l.getView();
if (id == MouseEvent.MOUSE_MOVED && c instanceof JTableHeader) {
updateLineLocation(scroll, e.getPoint());
} else {
line.setFrame(0d, 0d, 0d, 0d);
}
l.repaint(scroll.getBounds());
}
}
References