Java/Swing实现Qt中的LineEdit中的QCompleter,实现文本输入框(JTextField)的自动补全/智能提示/输入猜想。
百度搜索的时候,在搜索框中输入一些内容,后台会智能计算出一些可能的搜索内容,方便了用户。
而在Qt搭建C端界面/上位机的时候,也有一个组件,实现了自动补齐的功能。这是根据文本匹配,通过输入的内容和库中字符串进行匹配,并在下面列出候选框中的内容。
Java的界面框架Swing并没有类似的功能。本文扩展JTextField组件,即在JTextField文本输入框中,组合QComboBox的下拉框,实现类似的功能。并提供简易的添加/删除字符串库,以及常用功能的接口。
- 最终效果图
- 主要实现功能:
- 点击文本框,弹出下拉框,并显示所有库中的字符串。
- 弹出后,上下键更改选中框的选中项。
- 回车/点击弹出框,会将选中的内容放置到输入框中。
- 使用方法和JTextField一样(因为是继承的)
- 输入文本后,会自动根据文本在库中筛选结果,并放到下拉框中供选择。
- api
- addItem(String[] str),addItem(String str),addItem(Array strings)等方法均可添加字符串库。
- removeItem(String str)移除字符串库中的值。
- 实现细节:
- 将ComboBox的getPreferredSize().height设置成0,这样,就只有下拉框了。
- ComboBox添加到JTextField的BORDER.SOUTH。
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
public class ComboText extends JTextField {
private JComboBox<String> comboBox;
private Set<String> itemsSet = new HashSet<>(30);
public ComboText() {
setVisible(true);
initComboBox();
initTextField();
}
//当鼠标点击聚焦的时候,会弹出来。
@Override
public void requestFocus() {
super.requestFocus();
if (getText() == null || getText().equals(""))
setText("");
setText(getText());
}
public void addItem(String str) {
//判断一下是否重复
if (itemsSet.contains(str)) {
return;
}
comboBox.addItem(str);
itemsSet.add(str);
setText("");//保证初始化完成后TextField中内容是空。
}
public void removeItem(String str) {
if(itemsSet.contains(str)) {
itemsSet.remove(str);
}
}
public void addItem(String[] strings) {
for (String str : strings) {
addItem(str);
}
}
public void addItem(ArrayList<String> strings) {
for (String str : strings) {
addItem(str);
}
}
private void initComboBox() {
final DefaultComboBoxModel comboBoxModel = new DefaultComboBoxModel();
comboBox = new JComboBox(comboBoxModel) {
@Override
public Dimension getPreferredSize() {
return new Dimension(super.getPreferredSize().width, 0);
}
};
comboBox.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
if (comboBox.getSelectedItem() == null) {
return;
}
if(!isAdjusting(comboBox)) {
setText(comboBox.getSelectedItem().toString());
}
}
}
});
//comboBox.addItem("");这里可以加入默认的一些选项
comboBox.setSelectedItem(null);
comboBox.setEditable(true);
comboBox.setEnabled(true);
}
private void initTextField() {
setLayout(new BorderLayout());
add(comboBox, BorderLayout.SOUTH);
//获取文本编辑的时候的信息
getDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
updateList();
}
@Override
public void removeUpdate(DocumentEvent e) {
updateList();
}
@Override
public void changedUpdate(DocumentEvent e) {
updateList();
}
private void updateList() {
setAdjusting(comboBox,true);
comboBox.removeAllItems();
String containerStr = getText().trim();
if (containerStr != null && containerStr != "") {
for (String str : itemsSet) {
//通过String的contains进行判断,简洁很多。否则用正则也行
if (str.toLowerCase().contains(containerStr.toLowerCase())) {
comboBox.addItem(str);
}
}
}
//父组件是TextField,父父组件没有说明JTextField没有设置好位置,此时弹出会抛出异常
if(comboBox.getParent().getParent()!=null){
//重新弹出来一次,否则候选框的总数不知为何不会扩容只会缩容。
comboBox.setPopupVisible(false);
comboBox.setPopupVisible(true);
comboBox.setSelectedItem(null);
}
setAdjusting(comboBox,false);
}
});
addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
setAdjusting(comboBox,true);
super.mousePressed(e);
comboBox.setPopupVisible(true);
setAdjusting(comboBox,false);
}
});
addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
setAdjusting(comboBox,true);
super.keyPressed(e);
if( e.getKeyCode() == KeyEvent.VK_ENTER||e.getKeyCode() == KeyEvent.VK_UP || e.getKeyCode() == KeyEvent.VK_DOWN) {
if(e.getKeyCode() == KeyEvent.VK_UP || e.getKeyCode() == KeyEvent.VK_DOWN) {
e.setSource(comboBox);
comboBox.dispatchEvent(e);
}
if(e.getKeyCode()==KeyEvent.VK_ENTER) {
if(comboBox.getSelectedItem()!=null) {
if(comboBox.getSelectedItem()!=null) {
setText(comboBox.getSelectedItem().toString());
}
comboBox.setPopupVisible(false);
}
}
}
setAdjusting(comboBox,false);
}
});
}
private static void setAdjusting(JComboBox jComboBox, Boolean adjusting) {
jComboBox.putClientProperty("isAdjusting",adjusting);
}
private static Boolean isAdjusting(JComboBox cbInput) {
if(cbInput.getClientProperty("isAdjusting") instanceof Boolean) {
return (Boolean) cbInput.getClientProperty("isAdjusting");
}
return false;
}
}