• category: swing folder: SelectFileNameWithoutExtension title: JFileChooserのセルエディタでリネームを開始したとき拡張子を除くファイル名を選択状態にする tags: [JFileChooser, JTextField, JList, ContainerListener, JTable, FocusListener, DefaultCellEditor] author: aterai pubdate: 2023-10-01T00:44:38+09:00 description: JFileChooserのListViewやDetailsViewでリネーム可能なセルエディタとして使用されるJTextFieldを取得し、ファイル名全体ではなく拡張子を除くファイル名が選択状態になるよう設定します。 image: https://drive.google.com/uc?id=1Q83JplI4_5QHhy5qekG6vSDpBZmQYuQv

概要

JFileChooserのListViewやDetailsViewでリネーム可能なセルエディタとして使用されるJTextFieldを取得し、ファイル名全体ではなく拡張子を除くファイル名が選択状態になるよう設定します。

サンプルコード

JButton button2 = new JButton("ListView");
button2.addActionListener(e -> {
  JFileChooser chooser = new JFileChooser();
  descendants(chooser)
      .filter(JList.class::isInstance)
      .map(JList.class::cast)
      .findFirst()
      .ifPresent(MainPanel::addCellEditorListener);
  int retValue = chooser.showOpenDialog(log.getRootPane());
  if (retValue == JFileChooser.APPROVE_OPTION) {
    log.setText(chooser.getSelectedFile().getAbsolutePath());
  }
});
// ...
private static void selectWithoutExtension(JTextField editor) {
  EventQueue.invokeLater(() -> {
    String name = editor.getText();
    int end = name.lastIndexOf('.');
    editor.setSelectionStart(0);
    editor.setSelectionEnd(end > 0 ? end : name.length());
  });
}

private static void addCellEditorListener(JList<?> list) {
  boolean readOnly = UIManager.getBoolean("FileChooser.readOnly");
  if (!readOnly) {
    list.addContainerListener(new ContainerAdapter() {
      @Override public void componentAdded(ContainerEvent e) {
        Component c = e.getChild();
        if (c instanceof JTextField && "Tree.cellEditor".equals(c.getName())) {
          selectWithoutExtension((JTextField) c);
        }
      }
    });
  }
}
View in GitHub: Java, Kotlin

解説

  • Default
    • デフォルトのJFileChooserのセルエディタは編集開始時にJTextField#selectAll()でファイル名が全選択される
  • ListView(JList)
    • デフォルトのJListにはセルアイテムを編集するエディタは用意されていないので、JFileChooser(FilePane)では名前がTree.cellEditorJTextFieldJListに追加してセルエディタとしている
    • JListContainerListenerを追加し、セルエディタのJTextFieldが追加(ContainerListener#componentAdded(ContainerEvent))されたらJTextField#setSelectionEnd(...)などで拡張子を除くファイル名が選択状態になるよう設定
  • DetailsView(JTable)
    • ファイル名を表示する0列目のTableColumnからTableColumn#getCellEditor()#getComponent()でセルエディタとして使用するJTextFieldを取得
    • 取得したJTextFieldFocusListenerを追加し、フォーカスが当たったら(FocusListener#focusGained(FocusEvent))拡張子を除くファイル名が選択状態になるよう設定
    • マウスでファイル名のセルを選択したあと、シングルクリックでリネーム開始するとセルエディタが表示されるまでに想定外のタイムラグが発生する?
      • F2でのリネーム開始は正常に動作している
JButton button3 = new JButton("DetailsView");
button3.addActionListener(e -> {
  JFileChooser chooser = new JFileChooser();
  String cmd = "viewTypeDetails";
  Action detailsAction = chooser.getActionMap().get(cmd);
  if (Objects.nonNull(detailsAction)) {
    detailsAction.actionPerformed(new ActionEvent(chooser, ActionEvent.ACTION_PERFORMED, cmd));
  }
  descendants(chooser)
      .filter(JTable.class::isInstance)
      .map(JTable.class::cast)
      .findFirst()
      .ifPresent(MainPanel::addCellEditorFocusListener);
  int retValue = chooser.showOpenDialog(log.getRootPane());
  if (retValue == JFileChooser.APPROVE_OPTION) {
    log.setText(chooser.getSelectedFile().getAbsolutePath());
  }
});
// ...
private static void addCellEditorFocusListener(JTable table) {
  boolean readOnly = UIManager.getBoolean("FileChooser.readOnly");
  TableColumnModel columnModel = table.getColumnModel();
  if (!readOnly && columnModel.getColumnCount() > 0) {
    TableColumn tc = columnModel.getColumn(0);
    DefaultCellEditor editor = (DefaultCellEditor) tc.getCellEditor();
    JTextField tf = (JTextField) editor.getComponent();
    tf.addFocusListener(new FocusAdapter() {
      @Override public void focusGained(FocusEvent e) {
        selectWithoutExtension(tf);
      }
    });
  }
}

参考リンク

コメント