---
category: swing
folder: ComputeTitleWidth
title: JInternalFrameのタイトル文字列幅を取得し、その値でJDesktopIconの幅を調整する
tags: [JInternalFrame, JDesktopIcon, DesktopManager, NimbusLookAndFeel]
author: aterai
pubdate: 2017-08-21T16:35:32+09:00
description: JInternalFrameのタイトル文字列幅を取得し、その値をアイコン化した場合のJDesktopIconの幅として適用します。
image: https://drive.google.com/uc?id=1cfeEsnoOvSxcwzNqjqckcWIhkgDaGxzfRA
---
* 概要 [#summary]
`JInternalFrame`のタイトル文字列幅を取得し、その値をアイコン化した場合の`JDesktopIcon`の幅として適用します。

#download(https://drive.google.com/uc?id=1cfeEsnoOvSxcwzNqjqckcWIhkgDaGxzfRA)

* サンプルコード [#sourcecode]
#code(link){{
JDesktopPane desktop = new JDesktopPane();
desktop.setDesktopManager(new DefaultDesktopManager() {
  @Override public void iconifyFrame(JInternalFrame f) {
    Rectangle r = this.getBoundsForIconOf(f);
    r.width = f.getDesktopIcon().getPreferredSize().width;
    f.getDesktopIcon().setBounds(r);
    super.iconifyFrame(f);
  }
});
desktop.add(createFrame("looooooooooooong title #", 1));
desktop.add(createFrame("#", 0));
// ...
JInternalFrame f = new JInternalFrame(t + i, true, true, true, true);
f.setDesktopIcon(new JInternalFrame.JDesktopIcon(f) {
  @Override public Dimension getPreferredSize() {
    Dimension d = super.getPreferredSize();
    String title = f.getTitle();
    Font font = getFont();
    if (Objects.nonNull(font)) {
      FontMetrics fm = getFontMetrics(font);
      int titleW = SwingUtilities.computeStringWidth(fm, title);

      // @see javax/swing/plaf/basic/BasicInternalFrameTitlePane.java
      // Handler#minimumLayoutSize(Container)
      // Calculate width.
      int buttonsW = 22;
      if (f.isClosable()) {
        buttonsW += 19;
      }
      if (f.isMaximizable()) {
        buttonsW += 19;
      }
      if (f.isIconifiable()) {
        buttonsW += 19;
      }
      Insets i = getInsets();
      // 2: Magic number of gap between icons
      d.width = buttonsW + i.left + i.right + titleW + 2 + 2 + 2;
      // 27: Magic number for NimbusLookAndFeel
      d.height = Math.min(27, d.height);
      System.out.println("BasicInternalFrameTitlePane: " + d.width);
    }
    return d;
  }

  // private void testWidth() {
  //   Dimension dim = getLayout().minimumLayoutSize(this);
  //   System.out.println("minimumLayoutSize: " + dim.width);
  //
  //   int buttonsW = SwingUtils.stream(this)
  //       .filter(AbstractButton.class::isInstance)
  //       .mapToInt(c -> c.getPreferredSize().width)
  //       .sum();
  //   System.out.println("Total width of all buttons: " + buttonsW);
  // }
});
}}

* 解説 [#explanation]
- `JInternalFrame.JDesktopIcon#getPreferredSize()`メソッドをオーバーライドし`JInternalFrame`をアイコン化した場合の推奨サイズを変更
-- [[JInternalFrameをアイコン化した場合のサイズを変更する>Swing/DesktopIconSize]]
-- `JInternalFrame`のタイトル文字列を取得し`SwingUtilities.computeStringWidth(...)`で文字列幅を計算する
--- デフォルトの`JInternalFrame`では`SwingUtilities2.stringWidth(...)`メソッドなどで省略された場合などを考慮しているがこのサンプルでは無視する
-- `ClosableButton`、`MaximizableButton`、`IconifiableButton`などの合計幅を計算する
--- `javax/swing/plaf/basic/BasicInternalFrameTitlePane.java`の`Handler#minimumLayoutSize(Container)`メソッドを参照して値を取得(`22` + `19` + `19` + `19`)
--- `JButton`を計算して`getPreferredSize().width`を合計しても値が異なる?
-- 内余白を加算して推奨サイズを返す
--- `super.getPreferredSize()`の値が初回とそれ以降で変化するため、このサンプルでは高さに固定値を使用
- `DefaultDesktopManager#iconifyFrame(JInternalFrame)`メソッドをオーバーライドして、`JInternalFrame`をアイコン化した場合の実サイズを変更
- 注:
-- このサンプルは`NimbusLookAndFeel`のみ対応で`WindowsLookAndFeel`などには未対応
- `DefaultDesktopManager#iconifyFrame(JInternalFrame)`メソッドをオーバーライドして`JInternalFrame`をアイコン化した場合の実サイズを変更
- このサンプルは`NimbusLookAndFeel`のみ対応で`WindowsLookAndFeel`などには未対応

* 参考リンク [#reference]
- [[JInternalFrameをアイコン化した場合のサイズを変更する>Swing/DesktopIconSize]]
- [https://docs.oracle.com/javase/jp/8/docs/api/javax/swing/JInternalFrame.JDesktopIcon.html JInternalFrame.JDesktopIcon (Java Platform SE 8)]
- [https://stackoverflow.com/questions/45467212/set-jinternalframe-minimised-size/45499229#45499229 java - Set JInternalFrame minimised size - Stack Overflow]

* コメント [#comment]
#comment
#comment