Google Tag Manager

Showing posts with label Border. Show all posts
Showing posts with label Border. Show all posts

2023/11/30

Split TableColumn of JTableHeader with diagonal line Border

Code

int size = 32;
JTable table = new JTable(model) {
  @Override public void updateUI() {
    super.updateUI();
    setRowHeight(size);
    TableCellRenderer hr = new VerticalTableHeaderRenderer();
    TableColumnModel cm = getColumnModel();
    cm.getColumn(0).setHeaderRenderer(
        new DiagonallySplitHeaderRenderer());
    cm.getColumn(0).setPreferredWidth(size * 5);
    for (int i = 1; i < cm.getColumnCount(); i++) {
      TableColumn tc = cm.getColumn(i);
      tc.setHeaderRenderer(hr);
      tc.setPreferredWidth(size);
    }
  }
};
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);

JScrollPane scroll = new JScrollPane(table);
scroll.setColumnHeader(new JViewport() {
  @Override public Dimension getPreferredSize() {
    Dimension d = super.getPreferredSize();
    d.height = size * 2;
    return d;
  }
});
// ...

class DiagonallySplitBorder extends MatteBorder {
  protected DiagonallySplitBorder(
      int top, int left, int bottom, int right, Color matteColor) {
    super(top, left, bottom, right, matteColor);
  }

  @Override public void paintBorder(
      Component c, Graphics g, int x, int y, int width, int height) {
    super.paintBorder(c, g, x, y, width, height);
    Graphics2D g2 = (Graphics2D) g.create();
    g2.translate(x, y);
    g2.setRenderingHint(
        RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON);
    g2.setPaint(getMatteColor());
    g2.drawLine(0, 0, c.getWidth() - 1, c.getHeight() - 1);
    g2.dispose();
  }
}

References

2022/05/30

Focus Border of the previously selected tab in JTabbedPane is thinly displayed as history

Code

class LineFocusTabbedPane extends JTabbedPane {
  private transient ChangeListener listener;

  protected LineFocusTabbedPane() {
    super();
  }

  @Override public void updateUI() {
    removeChangeListener(listener);
    UIManager.put("TabbedPane.tabInsets", new InsetsUIResource(1, 4, 0, 4));
    UIManager.put("TabbedPane.selectedTabPadInsets", new InsetsUIResource(1, 1, 1, 1));
    UIManager.put("TabbedPane.tabAreaInsets", new InsetsUIResource(3, 2, 0, 2));
    UIManager.put("TabbedPane.selectedLabelShift", 0);
    UIManager.put("TabbedPane.labelShift", 0);
    UIManager.put("TabbedPane.focus", new ColorUIResource(new Color(0x0, true)));
    super.updateUI();
    listener = new TabSelectionListener();
    addChangeListener(listener);
    setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
  }

  @Override public void insertTab(String title, Icon icon, Component c, String tip, int index) {
    super.insertTab(title, icon, c, tip, index);
    JLabel label = new JLabel(title, icon, SwingConstants.CENTER);
    setTabComponentAt(index, label);
  }
}

class TabSelectionListener implements ChangeListener {
  private static final Color ALPHA_ZERO = new Color(0x0, true);
  private static final Color SELECTION_COLOR = new Color(0x00_AA_FF);
  private static final Color PREV_COLOR = new Color(0x48_00_AA_FF, true);
  private int prev = -1;

  @Override public void stateChanged(ChangeEvent e) {
    JTabbedPane tabbedPane = (JTabbedPane) e.getSource();
    if (tabbedPane.getTabCount() <= 0) {
      return;
    }
    int idx = tabbedPane.getSelectedIndex();
    for (int i = 0; i < tabbedPane.getTabCount(); i++) {
      Component tab = tabbedPane.getTabComponentAt(i);
      if (tab instanceof JComponent) {
        Color color;
        if (i == idx) {
          color = SELECTION_COLOR;
        } else if (i == prev) {
          color = PREV_COLOR;
        } else {
          color = ALPHA_ZERO;
        }
        ((JComponent) tab).setBorder(BorderFactory.createMatteBorder(3, 0, 0, 0, color));
      }
    }
    prev = idx;
  }
}

References

2022/01/01

Change the selection focus Border of JTabbedPane to underline

Code

class UnderlineFocusTabbedPane extends JTabbedPane {
  private static final Border DEFAULT_BORDER =
      BorderFactory.createMatteBorder(0, 0, 3, 0, new Color(0x0, true));
  private static final Border SELECTED_BORDER =
      BorderFactory.createMatteBorder(0, 0, 3, 0, new Color(0x00_AA_FF));

  protected UnderlineFocusTabbedPane() {
    super();
  }

  @Override public void updateUI() {
    super.updateUI();
    // setFocusable(false);
    if (getUI() instanceof WindowsTabbedPaneUI) {
      setUI(new WindowsTabbedPaneUI() {
        @Override protected void paintFocusIndicator(
            Graphics g, int tabPlacement, Rectangle[] rects, int tabIndex,
            Rectangle iconRect, Rectangle textRect, boolean isSelected) {
          super.paintFocusIndicator(g, tabPlacement, rects, tabIndex, iconRect, textRect, false);
        }
      });
    } else {
      setUI(new BasicTabbedPaneUI() {
        @Override protected void paintFocusIndicator(
            Graphics g, int tabPlacement, Rectangle[] rects, int tabIndex,
            Rectangle iconRect, Rectangle textRect, boolean isSelected) {
          super.paintFocusIndicator(g, tabPlacement, rects, tabIndex, iconRect, textRect, false);
        }
      });
    }
    addChangeListener(e -> {
      JTabbedPane tabbedPane = (JTabbedPane) e.getSource();
      if (tabbedPane.getTabCount() <= 0) {
        return;
      }
      int idx = tabbedPane.getSelectedIndex();
      for (int i = 0; i < tabbedPane.getTabCount(); i++) {
        Component c = tabbedPane.getTabComponentAt(i);
        if (c instanceof JComponent) {
          ((JComponent) c).setBorder(i == idx ? SELECTED_BORDER : DEFAULT_BORDER);
        }
      }
    });
  }

  @Override public void insertTab(
      String title, Icon icon, Component component, String tip, int index) {
    super.insertTab(title, icon, component, tip, index);
    JLabel label = new JLabel(title, icon, SwingConstants.CENTER);
    setTabComponentAt(index, label);
  }
}

References

2021/01/31

Draw the upper right, left, and right borders sequentially when JTextField gets focus

Code

class AnimatedBorder extends EmptyBorder {
  private static final int BOTTOM_SPACE = 20;
  private static final double PLAY_TIME = 300d;
  private static final int BORDER = 4;
  private final Timer animator = new Timer(10, null);
  private final transient Stroke stroke = new BasicStroke(BORDER);
  private final transient Stroke bottomStroke = new BasicStroke(BORDER / 2f);
  private long startTime = -1L;
  private final transient List points = new ArrayList<>();
  private transient Shape shape;

  public AnimatedBorder(JComponent c) {
    super(BORDER, BORDER, BORDER + BOTTOM_SPACE, BORDER);
    animator.addActionListener(e -> {
      if (startTime < 0) {
        startTime = System.currentTimeMillis();
      }
      long playTime = System.currentTimeMillis() - startTime;
      double progress = playTime / PLAY_TIME;
      boolean stop = progress > 1d || points.isEmpty();
      if (stop) {
        startTime = -1L;
        ((Timer) e.getSource()).stop();
        c.repaint();
        return;
      }
      Point2D pos = new Point2D.Double();
      pos.setLocation(points.get(0));
      Path2D border = new Path2D.Double();
      border.moveTo(pos.getX(), pos.getY());
      int idx = Math.min(Math.max(0, (int) (points.size() * progress)), points.size() - 1);
      for (int i = 0; i <= idx; i++) {
        pos.setLocation(points.get(i));
        border.lineTo(pos.getX(), pos.getY());
        border.moveTo(pos.getX(), pos.getY());
      }
      border.closePath();
      shape = border;
      c.repaint();
    });
    c.addFocusListener(new FocusListener() {
      @Override public void focusGained(FocusEvent e) {
        Rectangle r = c.getBounds();
        r.height -= BOTTOM_SPACE + 1;
        Path2D p = new Path2D.Double();
        p.moveTo(r.getWidth(), r.getHeight());
        p.lineTo(r.getWidth(), 0d);
        p.lineTo(0d, 0d);
        p.lineTo(0d, r.getHeight());
        p.closePath();
        makePointList(p, points);
        animator.start();
      }

      @Override public void focusLost(FocusEvent e) {
        points.clear();
        shape = null;
        c.repaint();
      }
    });
  }

  @Override public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) {
    super.paintBorder(c, g, x, y, w, h);
    Graphics2D g2 = (Graphics2D) g.create();
    g2.setPaint(c.isEnabled() ? Color.ORANGE : Color.GRAY);
    g2.translate(x, y);
    g2.setStroke(bottomStroke);
    g2.drawLine(0, h - BOTTOM_SPACE, w - 1, h - BOTTOM_SPACE);
    g2.setStroke(stroke);
    if (shape != null) {
      g2.draw(shape);
    }
    g2.dispose();
  }

  private static void makePointList(Shape shape, List points) {
    points.clear();
    PathIterator pi = shape.getPathIterator(null, .01);
    Point2D prev = new Point2D.Double();
    double delta = .02;
    double threshold = 2d;
    double[] coords = new double[6];
    while (!pi.isDone()) {
      int segment = pi.currentSegment(coords);
      Point2D current = createPoint(coords[0], coords[1]);
      if (segment == PathIterator.SEG_MOVETO) {
        points.add(current);
        prev.setLocation(current);
      } else if (segment == PathIterator.SEG_LINETO) {
        double distance = prev.distance(current);
        double fraction = delta;
        if (distance > threshold) {
          Point2D p = interpolate(prev, current, fraction);
          while (distance > prev.distance(p)) {
            points.add(p);
            fraction += delta;
            p = interpolate(prev, current, fraction);
          }
        } else {
          points.add(current);
        }
        prev.setLocation(current);
      }
      pi.next();
    }
  }

  private static Point2D createPoint(double x, double y) {
    return new Point2D.Double(x, y);
  }

  private static Point2D interpolate(Point2D start, Point2D end, double fraction) {
    double dx = end.getX() - start.getX();
    double dy = end.getY() - start.getY();
    double nx = start.getX() + dx * fraction;
    double ny = start.getY() + dy * fraction;
    return new Point2D.Double(nx, ny);
  }
}

References

2020/12/31

Use thumbnail as default Icon for JRadioButton

Code

class SelectedIcon implements Icon {
  private final Icon icon;
  private final Color color;

  protected SelectedIcon(Icon icon, Color color) {
    this.icon = icon;
    this.color = color;
  }

  @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);
    g2.translate(x, y);
    icon.paintIcon(c, g2, 0, 0);
    Path2D triangle = new Path2D.Double();
    triangle.moveTo(getIconWidth(), getIconHeight() / 2d);
    triangle.lineTo(getIconWidth(), getIconHeight());
    triangle.lineTo(getIconWidth() - getIconHeight() / 2d, getIconHeight());
    triangle.closePath();

    g2.setPaint(color);
    g2.fill(triangle);
    g2.setStroke(new BasicStroke(3f));
    g2.drawRect(0, 0, getIconWidth(), getIconHeight());
    g2.setPaint(Color.WHITE);
    Font f = g2.getFont();
    g2.drawString("?", getIconWidth() - f.getSize(), getIconHeight() - 3);
    g2.dispose();
  }

  @Override public int getIconWidth() {
    return icon.getIconWidth();
  }

  @Override public int getIconHeight() {
    return icon.getIconHeight();
  }
}

Explanation

Change the default radio button of JRadioButton to an image thumbnail and the selected state button to an icon with a border drawn on the thumbnail.

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 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);
    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/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

2011/05/24

Change border of focused row in JTable

Code

enum Type { START, END }

class DotBorder extends EmptyBorder {
  private static final BasicStroke DASHED = new BasicStroke(
      1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER,
      10f, new float[] {1f}, 0f);
  private static final Color DOT_COLOR = new Color(200, 150, 150);
  public final Set<Type> type = EnumSet.noneOf(Type.class);

  protected DotBorder(int top, int left, int bottom, int right) {
    super(top, left, bottom, right);
  }

  @Override public boolean isBorderOpaque() {
    return true;
  }

  @Override public void paintBorder(
      Component c, Graphics g, int x, int y, int w, int h) {
    Graphics2D g2 = (Graphics2D) g.create();
    g2.translate(x, y);
    g2.setPaint(DOT_COLOR);
    g2.setStroke(DASHED);
    if (type.contains(Type.START)) {
      g2.drawLine(0, 0, 0, h);
    }
    if (type.contains(Type.END)) {
      g2.drawLine(w - 1, 0, w - 1, h);
    }
    if (c.getBounds().x % 2 == 0) {
      g2.drawLine(0, 0, w, 0);
      g2.drawLine(0, h - 1, w, h - 1);
    } else {
      g2.drawLine(1, 0, w, 0);
      g2.drawLine(1, h - 1, w, h - 1);
    }
    g2.dispose();
  }
}

References