Google Tag Manager

2015/12/28

Copy on select for JTextArea

Code

class CopyOnSelectListener extends MouseAdapter implements CaretListener {
  private boolean dragActive;
  private int dot;
  private int mark;
  @Override public final void caretUpdate(CaretEvent e) {
    if (!dragActive) {
      fire(e.getSource());
    }
  }
  @Override public final void mousePressed(MouseEvent e) {
    dragActive = true;
  }
  @Override public final void mouseReleased(MouseEvent e) {
    dragActive = false;
    fire(e.getSource());
  }
  private void fire(Object c) {
    if (c instanceof JTextComponent) {
      JTextComponent tc = (JTextComponent) c;
      Caret caret = tc.getCaret();
      int d = caret.getDot();
      int m = caret.getMark();
      if (d != m && (dot != d || mark != m)) {
        String str = tc.getSelectedText();
        if (Objects.nonNull(str)) {
          //StringSelection data = new StringSelection(str);
          //Toolkit tk = Toolkit.getDefaultToolkit();
          //tk.getSystemClipboard().setContents(data, data);
          tc.copy();
        }
      }
      dot = d;
      mark = m;
    }
  }
}

References

2015/12/01

Show JToolTip for Icons placed in the cell of the JTable

Code

private final JTable table = new JTable(model) {
  @Override public String getToolTipText(MouseEvent e) {
    Point pt = e.getPoint();
    int vrow = rowAtPoint(pt);
    int vcol = columnAtPoint(pt);
    //int mrow = convertRowIndexToModel(vrow);
    int mcol = convertColumnIndexToModel(vcol);
    if (mcol == 1) {
      TableCellRenderer tcr = getCellRenderer(vrow, vcol);
      Component c = prepareRenderer(tcr, vrow, vcol);
      if (c instanceof JPanel) {
        Rectangle r = getCellRect(vrow, vcol, true);
        c.setBounds(r);
        //@see https://stackoverflow.com/questions/10854831/tool-tip-in-jpanel-in-jtable-not-working
        c.doLayout();
        pt.translate(-r.x, -r.y);
        Component l = SwingUtilities.getDeepestComponentAt(c, pt.x, pt.y);
        if (l instanceof JLabel) {
          ImageIcon icon = (ImageIcon)((JLabel) l).getIcon();
          return icon.getDescription();
        }
      }
    }
    return super.getToolTipText(e);
  }
};
class ListIconRenderer implements TableCellRenderer {
  private final JPanel p = new JPanel(new FlowLayout(FlowLayout.LEFT));
  @Override public Component getTableCellRendererComponent(
      JTable table, Object value,
      boolean isSelected, boolean hasFocus, int row, int column) {
    p.removeAll();
    if (isSelected) {
      p.setOpaque(true);
      p.setBackground(table.getSelectionBackground());
    } else {
      p.setOpaque(false);
    }
    if (value instanceof List) {
      for (Object o : (List) value) {
        if (o instanceof Icon) {
          Icon icon = (Icon) o;
          JLabel label = new JLabel(icon);
          label.setToolTipText(icon.toString());
          p.add(label);
        }
      }
    }
    return p;
  }
}

References

2015/10/30

Display tooltip while dragging JSlider thumb

Code

class SliderPopupListener extends MouseAdapter {
  private final JWindow toolTip = new JWindow();
  private final JLabel label = new JLabel("", SwingConstants.CENTER);
  private final Dimension size = new Dimension(30, 20);
  private int prevValue = -1;

  protected SliderPopupListener() {
    super();
    label.setOpaque(false);
    label.setBackground(UIManager.getColor("ToolTip.background"));
    label.setBorder(UIManager.getBorder("ToolTip.border"));
    toolTip.add(label);
    toolTip.setSize(size);
  }
  protected void updateToolTip(MouseEvent me) {
    JSlider slider = (JSlider) me.getComponent();
    int intValue = (int) slider.getValue();
    if (prevValue != intValue) {
      label.setText(String.format("%03d", slider.getValue()));
      Point pt = me.getPoint();
      pt.y = -size.height;
      SwingUtilities.convertPointToScreen(pt, me.getComponent());
      pt.translate(-size.width / 2, 0);
      toolTip.setLocation(pt);
    }
    prevValue = intValue;
  }
  @Override public void mouseDragged(MouseEvent me) {
    updateToolTip(me);
  }
  @Override public void mousePressed(MouseEvent me) {
    if (UIManager.getBoolean("Slider.onlyLeftMouseButtonDrag")
        && SwingUtilities.isLeftMouseButton(me)) {
      toolTip.setVisible(true);
      updateToolTip(me);
    }
  }
  @Override public void mouseReleased(MouseEvent me) {
    toolTip.setVisible(false);
  }
  @Override public void mouseWheelMoved(MouseWheelEvent e) {
    JSlider s = (JSlider) e.getComponent();
    int i = (int) s.getValue() - e.getWheelRotation();
    BoundedRangeModel m = s.getModel();
    s.setValue(Math.min(Math.max(i, m.getMinimum()), m.getMaximum()));
  }
}

References

2015/09/30

Adjust the height of every row in the JTable to fit the JViewport

Code

JTable table = new JTable(model) {
  int prevHeight = -1;
  int prevCount = -1;
  public void updateRowsHeigth(JViewport vport) {
    int height = vport.getExtentSize().height;
    int rowCount = getModel().getRowCount();
    int defautlRowHeight = height / rowCount;
    if ((height != prevHeight || rowCount != prevCount) && defautlRowHeight > 0) {
      int over = height - rowCount * defautlRowHeight;
      for (int i = 0; i < rowCount; i++) {
        int a = over-- > 0 ? i == rowCount - 1 ? over : 1 : 0;
        setRowHeight(i, defautlRowHeight + a);
      }
    }
    prevHeight = height;
    prevCount = rowCount;
  }
  @Override public void doLayout() {
    super.doLayout();
    Container p = SwingUtilities.getAncestorOfClass(JViewport.class, this);
    if (p instanceof JViewport) {
      updateRowsHeigth((JViewport) p);
    }
  }
};

References

2015/08/31

Change the indeterminate JProgressBar animation patterns

Code

class StripedProgressBarUI extends BasicProgressBarUI {
  private final boolean dir;
  private final boolean slope;
  public StripedProgressBarUI(boolean dir, boolean slope) {
    super();
    this.dir = dir;
    this.slope = slope;
  }
  @Override protected int getBoxLength(int availableLength, int otherDimension) {
    return availableLength; //(int) Math.round(availableLength / 6d);
  }
  @Override public void paintIndeterminate(Graphics g, JComponent c) {
    if (!(g instanceof Graphics2D)) {
      return;
    }

    Insets b = progressBar.getInsets(); // area for border
    int barRectWidth  = progressBar.getWidth() - b.right - b.left;
    int barRectHeight = progressBar.getHeight() - b.top - b.bottom;

    if (barRectWidth <= 0 || barRectHeight <= 0) {
      return;
    }

    Graphics2D g2 = (Graphics2D) g;
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                        RenderingHints.VALUE_ANTIALIAS_ON);

    // Paint the striped box.
    boxRect = getBox(boxRect);
    if (boxRect != null) {
      int w = 10;
      int x = getAnimationIndex();
      GeneralPath p = new GeneralPath();
      if (dir) {
        p.moveTo(boxRect.x,           boxRect.y);
        p.lineTo(boxRect.x + w * .5f, boxRect.y + boxRect.height);
        p.lineTo(boxRect.x + w,       boxRect.y + boxRect.height);
        p.lineTo(boxRect.x + w * .5f, boxRect.y);
      } else {
        p.moveTo(boxRect.x,           boxRect.y + boxRect.height);
        p.lineTo(boxRect.x + w * .5f, boxRect.y + boxRect.height);
        p.lineTo(boxRect.x + w,       boxRect.y);
        p.lineTo(boxRect.x + w * .5f, boxRect.y);
      }
      p.closePath();
      g2.setColor(progressBar.getForeground());
      if (slope) {
        for (int i = boxRect.width + x; i > -w; i -= w) {
          g2.fill(AffineTransform.getTranslateInstance(i, 0).createTransformedShape(p));
        }
      } else {
        for (int i = -x; i < boxRect.width; i += w) {
          g2.fill(AffineTransform.getTranslateInstance(i, 0).createTransformedShape(p));
        }
      }
    }
  }
}

References

2015/08/13

Create a custom drag ghost image

Code

class ListItemTransferHandler extends TransferHandler {
  @Override public int getSourceActions(JComponent c) {
    System.out.println("getSourceActions");
    if (!(c instanceof JList)) {
      return NONE;
    }
    JList source = (JList) c;
    Point pt;
    if (compact) {
      int w = source.getFixedCellWidth();
      int h = source.getFixedCellHeight() - 20; //TODO
      setDragImage(createCompactDragImage(source, w, h));
      pt = new Point(w / 2, h);
    } else {
      setDragImage(createDragImage(source));
      pt = c.getMousePosition();
    }
    if (pt != null) {
      setDragImageOffset(pt);
    }
    return MOVE; //TransferHandler.COPY_OR_MOVE;
  }
  private static BufferedImage createDragImage(JList source) {
    int w = source.getWidth();
    int h = source.getHeight();
    BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
    Graphics g = bi.getGraphics();
    DefaultListCellRenderer renderer =
      (DefaultListCellRenderer) source.getCellRenderer();
    for (int i : source.getSelectedIndices()) {
      Component c = renderer.getListCellRendererComponent(
          source, source.getModel().getElementAt(i), i, false, false);
      Rectangle rect = source.getCellBounds(i, i);
      SwingUtilities.paintComponent(g, c, source, rect);
    }
    g.dispose();
    return bi;
  }
  private BufferedImage createCompactDragImage(JList source, int w, int h) {
    BufferedImage br = null;
    if (w > 0 && h > 0) {
      br = source.getGraphicsConfiguration().createCompatibleImage(
          w, h, Transparency.TRANSLUCENT);
    } else {
      return null;
    }
    int[] selectedIndices = source.getSelectedIndices();
    int length = selectedIndices.length;
    Graphics g = br.getGraphics();
    DefaultListCellRenderer renderer =
      (DefaultListCellRenderer) source.getCellRenderer();
    int idx = selectedIndices[0];
    Object valueAt = source.getModel().getElementAt(idx);
    Component c = renderer.getListCellRendererComponent(
        source, valueAt, idx, false, false);
    Rectangle rect = source.getCellBounds(idx, idx);
    SwingUtilities.paintComponent(g, c, source, 0, 0, rect.width, rect.height);
    if (length > 1) {
      LABEL.setText(String.valueOf(length));
      Dimension d = LABEL.getPreferredSize();
      SwingUtilities.paintComponent(
          g, LABEL, source, (w - d.width) / 2, (h - d.height) / 2, d.width, d.height);
    }
    g.dispose();
    br.coerceData(true);
    return br;
  }
//...

References

2015/06/30

An Image inside a JScrollPane zooming by mouse wheel and panning by mouse click to drag

Code

class ZoomAndPanePanel extends JPanel {
  private final AffineTransform zoomTransform = new AffineTransform();
  private final transient Image img;
  private final Rectangle imgrect;
  private transient ZoomHandler handler;
  private transient DragScrollListener listener;

  protected ZoomAndPanePanel(Image img) {
    super();
    this.img = img;
    this.imgrect = new Rectangle(img.getWidth(this), img.getHeight(this));
  }
  @Override protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2 = (Graphics2D) g.create();
    g2.setPaint(new Color(0x55FF0000, true));
    Rectangle r = new Rectangle(500, 140, 150, 150);

    //use: AffineTransform#concatenate(...) and Graphics2D#setTransform(...)
    //https://docs.oracle.com/javase/8/docs/api/java/awt/geom/AffineTransform.html#concatenate-java.awt.geom.AffineTransform-
    //AffineTransform at = g2.getTransform();
    //at.concatenate(zoomTransform);
    //g2.setTransform(at);
    //g2.drawImage(img, 0, 0, this);
    //g2.fill(r);

    //or use: Graphics2D#drawImage(Image, AffineTransform, ImageObserver)
    //https://docs.oracle.com/javase/8/docs/api/java/awt/Graphics2D.html#drawImage-java.awt.Image-java.awt.geom.AffineTransform-java.awt.image.ImageObserver-
    g2.drawImage(img, zoomTransform, this); //or: g2.drawRenderedImage((RenderedImage) img, zoomTransform);
    g2.fill(zoomTransform.createTransformedShape(r));

    //BAD EXAMPLE
    //g2.setTransform(zoomTransform);
    //g2.drawImage(img, 0, 0, this);

    g2.dispose();
  }
  @Override public Dimension getPreferredSize() {
    Rectangle r = zoomTransform.createTransformedShape(imgrect).getBounds();
    return new Dimension(r.width, r.height);
  }
  @Override public void updateUI() {
    removeMouseListener(listener);
    removeMouseMotionListener(listener);
    removeMouseWheelListener(handler);
    super.updateUI();
    listener = new DragScrollListener();
    addMouseListener(listener);
    addMouseMotionListener(listener);
    handler = new ZoomHandler();
    addMouseWheelListener(handler);
  }

  protected class ZoomHandler extends MouseAdapter {
    private static final double ZOOM_MULTIPLICATION_FACTOR = 1.2;
    private static final int MIN_ZOOM = -10;
    private static final int MAX_ZOOM = 10;
    private static final int EXTENT = 1;
    private final BoundedRangeModel zoomRange = new DefaultBoundedRangeModel(
        0, EXTENT, MIN_ZOOM, MAX_ZOOM + EXTENT);
    @Override public void mouseWheelMoved(MouseWheelEvent e) {
      int dir = e.getWheelRotation();
      int z = zoomRange.getValue();
      zoomRange.setValue(z + EXTENT * (dir > 0 ? -1 : 1));
      if (z != zoomRange.getValue()) {
        Component c = e.getComponent();
        Container p = SwingUtilities.getAncestorOfClass(JViewport.class, c);
        if (p instanceof JViewport) {
          JViewport vport = (JViewport) p;
          Rectangle ovr = vport.getViewRect();
          double s = dir > 0 ? 1d / ZOOM_MULTIPLICATION_FACTOR : ZOOM_MULTIPLICATION_FACTOR;
          zoomTransform.scale(s, s);
          //double s = 1d + zoomRange.getValue() * .1;
          //zoomTransform.setToScale(s, s);
          Rectangle nvr = AffineTransform.getScaleInstance(s, s).createTransformedShape(ovr).getBounds();
          Point vp = nvr.getLocation();
          vp.translate((nvr.width - ovr.width) / 2, (nvr.height - ovr.height) / 2);
          vport.setViewPosition(vp);
          c.revalidate();
          c.repaint();
        }
      }
    }
  }
}

References

2015/05/29

Dynamically change the color of JProgressBar based on its value

Code

class GradientPalletProgressBarUI extends BasicProgressBarUI {
  private final int[] pallet;
  public GradientPalletProgressBarUI() {
    super();
    this.pallet = makeGradientPallet();
  }
  private static int[] makeGradientPallet() {
    BufferedImage image = new BufferedImage(100, 1, BufferedImage.TYPE_INT_RGB);
    Graphics2D g2 = image.createGraphics();
    Point2D start = new Point2D.Float(0f, 0f);
    Point2D end = new Point2D.Float(99f, 0f);
    float[] dist = {0f, .5f, 1f};
    Color[] colors = {Color.RED, Color.YELLOW, Color.GREEN};
    g2.setPaint(new LinearGradientPaint(start, end, dist, colors));
    g2.fillRect(0, 0, 100, 1);
    g2.dispose();
    int width = image.getWidth(null);
    int[] pallet = new int[width];
    PixelGrabber pg = new PixelGrabber(image, 0, 0, width, 1, pallet, 0, width);
    try {
      pg.grabPixels();
    } catch (InterruptedException ex) {
      ex.printStackTrace();
    }
    return pallet;
  }
  private static Color getColorFromPallet(int[] pallet, float x) {
    if (x < 0d || x > 1d) {
      throw new IllegalArgumentException("Parameter outside of expected range");
    }
    int i = (int) (pallet.length * x);
    int max = pallet.length - 1;
    int index = i < 0 ? 0 : i > max ? max : i;
    return new Color(pallet[index] & 0x00ffffff);
    //translucent
    //int pix = pallet[index] & 0x00ffffff | (0x64 << 24);
    //return new Color(pix), true);
  }
  @Override public void paintDeterminate(Graphics g, JComponent c) {
    Insets b = progressBar.getInsets(); // area for border
    int barRectWidth = progressBar.getWidth() - b.right - b.left;
    int barRectHeight = progressBar.getHeight() - b.top - b.bottom;
    if (barRectWidth <= 0 || barRectHeight <= 0) {
      return;
    }
    //int cellLength = getCellLength();
    //int cellSpacing = getCellSpacing();
    // amount of progress to draw
    int amountFull = getAmountFull(b, barRectWidth, barRectHeight);

    // draw the cells
    if (progressBar.getOrientation() == SwingConstants.HORIZONTAL) {
      float x = amountFull / (float) barRectWidth;
      g.setColor(getColorFromPallet(pallet, x));
      g.fillRect(b.left, b.top, amountFull, barRectHeight);
    } else { // VERTICAL
      float y = amountFull / (float) barRectHeight;
      g.setColor(getColorFromPallet(pallet, y));
      g.fillRect(b.left, barRectHeight + b.bottom - amountFull, barRectWidth, amountFull);
    }

    // Deal with possible text painting
    if (progressBar.isStringPainted()) {
      paintString(g, b.left, b.top, barRectWidth, barRectHeight, amountFull, b);
    }
  }
}

References

2015/04/28

ScrollBar for JTextField

Code

scroller.setModel(textField.getHorizontalVisibility());
//...
class EmptyThumbHandler extends ComponentAdapter implements DocumentListener {
  private final BoundedRangeModel emptyThumbModel
    = new DefaultBoundedRangeModel(0, 1, 0, 1);
  private final JTextField textField;
  private final JScrollBar scroller;
  public EmptyThumbHandler(JTextField textField, JScrollBar scroller) {
    super();
    this.textField = textField;
    this.scroller = scroller;
  }
  private void changeThumbModel() {
    EventQueue.invokeLater(new Runnable() {
      @Override public void run() {
        BoundedRangeModel m = textField.getHorizontalVisibility();
        int iv = m.getMaximum() - m.getMinimum() - m.getExtent() - 1; //-1:bug?
        if (iv <= 0) {
          scroller.setModel(emptyThumbModel);
        } else {
          scroller.setModel(textField.getHorizontalVisibility());
        }
      }
    });
  }
  @Override public void componentResized(ComponentEvent e) {
    changeThumbModel();
  }
  @Override public void insertUpdate(DocumentEvent e) {
    changeThumbModel();
  }
  @Override public void removeUpdate(DocumentEvent e) {
    changeThumbModel();
  }
  @Override public void changedUpdate(DocumentEvent e) {
    changeThumbModel();
  }
}

References

2015/03/30

Create a translucent JScrollBar

Code

public JComponent makeTranslucentScrollBar(JComponent c) {
  JScrollPane scrollPane = new JScrollPane(c) {
    @Override public boolean isOptimizedDrawingEnabled() {
      return false; // JScrollBar is overlap
    }
  };
  scrollPane.setVerticalScrollBarPolicy(
      ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
  scrollPane.setHorizontalScrollBarPolicy(
      ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);

  scrollPane.setComponentZOrder(scrollPane.getVerticalScrollBar(), 0);
  scrollPane.setComponentZOrder(scrollPane.getViewport(), 1);
  scrollPane.getVerticalScrollBar().setOpaque(false);

  scrollPane.setLayout(new ScrollPaneLayout() {
    @Override public void layoutContainer(Container parent) {
      JScrollPane scrollPane = (JScrollPane) parent;

      Rectangle availR = scrollPane.getBounds();
      availR.x = availR.y = 0;

      Insets insets = parent.getInsets();
      availR.x = insets.left;
      availR.y = insets.top;
      availR.width  -= insets.left + insets.right;
      availR.height -= insets.top  + insets.bottom;

      Rectangle vsbR = new Rectangle();
      vsbR.width  = 12;
      vsbR.height = availR.height;
      vsbR.x = availR.x + availR.width - vsbR.width;
      vsbR.y = availR.y;

      if (viewport != null) {
        viewport.setBounds(availR);
      }
      if (vsb != null) {
        vsb.setVisible(true);
        vsb.setBounds(vsbR);
      }
    }
  });
  scrollPane.getVerticalScrollBar().setUI(new BasicScrollBarUI() {
    private final Color defaultColor  = new Color(220, 100, 100, 100);
    private final Color draggingColor = new Color(200, 100, 100, 100);
    private final Color rolloverColor = new Color(255, 120, 100, 100);
    private final Dimension d = new Dimension();
    @Override protected JButton createDecreaseButton(int orientation) {
      return new JButton() {
        @Override public Dimension getPreferredSize() {
          return d;
        }
      };
    }
    @Override protected JButton createIncreaseButton(int orientation) {
      return new JButton() {
        @Override public Dimension getPreferredSize() {
          return d;
        }
      };
    }
    @Override protected void paintTrack(Graphics g, JComponent c, Rectangle r) {}
    @Override protected void paintThumb(Graphics g, JComponent c, Rectangle r) {
      Color color;
      JScrollBar sb = (JScrollBar) c;
      if (!sb.isEnabled() || r.width > r.height) {
        return;
      } else if (isDragging) {
        color = draggingColor;
      } else if (isThumbRollover()) {
        color = rolloverColor;
      } else {
        color = defaultColor;
      }
      Graphics2D g2 = (Graphics2D) g.create();
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                          RenderingHints.VALUE_ANTIALIAS_ON);
      g2.setPaint(color);
      g2.fillRect(r.x, r.y, r.width - 1, r.height - 1);
      g2.setPaint(Color.WHITE);
      g2.drawRect(r.x, r.y, r.width - 1, r.height - 1);
      g2.dispose();
    }
    @Override protected void setThumbBounds(int x, int y, int width, int height) {
      super.setThumbBounds(x, y, width, height);
      //scrollbar.repaint(x, 0, width, scrollbar.getHeight());
      scrollbar.repaint();
    }
  });
  return scrollPane;
}

References

2015/02/25

Logging into the JTextArea

Code

Logger logger = Logger.getLogger(TextAreaLogger.TEST.getClass().getName());
logger.setUseParentHandlers(false);
OutputStream os = new TextAreaOutputStream(new JTextArea());
logger.addHandler(new TextAreaHandler(os));
logger.info("test, TEST");

//...
class TextAreaHandler extends StreamHandler {
  private void configure() {
    setFormatter(new SimpleFormatter());
    try {
      setEncoding("UTF-8");
    } catch (IOException ex) {
      try {
        setEncoding(null);
      } catch (IOException ex2) {
        // doing a setEncoding with null should always work.
        // assert false;
        ex2.printStackTrace();
      }
    }
  }
  public TextAreaHandler(OutputStream os) {
    super();
    configure();
    setOutputStream(os);
  }
  //@see java/util/logging/ConsoleHandler.java
  @Override public void publish(LogRecord record) {
    super.publish(record);
    flush();
  }
  @Override public void close() {
    flush();
  }
}

References

2015/01/29

Show/Hide PasswordField

Code

JPasswordField pf = new JPasswordField(24);
pf.setText("abcdefghijklmn");
pf.setAlignmentX(Component.RIGHT_ALIGNMENT);
AbstractDocument doc = (AbstractDocument) pf.getDocument();
doc.setDocumentFilter(new ASCIIOnlyDocumentFilter());

AbstractButton b = new JToggleButton(new AbstractAction() {
  @Override public void actionPerformed(ActionEvent e) {
    AbstractButton c = (AbstractButton) e.getSource();
    Character ec = c.isSelected() ? 0
        : (Character) UIManager.get("PasswordField.echoChar");
    pf.setEchoChar(ec);
  }
});
b.setFocusable(false);
b.setOpaque(false);
b.setContentAreaFilled(false);
b.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 4));
b.setAlignmentX(Component.RIGHT_ALIGNMENT);
b.setAlignmentY(Component.CENTER_ALIGNMENT);
b.setIcon(new ColorIcon(Color.GREEN));
b.setRolloverIcon(new ColorIcon(Color.BLUE));
b.setSelectedIcon(new ColorIcon(Color.RED));
b.setRolloverSelectedIcon(new ColorIcon(Color.ORANGE));

JPanel panel = new JPanel() {
  @Override public boolean isOptimizedDrawingEnabled() {
    return false;
  }
};
panel.setLayout(new OverlayLayout(panel));
panel.add(b);
panel.add(pf);

References