Summary

JTextFieldでタグの追加、JLabelでタグの表示、JButtonでタグの削除を実行するタグ入力コンポーネントを作成します。

Source Code Examples

class TagInputPanel extends JPanel {
  private final List<String> tags = new ArrayList<>();
  private final JTextField textField = new JTextField(15);
  private final JPanel tagContainer = new JPanel(new FlowLayout(FlowLayout.LEFT)) {
    @Override public void updateUI() {
      super.updateUI();
      setBackground(UIManager.getColor("TextField.background"));
    }
  };

  protected TagInputPanel() {
    super(new BorderLayout());
    textField.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
    textField.addActionListener(e -> {
      String text = textField.getText().trim();
      if (!text.isEmpty() && !tags.contains(text)) {
        addTag(text);
        textField.setText("");
      }
    });
    textField.addKeyListener(new KeyAdapter() {
      @Override public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_BACK_SPACE &&
            textField.getText().isEmpty()) {
          removeLastTag();
          e.consume();
        }
      }
    });
    tagContainer.add(textField);
    add(new JScrollPane(tagContainer));
  }

  @Override public void updateUI() {
    super.updateUI();
    setBorder(UIManager.getBorder("TextField.border"));
    setBackground(UIManager.getColor("TextField.background"));
  }

  private void addTag(String text) {
    JPanel tag = new JPanel(new BorderLayout(5, 0));
    tag.setName(text);
    tag.setBackground(new Color(230, 245, 255));
    Color color = UIManager.getColor("Table.selectionBackground");
    tag.setBorder(BorderFactory.createCompoundBorder(
        BorderFactory.createLineBorder(color),
        BorderFactory.createEmptyBorder(3, 5, 3, 5)
    ));
    tags.add(text);
    tag.add(new JLabel(text));
    tag.add(makeCloseButton(tag), BorderLayout.EAST);
    tagContainer.add(tag, tagContainer.getComponentCount() - 1);
    resizeAndRepaint();
  }

  private JButton makeCloseButton(JPanel tag) {
    JButton closeBtn = new JButton("×") {
      @Override public void updateUI() {
        super.updateUI();
        setContentAreaFilled(false);
        setFocusPainted(false);
        setFocusable(false);
        setBorder(BorderFactory.createEmptyBorder());
      }
    };
    closeBtn.addActionListener(e -> {
      tags.remove(tag.getName());
      tagContainer.remove(tag);
      resizeAndRepaint();
    });
    closeBtn.addMouseListener(new MouseAdapter() {
      @Override public void mouseEntered(MouseEvent e) {
        e.getComponent().setForeground(Color.RED);
      }

      @Override public void mouseExited(MouseEvent e) {
        e.getComponent().setForeground(UIManager.getColor("Button.foreground"));
      }
    });
    return closeBtn;
  }

  private void removeLastTag() {
    int count = tagContainer.getComponentCount();
    boolean moreThanOne = count > 1;
    if (moreThanOne) {
      tags.remove(tags.size() - 1); // Java 21: .removeLast();
      tagContainer.remove(count - 2);
      resizeAndRepaint();
    }
  }

  // ...
}
View in GitHub: Java, Kotlin

Description

  • タグコンポーネントはnew JPanel(new BorderLayout(5, 0))で作成したJPanelの中央にタグ文字列用のJLabelBorderLayout.EASTに削除用のJButtonを配置して作成
  • これらのタグコンポーネントを左揃えで配置するようnew JPanel(new FlowLayout(FlowLayout.LEFT, 5, 5))でタグ配置コンテナを作成
  • EmptyBorderで枠線を非表示にしてタグ入力用のJTextFieldを作成
    • JTextFieldActionListenerを追加しEnterキーでタグ追加アクションとJTextFieldのクリアを実行
    • JTextFieldKeyListenerを追加しBackSpaceキーで末尾タグの削除とbeep音のキャンセルを実行
  • タグ配置コンテナにContainerListenerを追加し、タグ追加でcomponentAdded、タグ削除でcomponentRemovedが実行されると現在のタグ一覧をカンマ区切りでログ出力
JTextArea log = new JTextArea();
TagInputPanel tagInput = new TagInputPanel();
tagInput.getTagContainer().addContainerListener(new ContainerListener() {
  @Override public void componentAdded(ContainerEvent e) {
    log.setText(String.join(", ", tagInput.getTags()));
  }

  @Override public void componentRemoved(ContainerEvent e) {
    log.setText(String.join(", ", tagInput.getTags()));
  }
});

Reference

Comment