Swing/FileChooserBottomAccessory の変更点
- 追加された行はこの色です。
- 削除された行はこの色です。
- Swing/FileChooserBottomAccessory へ行く。
- Swing/FileChooserBottomAccessory の差分を削除
--- category: swing folder: FileChooserBottomAccessory title: MetalLookAndFeelでJFileChooserの下部にコンポーネントを追加する tags: [JFileChooser, MetalLookAndFeel] author: aterai pubdate: 2017-08-14T15:32:42+09:00 description: MetalLookAndFeelを適用しているJFileChooserのファイルフィルタとボタンパネルの間にJComboBoxのような横長のコンポーネントを追加します。 image: https://drive.google.com/uc?id=1Nyb4wo_ryaaCsJEgpGBxbIlYazx3FQVFfw hreflang: href: https://java-swing-tips.blogspot.com/2017/09/add-jcombobox-that-selects-encoding-at.html lang: en --- * 概要 [#summary] `MetalLookAndFeel`を適用している`JFileChooser`のファイルフィルタとボタンパネルの間に`JComboBox`のような横長のコンポーネントを追加します。 #download(https://drive.google.com/uc?id=1Nyb4wo_ryaaCsJEgpGBxbIlYazx3FQVFfw) * サンプルコード [#sourcecode] #code(link){{ class EncodingFileChooserUI extends MetalFileChooserUI { public final JComboBox<String> combo = new JComboBox<>( new String[] {"UTF-8", "UTF-16", "Shift_JIS", "EUC-JP"}); protected EncodingFileChooserUI(JFileChooser filechooser) { super(filechooser); } @Override public void installComponents(JFileChooser fc) { super.installComponents(fc); JPanel bottomPanel = getBottomPanel(); JLabel label = new JLabel("Encoding:") { @Override public Dimension getPreferredSize() { return SwingUtils.stream(bottomPanel) .filter(JLabel.class::isInstance).map(JLabel.class::cast) .findFirst() .map(JLabel::getPreferredSize) .orElse(super.getPreferredSize()); } }; label.setDisplayedMnemonic('E'); label.setLabelFor(combo); JPanel panel = new JPanel(); panel.setLayout(new BoxLayout(panel, BoxLayout.LINE_AXIS)); panel.add(label); panel.add(combo); // 0: fileNamePanel // 1: RigidArea // 2: filesOfTypePanel bottomPanel.add(Box.createRigidArea(new Dimension(1, 5)), 3); bottomPanel.add(panel, 4); SwingUtils.stream(bottomPanel) .filter(JLabel.class::isInstance).map(JLabel.class::cast) .forEach(l -> { l.setHorizontalAlignment(SwingConstants.RIGHT); l.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5)); }); } } }} * 解説 [#explanation] - `JFileChooser#setAccessory(JComponent)`を使用すると`JFileChooser`の右側にコンポーネントが追加されるので、横長のコンポーネントを追加すると`JFileChooser`全体の幅が広がってしまう -- [[JFileChooserに画像プレビューを追加>Swing/PreviewAccessory]] - `BasicFileChooserUI#getBottomPanel()`メソッドでファイル名入力欄、ファイルフィルタ、ボタンなどを格納している下部パネルを取得し、「ファイルのタイプ(`T`)」パネルとボタンパネルの間に`JComboBox`のような横長のコンポーネントを設定した別パネルを追加 -- `MetalFileChooserUI`の場合、`2`番目の`filesOfTypePanel`の直後になるよう`bottomPanel.add(Box.createRigidArea(vstrut5), 3); bottomPanel.add(encodingPanel, 4)`で追加 --- [https://docs.oracle.com/javase/jp/8/docs/api/java/awt/Container.html#add-java.awt.Component-int- Container#add(Component, int) (Java Platform SE 8)] -- `BasicFileChooserUI#getBottomPanel()`で取得できる`JPanel`内のレイアウトは、`LookAndFeel`ごとに大きく異なるため同じ方法は使用できない -- `BasicFileChooserUI#getBottomPanel()`で取得できる`JPanel`内のレイアウトは`LookAndFeel`ごとに大きく異なるため同じ方法は使用できない --- 例えば`WindowsLookAndFeel`では`BoxLayout.LINE_AXIS`、`MetalLookAndFeel`では`BoxLayout.Y_AXIS` -- `MetalFileChooserUI`では`JLabel`を継承する`AlignedLabel`で最も長い文字列幅から推奨サイズを揃えているが、`private`のためこのサンプルでは使用できない --- [[Containerの子Componentを再帰的にすべて取得する>Swing/GetComponentsRecursively]]でラベルを検索して推奨サイズを取得しているが、もし`Encoding:`がこの最も長い文字列幅より長い場合は末尾が省略されてしまう - `JFileChooser#updateUI()`メソッドをオーバーライドして`super.updateUI(); setUI(new EncodingFileChooserUI(this));`などを実行した場合、`AcceptAll`ファイルフィルタが重複追加されてしまう -- `setUI(...)`の後で`JFileChooser#resetChoosableFileFilters()`を実行するか、`super.updateUI()`を実行しないことで回避可能 --- 個別のファイルフィルタ追加などの設定は`JFileChooser#updateUI()`メソッド内で実施する * 参考リンク [#reference] - [[JFileChooserに画像プレビューを追加>Swing/PreviewAccessory]] - [[Containerの子Componentを再帰的にすべて取得する>Swing/GetComponentsRecursively]] - [https://docs.oracle.com/javase/jp/8/docs/api/java/awt/Container.html#add-java.awt.Component-int- Container#add(Component, int) (Java Platform SE 8)] * コメント [#comment] #comment #comment