Google Tag Manager

2012/12/09

Combine five JButtons to make CompoundButton

Code

private static JComponent makeCompoundButton(final Dimension d) {
  JPanel p = new JPanel() {
    @Override public Dimension getPreferredSize() {
      return d;
    }
  };
  p.setLayout(new OverlayLayout(p));
  p.add(new CompoundButton(d, ButtonLocation.NOTH));
  p.add(new CompoundButton(d, ButtonLocation.SOUTH));
  p.add(new CompoundButton(d, ButtonLocation.EAST));
  p.add(new CompoundButton(d, ButtonLocation.WEST));
  p.add(new CompoundButton(d, ButtonLocation.CENTER));
  return p;
}

class CompoundButton extends JButton {
  protected final Color fc = new Color(100,150,255,200);
  protected final Color ac = new Color(230,230,230);
  protected final Color rc = Color.ORANGE;
  protected Shape shape;
  protected Shape base = null;
  private final ButtonLocation bl;
  private final Dimension dim;
  public CompoundButton(Dimension d, ButtonLocation bl) {
    super();
    this.dim = d;
    this.bl = bl;
    setIcon(new Icon() {
      @Override public void paintIcon(Component c, Graphics g, int x, int y) {
        Graphics2D g2 = (Graphics2D)g.create();
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                  RenderingHints.VALUE_ANTIALIAS_ON);
        if(getModel().isArmed()) {
          g2.setColor(ac);
          g2.fill(shape);
        }else if(isRolloverEnabled() && getModel().isRollover()) {
          paintFocusAndRollover(g2, rc);
        }else if(hasFocus()) {
          paintFocusAndRollover(g2, fc);
        }else{
          g2.setColor(getBackground());
          g2.fill(shape);
        }
        g2.dispose();
      }
      @Override public int getIconWidth()  {
        return dim.width;
      }
      @Override public int getIconHeight() {
        return dim.height;
      }
    });
    setFocusPainted(false);
    setContentAreaFilled(false);
    setBackground(new Color(250, 250, 250));
    initShape();
  }
  @Override public Dimension getPreferredSize() {
    return dim;
  }
  protected void initShape() {
    if(!getBounds().equals(base)) {
      base = getBounds();
      float ww = getWidth() * 0.5f;
      float xx = ww * 0.5f;
      Shape inner = new Ellipse2D.Float(xx, xx, ww, ww);
      if(ButtonLocation.CENTER==bl) {
        shape = inner;
      }else{
        Shape outer = new Arc2D.Float(
          1, 1, getWidth()-2, getHeight()-2,
          bl.getStartDegree(), 90f, Arc2D.PIE);
        Area area = new Area(outer);
        area.subtract(new Area(inner));
        shape = area;
      }
    }
  }
  private void paintFocusAndRollover(Graphics2D g2, Color color) {
    g2.setPaint(new GradientPaint(0, 0, color,
                    getWidth()-1, getHeight()-1, color.brighter(), true));
    g2.fill(shape);
    g2.setColor(getBackground());
  }
  @Override protected void paintComponent(Graphics g) {
    initShape();
    super.paintComponent(g);
  }
  @Override protected void paintBorder(Graphics g) {
    Graphics2D g2 = (Graphics2D)g;
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
              RenderingHints.VALUE_ANTIALIAS_ON);
    g2.setColor(getForeground());
    g2.draw(shape);
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
              RenderingHints.VALUE_ANTIALIAS_OFF);
  }
  @Override public boolean contains(int x, int y) {
    //initShape();
    return shape.contains(x, y);
  }
}

References

2012/11/20

Make a ToggleButtonBar with JRadioButtons

Code

class ToggleButtonBarCellIcon implements Icon{
  private static final Color TL = new Color(1f,1f,1f,.2f);
  private static final Color BR = new Color(0f,0f,0f,.2f);
  private static final Color ST = new Color(1f,1f,1f,.4f);
  private static final Color SB = new Color(1f,1f,1f,.1f);

  private Color ssc;
  private Color bgc;

  @Override public void paintIcon(Component c, Graphics g, int x, int y) {
    int r = 8;
    int w = c.getWidth();
    int h = c.getHeight();

    Container parent = c.getParent();
    if(parent==null) {
      return;
    }

    Graphics2D g2 = (Graphics2D)g.create();
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                        RenderingHints.VALUE_ANTIALIAS_ON);
    Path2D.Float p = new Path2D.Float();

    if(c==parent.getComponent(0)) {
      //:first-child
      p.moveTo(x, y + r);
      p.quadTo(x, y, x + r, y);
      p.lineTo(x + w, y);
      p.lineTo(x + w, y + h);
      p.lineTo(x + r, y + h);
      p.quadTo(x, y + h, x, y + h - r);
    }else if(c==parent.getComponent(parent.getComponentCount()-1)) {
      //:last-child
      p.moveTo(x, y);
      p.lineTo(x + w - r, y);
      p.quadTo(x + w, y, x + w, y + r);
      p.lineTo(x + w, y + h - r);
      p.quadTo(x + w, y + h, x + w -r, y + h);
      p.lineTo(x, y + h);
    }else{
      p.moveTo(x, y);
      p.lineTo(x + w, y);
      p.lineTo(x + w, y + h);
      p.lineTo(x, y + h);
    }
    p.closePath();
    Area area = new Area(p);

    g2.setPaint(c.getBackground());
    g2.fill(area);

    ssc = TL;
    bgc = BR;
    if(c instanceof AbstractButton) {
      ButtonModel m = ((AbstractButton)c).getModel();
      if(m.isSelected() || m.isRollover()) {
        ssc = ST;
        bgc = SB;
      }
    }
    g2.setPaint(new GradientPaint(x, y, ssc, x, y+h, bgc, true));
    g2.fill(area);

    g2.setPaint(BR);
    g2.draw(area);

    g2.dispose();
  }
  @Override public int getIconWidth()  {
    return 80;
  }
  @Override public int getIconHeight() {
    return 20;
  }
}

References

2012/10/29

Delete button in a JComboBox popup menu items

Code

class CellButtonsMouseListener extends MouseAdapter {
  private int prevIndex = -1;
  private JButton prevButton;
  private static void listRepaint(JList list, Rectangle rect) {
    if (Objects.nonNull(rect)) {
      list.repaint(rect);
    }
  }
  @Override public void mouseMoved(MouseEvent e) {
    JList list = (JList) e.getComponent();
    Point pt = e.getPoint();
    int index = list.locationToIndex(pt);
    if (!list.getCellBounds(index, index).contains(pt)) {
      if (prevIndex >= 0) {
        Rectangle r = list.getCellBounds(prevIndex, prevIndex);
        listRepaint(list, r);
      }
      index = -1;
      prevButton = null;
      return;
    }
    if (index >= 0) {
      JButton button = getButton(list, pt, index);
      ButtonsRenderer renderer = (ButtonsRenderer) list.getCellRenderer();
      if (Objects.nonNull(button)) {
        renderer.rolloverIndex = index;
        if (!button.equals(prevButton)) {
          Rectangle r = list.getCellBounds(prevIndex, index);
          listRepaint(list, r);
        }
      } else {
        renderer.rolloverIndex = -1;
        Rectangle r = null;
        if (prevIndex == index) {
          if (prevIndex >= 0 && Objects.nonNull(prevButton)) {
            r = list.getCellBounds(prevIndex, prevIndex);
          }
        } else {
          r = list.getCellBounds(index, index);
        }
        listRepaint(list, r);
        prevIndex = -1;
      }
      prevButton = button;
    }
    prevIndex = index;
  }
  @Override public void mousePressed(MouseEvent e) {
    JList list = (JList) e.getComponent();
    Point pt = e.getPoint();
    int index = list.locationToIndex(pt);
    if (index >= 0) {
      JButton button = getButton(list, pt, index);
      if (Objects.nonNull(button)) {
        listRepaint(list, list.getCellBounds(index, index));
      }
    }
  }
  @Override public void mouseReleased(MouseEvent e) {
    JList list = (JList) e.getComponent();
    Point pt = e.getPoint();
    int index = list.locationToIndex(pt);
    if (index >= 0) {
      JButton button = getButton(list, pt, index);
      if (Objects.nonNull(button)) {
        button.doClick();
        Rectangle r = list.getCellBounds(index, index);
        listRepaint(list, r);
      }
    }
  }
  @Override public void mouseExited(MouseEvent e) {
    JList list = (JList) e.getComponent();
    ButtonsRenderer renderer = (ButtonsRenderer) list.getCellRenderer();
    renderer.rolloverIndex = -1;
  }
  @SuppressWarnings("unchecked")
  private static JButton getButton(JList list, Point pt, int index) {
    Container c = (Container) list.getCellRenderer().getListCellRendererComponent(
        list, "", index, false, false);
    Rectangle r = list.getCellBounds(index, index);
    c.setBounds(r);
    // c.doLayout(); // may be needed for other layout managers (eg. FlowLayout)
    pt.translate(-r.x, -r.y);
    Component b = SwingUtilities.getDeepestComponentAt(c, pt.x, pt.y);
    if (b instanceof JButton) {
      return (JButton) b;
    } else {
      return null;
    }
  }
}

References

2012/09/24

create a gradient titled separator

Code

class TitledSeparator extends JLabel{
  private Color color;
  private final String title;
  private final Color target;
  private final int height;
  private final int titlePosition;
  public TitledSeparator(String title, int height, int titlePosition) {
    this(title, null, height, titlePosition);
  }
  public TitledSeparator(
      String _title, Color _target, int _height, int _titlePosition) {
    super();
    this.title = _title;
    this.target = _target;
    this.height = _height;
    this.titlePosition = _titlePosition;
    Icon icon = new Icon() {
      private int width = -1;
      private Paint painter1, painter2;
      @Override public void paintIcon(Component c, Graphics g, int x, int y) {
        int w = c.getWidth();
        if(w!=width || painter1==null || painter2==null || color==null) {
          width = w;
          Point2D start = new Point2D.Float(0f, 0f);
          Point2D end   = new Point2D.Float((float)width, 0f);
          float[] dist  = {0.0f, 1.0f};
          color = getBackground();
          color = color==null ? UIManager.getColor("Panel.background"):color;
          Color tc = target==null ? color : target;
          painter1 = new LinearGradientPaint(
              start, end, dist, new Color[] {tc.darker(),   color});
          painter2 = new LinearGradientPaint(
              start, end, dist, new Color[] {tc.brighter(), color});
        }
        int h = getIconHeight()/2;
        Graphics2D g2  = (Graphics2D)g.create();
        g2.setPaint(painter1);
        g2.fillRect(x, y,   width, getIconHeight());
        g2.setPaint(painter2);
        g2.fillRect(x, y+h, width, getIconHeight()-h);
        g2.dispose();
      }
      @Override public int getIconWidth()  { return 200; } //dummy width
      @Override public int getIconHeight() { return height; }
    };
    this.setBorder(BorderFactory.createTitledBorder(
      BorderFactory.createMatteBorder(height, 0, 0, 0, icon), title,
      TitledBorder.DEFAULT_JUSTIFICATION, titlePosition));
    //System.out.println(getInsets());
  }
  @Override public Dimension getMaximumSize() {
    Dimension d = super.getPreferredSize();
    d.width = Short.MAX_VALUE;
    return d;
  }
  @Override public void updateUI() {
    super.updateUI();
    color = null;
  }
}

References

2012/08/17

JFileChooser with file already exists Dialog

Code

JFileChooser fileChooser = new JFileChooser() {
  @Override public void approveSelection() {
    File f = getSelectedFile();
    if(f.exists() && getDialogType() == SAVE_DIALOG) {
      String m = String.format(
          "<html>%s already exists.<br>Do you want to replace it?",
          f.getAbsolutePath());
      int rv = JOptionPane.showConfirmDialog(
          this, m, "Save As", JOptionPane.YES_NO_OPTION);
      if(rv!=JOptionPane.YES_OPTION) {
        return;
      }
    }
    super.approveSelection();
  }
};

References

2012/07/04

Translucent JPopupMenu

Code

class TranslucentPopupMenu extends JPopupMenu{
  private static final Color ALPHA_ZERO = new Color(0, true);
  private static final Color POPUP_BACK = new Color(250,250,250,200);
  private static final Color POPUP_LEFT = new Color(230,230,230,200);
  private static final int LEFT_WIDTH = 24;
  @Override public boolean isOpaque() {
    return false;
  }
  @Override public void updateUI() {
    super.updateUI();
    //Test:
    boolean isNimbus = UIManager.getBorder("PopupMenu.border")==null;
    if(isNimbus) {
      //XXX: NimbusLnF not work???
      setBorder(new BorderUIResource(BorderFactory.createLineBorder(Color.GRAY)));
    }
  }
  @Override public JMenuItem add(JMenuItem menuItem) {
    menuItem.setOpaque(false);
    return super.add(menuItem);
  }
  @Override public void show(Component c, int x, int y) {
    EventQueue.invokeLater(new Runnable() {
      @Override public void run() {
        Window p = SwingUtilities.getWindowAncestor(TranslucentPopupMenu.this);
        if(p!=null && p instanceof JWindow) {
          System.out.println("Heavy weight");
          JWindow w = (JWindow)p;
          //To be exact: 1.6.0_10 <= java.version < 1.7.0
          //if(System.getProperty("java.version").startsWith("1.6.0")) {
          //  w.dispose();
          //  if(com.sun.awt.AWTUtilities.isWindowOpaque(w)) {
          //    com.sun.awt.AWTUtilities.setWindowOpaque(w, false);
          //  }
          //  w.setVisible(true);
          //}else{
          w.setBackground(ALPHA_ZERO);
          //}}
        }else{
          System.out.println("Light weight");
        }
      }
    });
    super.show(c, x, y);
  }
  @Override protected void paintComponent(Graphics g) {
    Graphics2D g2 = (Graphics2D)g.create();
    g2.setPaint(POPUP_LEFT);
    g2.fillRect(0,0,LEFT_WIDTH,getHeight());
    g2.setPaint(POPUP_BACK);
    g2.fillRect(LEFT_WIDTH,0,getWidth(),getHeight());
    g2.dispose();
  }
}

References

2012/07/02

Rounded corner JComboBox border

Code

class RoundedCornerBorder extends AbstractBorder {
  @Override public void paintBorder(
      Component c, Graphics g, int x, int y, int width, int height) {
    Graphics2D g2 = (Graphics2D)g.create();
    g2.setRenderingHint(
        RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    int r = 12;
    int w = width  - 1;
    int h = height - 1;
    Area round = new Area(new RoundRectangle2D.Float(x, y, w, h, r, r));
    Container parent = c.getParent();
    if(parent!=null) {
      g2.setColor(parent.getBackground());
      Area corner = new Area(new Rectangle2D.Float(x, y, width, height));
      corner.subtract(round);
      g2.fill(corner);
    }
    g2.setPaint(c.getForeground());
    g2.draw(round);
    g2.dispose();
  }
  @Override public Insets getBorderInsets(Component c) {
    return new Insets(4, 8, 4, 8);
  }
  @Override public Insets getBorderInsets(Component c, Insets insets) {
    insets.left = insets.right = 8;
    insets.top = insets.bottom = 4;
    return insets;
  }
}

class KamabokoBorder extends RoundedCornerBorder {
  @Override public void paintBorder(
      Component c, Graphics g, int x, int y, int width, int height) {
    Graphics2D g2 = (Graphics2D)g.create();
    g2.setRenderingHint(
        RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    int r = 12;
    int w = width  - 1;
    int h = height - 1;
//*/
    Path2D.Float p = new Path2D.Float();
    p.moveTo(x, y + h);
    p.lineTo(x, y + r);
    p.quadTo(x, y, x + r, y);
    p.lineTo(x + w - r, y);
    p.quadTo(x + w, y, x + w, y + r);
    p.lineTo(x + w, y + h);
    p.closePath();
    Area round = new Area(p);
/*/
    Area round = new Area(new RoundRectangle2D.Float(x, y, w, h, r, r));
    Rectangle b = round.getBounds();
    b.setBounds(b.x, b.y + r, b.width, b.height - r);
    round.add(new Area(b));
//*/
    Container parent = c.getParent();
    if(parent!=null) {
      g2.setColor(parent.getBackground());
      Area corner = new Area(new Rectangle2D.Float(x, y, width, height));
      corner.subtract(round);
      g2.fill(corner);
    }
    g2.setPaint(c.getForeground());
    g2.draw(round);
    g2.dispose();
  }
}

References

2012/06/21

Height of JTableHeader

Code

JScrollPane scroll = new JScrollPane(table);
scroll.setColumnHeader(new JViewport() {
  @Override public Dimension getPreferredSize() {
    Dimension d = super.getPreferredSize();
    d.height = 32;
    return d;
  }
});
//or
table.setTableHeader(new JTableHeader(table.getColumnModel()) {
  @Override public Dimension getPreferredSize() {
    Dimension d = super.getPreferredSize();
    d.height = 32;
    return d;
  }
});

References

2012/05/25

Creating a Custom Layout Manager

Code

final double A2 = 4.0;
panel2.setLayout(new FlowLayout() {
  @Override public void layoutContainer(Container target) {
    synchronized(target.getTreeLock()) {
      Insets insets = target.getInsets();
      int nmembers  = target.getComponentCount();
      if(nmembers<=0) return;
      int vgap = getVgap();
      int hgap = getHgap();
      int rowh = (target.getHeight()-(insets.top+insets.bottom+vgap*2))/nmembers;
      int x = insets.left + hgap;
      int y = insets.top  + vgap;
      for(int i=0;i < nmembers; i++) {
        Component m = target.getComponent(i);
        if(m.isVisible()) {
          Dimension d = m.getPreferredSize();
          m.setSize(d.width, d.height);
          m.setLocation(x, y);
          y += (vgap + Math.min(rowh, d.height));
          x = (int)(A2 * Math.sqrt(y));
        }
      }
    }
  }
});

References

2012/04/26

Select multiple items in a JList by clicking and dragging

Code

JList list = new JList(model) {
  private ClearSelectionListener listener;
  @Override public void setSelectionInterval(int anchor, int lead) {
    if(anchor==lead && lead >= 0 && anchor >= 0) {
      if(listener.isDragging) {
        addSelectionInterval(anchor, anchor);
      }else if(!listener.isInCellDragging) {
        if(isSelectedIndex(anchor)) {
          removeSelectionInterval(anchor, anchor);
        }else{
          addSelectionInterval(anchor, anchor);
        }
        listener.isInCellDragging = true;
      }
    }else{
      super.setSelectionInterval(anchor, lead);
    }
  }
};

References

2012/03/21

Rounded Border for JTextField

Code

JTextField textField02 = new JTextField(20) {
  @Override protected void paintComponent(Graphics g) {
    if (!isOpaque() && getBorder() instanceof RoundedCornerBorder) {
      Graphics2D g2 = (Graphics2D) g.create();
      g2.setPaint(getBackground());
      g2.fill(((RoundedCornerBorder) getBorder()).getBorderShape(
          0, 0, getWidth() - 1, getHeight() - 1));
      g2.dispose();
    }
    super.paintComponent(g);
  }
  @Override public void updateUI() {
    super.updateUI();
    setOpaque(false);
    setBorder(new RoundedCornerBorder());
  }
};
class RoundedCornerBorder extends AbstractBorder {
  private static final Color ALPHA_ZERO = new Color(0x0, true);
  @Override public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
    Graphics2D g2 = (Graphics2D) g.create();
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    Shape border = getBorderShape(x, y, width - 1, height - 1);
    g2.setPaint(ALPHA_ZERO);
    Area corner = new Area(new Rectangle2D.Double(x, y, width, height));
    corner.subtract(new Area(border));
    g2.fill(corner);
    g2.setPaint(Color.GRAY);
    g2.draw(border);
    g2.dispose();
  }
  public Shape getBorderShape(int x, int y, int w, int h) {
    int r = h; //h / 2;
    return new RoundRectangle2D.Double(x, y, w, h, r, r);
  }
  @Override public Insets getBorderInsets(Component c) {
    return new Insets(4, 8, 4, 8);
  }
  @Override public Insets getBorderInsets(Component c, Insets insets) {
    insets.set(4, 8, 4, 8);
    return insets;
  }
}

References

2012/02/06

JCheckBox Node JTree

Code

class CheckBoxNodeEditor extends TriStateCheckBox implements TreeCellEditor {
  private DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer();
  private final JPanel panel = new JPanel(new BorderLayout());
  private String str = null;
  public CheckBoxNodeEditor() {
    super();
    this.addActionListener(new ActionListener() {
      @Override public void actionPerformed(ActionEvent e) {
        //System.out.println("actionPerformed: stopCellEditing");
        stopCellEditing();
      }
    });
    panel.setFocusable(false);
    panel.setRequestFocusEnabled(false);
    panel.setOpaque(false);
    panel.add(this, BorderLayout.WEST);
    this.setOpaque(false);
  }
  @Override public Component getTreeCellEditorComponent(
      JTree tree, Object value, boolean isSelected,
      boolean expanded, boolean leaf, int row) {
    JLabel l = (JLabel)renderer.getTreeCellRendererComponent(
        tree, value, true, expanded, leaf, row, true);
    l.setFont(tree.getFont());
    if(value != null && value instanceof DefaultMutableTreeNode) {
      this.setEnabled(tree.isEnabled());
      this.setFont(tree.getFont());
      Object userObject = ((DefaultMutableTreeNode)value).getUserObject();
      if(userObject!=null && userObject instanceof CheckBoxNode) {
        CheckBoxNode node = (CheckBoxNode)userObject;
        if(node.status==Status.INDETERMINATE) {
          setIcon(new IndeterminateIcon());
        }else{
          setIcon(null);
        }
        l.setText(node.label);
        setSelected(node.status==Status.SELECTED);
        str = node.label;
      }
      //panel.add(this, BorderLayout.WEST);
      panel.add(l);
      return panel;
    }
    return l;
  }
  @Override public Object getCellEditorValue() {
    return new CheckBoxNode(str, isSelected()?Status.SELECTED:Status.DESELECTED);
  }
  @Override public boolean isCellEditable(EventObject e) {
    if(e != null && e instanceof MouseEvent && e.getSource() instanceof JTree) {
      MouseEvent me = (MouseEvent)e;
      JTree tree = (JTree)e.getSource();
      TreePath path = tree.getPathForLocation(me.getX(), me.getY());
      Rectangle r = tree.getPathBounds(path);
      if(r==null) return false;
      Dimension d = getPreferredSize();
      r.setSize(new Dimension(d.width, r.height));
      if(r.contains(me.getX(), me.getY())) {
        if(str==null && System.getProperty("java.version").startsWith("1.7.0")) {
          System.out.println("XXX: Java 7, only on first run\n"+getBounds());
          setBounds(new Rectangle(0,0,d.width,r.height));
        }
        //System.out.println(getBounds());
        return true;
      }
    }
    return false;
  }
  @Override public void updateUI() {
    super.updateUI();
    setName("Tree.cellEditor");
    if(panel!=null) {
      //panel.removeAll(); //??? Change to Nimbus LnF, JDK 1.6.0
      panel.updateUI();
      //panel.add(this, BorderLayout.WEST);
    }
    //???#1: JDK 1.6.0 bug??? @see 1.7.0 DefaultTreeCellRenderer#updateUI()
    //if(System.getProperty("java.version").startsWith("1.6.0")) {
    //  renderer = new DefaultTreeCellRenderer();
    //}
  }
//...

References

2012/01/25

Sharing tabs between 2 JFrames

Code

//Display "DropLocation" using JLayer 
class DropLocationLayerUI extends LayerUI {
  private static final int LINEWIDTH = 3;
  private final Rectangle lineRect = new Rectangle();
  @Override public void paint(Graphics g, JComponent c) {
    super.paint (g, c);
    JLayer layer = (JLayer)c;
    DnDTabbedPane tabbedPane = (DnDTabbedPane)layer.getView();
    DnDTabbedPane.DropLocation loc = tabbedPane.getDropLocation();
    if(loc != null && loc.isDropable() && loc.getIndex()>=0) {
      int index = loc.getIndex();
      boolean isZero = index==0;
      Rectangle r = tabbedPane.getBoundsAt(isZero?0:index-1);
      if(tabbedPane.getTabPlacement()==JTabbedPane.TOP ||
         tabbedPane.getTabPlacement()==JTabbedPane.BOTTOM) {
        lineRect.setRect(
            r.x-LINEWIDTH/2+r.width*(isZero?0:1), r.y,LINEWIDTH,r.height);
      }else{
        lineRect.setRect(
            r.x,r.y-LINEWIDTH/2+r.height*(isZero?0:1), r.width,LINEWIDTH);
      }
      Graphics2D g2 = (Graphics2D)g.create();
      g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
      g2.setColor(Color.RED);
      g2.fill(lineRect);
      g2.dispose();
    }
  }
}
private final JLabel label = new JLabel() {
// https://free-the-pixel.blogspot.com/2010/04/ghost-drag-and-drop-over-multiple.html
// Free the pixel: GHOST drag and drop, over multiple windows]
  @Override public boolean contains(int x, int y) {
    return false;
  }
};
private final JWindow dialog = new JWindow();
public TabTransferHandler() {
  dialog.add(label);
  //dialog.setAlwaysOnTop(true); // Web Start
  dialog.setOpacity(0.5f);
  //com.sun.awt.AWTUtilities.setWindowOpacity(dialog, 0.5f); // JDK 1.6.0
  DragSource.getDefaultDragSource().addDragSourceMotionListener(
      new DragSourceMotionListener() {
    @Override public void dragMouseMoved(DragSourceDragEvent dsde) {
      Point pt = dsde.getLocation();
      pt.translate(5, 5); // offset
      dialog.setLocation(pt);
    }
  });
//...

References