概要

JColorChooserRGB色選択パネル内に表示される16進数カラーコードをRGB6桁からAlpha値を追加したRGBA8桁に変更します。

サンプルコード

UIManager.put("ColorChooser.rgbHexCodeText", "#RGBA:");
JButton button = new JButton("open JColorChooser");
button.addActionListener(e -> {
  JColorChooser cc = new JColorChooser();
  cc.setColor(new Color(0xFF_FF_00_00, true));
  AbstractColorChooserPanel[] panels = cc.getChooserPanels();
  List<AbstractColorChooserPanel> choosers = new ArrayList<>(Arrays.asList(panels));
  AbstractColorChooserPanel ccp = choosers.get(3);
  // Java 9: if (ccp.isColorTransparencySelectionEnabled()) {
  for (Component c : ccp.getComponents()) {
    if (c instanceof JFormattedTextField) {
      // removeFocusListeners(c);
      // javax.swing.colorchooser.ValueFormatter.init(8, true, (JFormattedTextField) c);
      ValueFormatter.init((JFormattedTextField) c);
    }
  }
  cc.setChooserPanels(choosers.toArray(new AbstractColorChooserPanel[0]));

  ColorTracker ok = new ColorTracker(cc);
  Component parent = getRootPane();
  String title = "JColorChooser";
  JDialog dialog = JColorChooser.createDialog(parent, title, true, cc, ok, null);
  dialog.addComponentListener(new ComponentAdapter() {
    @Override public void componentHidden(ComponentEvent e) {
      ((Window) e.getComponent()).dispose();
    }
  });
  dialog.setVisible(true);
  Color color = ok.getColor();
  if (color != null) {
    label.setBackground(color);
  }
});

// copied from javax/swing/colorchooser/ValueFormatter.java
class ValueFormatter extends JFormattedTextField.AbstractFormatter implements FocusListener {
  private final transient DocumentFilter filter = new DocumentFilter() {
    // ...
  };

  public static void init(JFormattedTextField text) {
    ValueFormatter formatter = new ValueFormatter();
    text.setColumns(8);
    text.setFormatterFactory(new DefaultFormatterFactory(formatter));
    text.setHorizontalAlignment(SwingConstants.RIGHT);
    text.setMinimumSize(text.getPreferredSize());
    text.addFocusListener(formatter);
  }

  @Override public Object stringToValue(String text) throws ParseException {
    try {
      int r = Integer.parseInt(text.substring(0, 2), 16);
      int g = Integer.parseInt(text.substring(2, 4), 16);
      int b = Integer.parseInt(text.substring(4, 6), 16);
      int a = Integer.parseInt(text.substring(6), 16);
      return (a << 24) | (r << 16) | (g << 8) | b;
      // return Integer.valueOf(argb, 16); // <- NumberFormatException
    } catch (NumberFormatException nfe) {
      ParseException pe = new ParseException("illegal format", 0);
      pe.initCause(nfe);
      throw pe;
    }
  }

  @Override public String valueToString(Object object) throws ParseException {
    if (object instanceof Integer) {
      int value = (Integer) object;
      // String str = "00" + Integer.toHexString(value).toUpperCase();
      char[] array = new char[8];
      for (int i = array.length - 1; i >= 0; i--) {
        array[i] = Character.forDigit(value & 0x0F, 16);
        value >>= 4;
      }
      String argb = String.valueOf(array).toUpperCase(Locale.ENGLISH);
      return argb.substring(2) + argb.substring(0, 2);
    }
    throw new ParseException("illegal object", 0);
  }
}
View in GitHub: Java, Kotlin

解説

  • デフォルトJColorChooserRGB色選択パネルで16進数色コード(ColorChooser.rgbHexCodeText)表示に使用されるJFormattedTextField6桁で#RRGGBB表示
  • 16進数色コード表示用のJFormattedTextFieldを取得して16進数8桁(#RRGGBBAA)を表示するようなFormatterを設定
    • JColorChooser#getChooserPanels()AbstractColorChooserPanelの配列を取得
    • この配列の3番目からRGB色選択パネルを取得
    • AbstractColorChooserPanel#getComponents()で子要素のJFormattedTextFieldを取得
      • 赤青緑アルファ用のJSpinnerが使用するJFormattedTextFieldを取得しないよう注意
    • 16進数色コード表示用のJFormattedTextFieldsetFormatterFactory(new DefaultFormatterFactory(formatter))16進数8桁(#RRGGBBAA)を表示するFormatterを設定
      • このFormatterjavax/swing/colorchooser/ValueFormatter.javaを参考に作成
    • valueToString(Object)argb形式のInteger色値を16進数色コード文字列に変換後、argb.substring(2) + argb.substring(0, 2)rgba形式に並び替える
    • stringToValue(String)rgba形式の16進数色コード文字列をred, green, blue, alphaを表す文字列に分解してInteger.parseInt(...)Integer化し、(a << 24) | (r << 16) | (g << 8) | bで順序を並び変えて結合してargb形式のInteger色値に変換
      • 16進数6桁で使用しているInteger.valueOf(argbStr, 16)8桁で使用するとintの最大値を超えてNumberFormatExceptionが発生する場合がある
      • Integer.parseUnsignedInt(argbStr, 16)で回避可能

参考リンク

コメント