トップ 一覧 置換 検索 ヘルプ RSS ログイン

Swingのラベル等の文字列省略についての変更点

  • 追加された行はこのように表示されます。
  • 削除された行はこのように表示されます。
http://www.ne.jp/asahi/hishidama/home/tech/java/swing/JLabel.html

!!!JLabel等の文字列の省略
JLabelやJComboBoxなどで表示されている文字列がコンポーネントのサイズを超えると、文字列の最後が「...」になって省略される。

これは、BasicLabelUI#layoutCL() から SwingUtilities.layoutCompoundLabel() を呼び出して、省略した文字列の取得や表示座標を計算している。

!!省略文字列を変更する
JLabelやJComboboxの省略文字を変更するにはオリジナルのLabelUIを作成して省略文字の処理を変更する

!サンプル
以下は、文字列の最後ではなく、途中を省略するサンプル。
真ん中の左右の文字列の幅は、プロポーショナルフォントを考慮して、バイナリサーチで計算する。

{{code Java,
class MetalLabelUIForMiddleClip extends MetalLabelUI {
  protected String layoutCL(
    JLabel label,                  
    FontMetrics fontMetrics, 
    String text, 
    Icon icon, 
    Rectangle viewR, 
    Rectangle iconR, 
    Rectangle textR)
  {
    String clipString = "...";
    int clipLength = clipString.length();
    int clipWidth = fontMetrics.stringWidth(clipString);
    
    int width = viewR.width - viewR.x;
    width = width - (icon.getIconWidth() + label.getIconTextGap());
    if (icon != null){
      width = width - (icon.getIconWidth() + label.getIconTextGap());
    }
    
    // 超える可能性あり
    if (fontMetrics.stringWidth(text) > width ){
      // System.out.println(viewR);
      // System.out.println(iconR);
      // System.out.println(icon.getIconWidth());
      // System.out.println(label.getIconTextGap());
      
      int middleWidth = (width - clipWidth ) / 2;
      
      int length = text.length();
      int middle = length / 2;
      
      String left = text.substring(0, middle);
      left = cutString(left, fontMetrics, middleWidth);
      
      String right = text.substring(middle, length);
      StringBuilder sb = new StringBuilder(right);
      ;
      right = sb.reverse().toString();
      right = cutString(right, fontMetrics, middleWidth);
      sb.delete(0, sb.length());
      right = sb.append(right).reverse().toString();
      
      sb.delete(0, sb.length());
      sb.append(left).append("...").append(right);
      // System.out.println(left);
      // System.out.println(right);
      text = sb.toString();
    }
    // System.out.println(text);
    
    return SwingUtilities.layoutCompoundLabel(
      (JComponent) label,
      fontMetrics,
      text,
      icon,
      label.getVerticalAlignment(),
      label.getHorizontalAlignment(),
      label.getVerticalTextPosition(),
      label.getHorizontalTextPosition(),
      viewR,
      iconR,
      textR,
      label.getIconTextGap());
  }
  
  protected String cutString(String text, FontMetrics fm, int width){
    if (width <= 0){
      return "";
    }
    
    if (fm.stringWidth(text) <= width){
      return text;
    }
    
    int left = 0;
    int right = text.length();
    int middle = 0;
    while(right - left > 1){
      middle = left + (right - left) / 2;
      if (fm.stringWidth(text.substring(0, middle)) > width){
        right = middle;
      } else {
        left = middle;
      }
    }
    
    // 最後の2つのどちらか
    if (fm.stringWidth(text.substring(0, right)) > width){
      right = left;
    }
    return text.substring(0, right);
  }
}
}}

このLabelUIを使うには

JLabelの場合
 JLabel test = new JLabel("aaaaaaaaaaaaaaaaaaaaaaaaaaaa");
 test.setUI(new MetalLabelUIForMiddleClip ());

JComboBoxの場合
  JComboBox cb = new JComboBox(new Object[]{"aaaaaaaaaaaaaaaa"});
  ListCellRenderer renderer =  cb.getRenderer();
  if (!(renderer instanceof JLabel)){
    return;
  }
  LabelUI labelui = ((JLabel)renderer).getUI();
  if (!MetalLabelUI.class.equals(labelui.getClass())){
    return;
  }
  ((JLabel)renderer).setUI(new MetalLabelUIForMiddleClip());

{{category2 プログラミング言語,Java}}