Je souhaite créer une zone de texte de suggestion automatique qui interrogerait la base de données à chaque événement clé de libération . Cette partie est simple, mais je souhaite lui donner un aspect visuel. Quelque chose de semblable à la zone de texte de suggestion automatique que nous voyons dans les sites Web, comme la recherche dans Facebook.
Comment faire une telle interface?
Une idée naïve consisterait à placer une liste JList juste en dessous de la zone de texte et à la rendre visible avec les résultats lors de la recherche.
Une meilleure idée ou un moyen standard de le faire?
Une méthode très simple consiste à utiliser l'implémentation GlazedList
de l'auto-complétion. Il est très facile de se lever et de courir. Vous pouvez le trouver ici .
Vous pouvez installer l'auto-complétion sur une JComboBox avec une seule ligne de code Glazed, comme ceci:
JComboBox comboBox = new JComboBox();
Object[] elements = new Object[] {"Cat", "Dog", "Lion", "Mouse"};
AutoCompleteSupport.install(comboBox, GlazedLists.eventListOf(elements));
De plus, SwingX
prend en charge la saisie automatique et pourrait être plus facile à utiliser que GlazedList
. Tout ce que vous écrivez avec SwingX
est AutoCompleteDecorator.decorate(comboBox);
Pour utiliser la classe TextAutoCompleter, vous devez télécharger un fichier jar, AutoCompleter.jar, et l'ajouter au dossier de bibliothèque de votre projet. Voici le lien pour le télécharger: http://download1689.mediafire.com/4grrthscpsug/7pwzgefiomu392o/AutoCompleter.jar -Nawin
// Dans la classe Main, écrivez le code suivant
package autocomplete;
import com.mxrck.autocompleter.TextAutoCompleter;
import Java.sql.SQLException;
import javax.swing.JFrame;
import javax.swing.JTextField;
public class AutoComplete {
JFrame f=new JFrame();
JTextField t1;
AutoComplete() throws ClassNotFoundException, SQLException{
f.setSize(500,500);
f.setLocation(500,100);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLayout(null);
f.setVisible(true);
t1=new JTextField();
t1.setBounds(50,80,200,20);
f.add(t1);
TextAutoCompleter complete=new TextAutoCompleter(t1);
DBConn conn=new DBConn();
conn.connection();
conn.retrieve();
while(conn.rs.next()){
complete.addItem(conn.rs.getString("number"));
}
}
public static void main(String[] args) throws ClassNotFoundException,
SQLException{
new AutoComplete();
}
}
//Create seperate class for database connection and write the following code
package autocomplete;
import Java.sql.Connection;
import Java.sql.DriverManager;
import Java.sql.PreparedStatement;
import Java.sql.ResultSet;
import Java.sql.SQLException;
import Java.sql.Statement;
public class DBConn {
Connection con; ResultSet rs;PreparedStatement stat;
public void connection() throws ClassNotFoundException, SQLException{
String url="jdbc:mysql://localhost:3306/";
String driver="com.mysql.jdbc.Driver";
String db="demo";
String username="root";
String password="root";
stat =null;
Class.forName(driver);
con=(Connection)DriverManager.getConnection
(url+db,username,password);
System.out.println("Connecttion SuccessFul");
}
public void retrieve() throws SQLException{
Statement stmt=con.createStatement();
String query="select number from phone";
rs = stmt.executeQuery(query);
System.out.println("retrieve succesfully");
}
}
Construit sur le dessus de Davidsolution :
J'ai ajouté des fonctionnalités pour le UP clé, ainsi que la fonctionnalité ajoutée pour la ESC clé afin de cacher la fenêtre popup. En plus de cela, vous pouvez spécifier une fonction de rappel lors de la construction d'un objet AutoSuggestor
, qui sera appelé lorsqu'une suggestion de la liste est sélectionnée.
import javax.swing.border.LineBorder
import Java.util.ArrayList
import javax.swing.event.DocumentListener
import Java.awt.*
import Java.awt.event.*
import javax.swing.*
import javax.swing.event.DocumentEvent
/**
* Author of the original version: David @ https://stackoverflow.com/users/1133011/david-kroukamp
*/
class Test {
init {
val frame = JFrame()
frame.defaultCloseOperation = JFrame.EXIT_ON_CLOSE
val f = JTextField(10)
val autoSuggestor = object : AutoSuggestor(f, frame, ArrayList(), Color.WHITE.brighter(), Color.BLUE, Color.RED, 0.75f) {
override fun wordTyped(typedWord: String?): Boolean {
//create list for dictionary this in your case might be done via calling a method which queries db and returns results as arraylist
val words = ArrayList<String>()
words.add("hello")
words.add("heritage")
words.add("happiness")
words.add("goodbye")
words.add("cruel")
words.add("car")
words.add("war")
words.add("will")
words.add("world")
words.add("wall")
setDictionary(words)
//addToDictionary("bye");//adds a single Word
return super.wordTyped(typedWord)//now call super to check for any matches against newest dictionary
}
}
val p = JPanel()
p.add(f)
frame.add(p)
frame.pack()
frame.isVisible = true
}
companion object {
@JvmStatic
fun main(args: Array<String>) {
SwingUtilities.invokeLater { Test() }
}
}
}
internal open class AutoSuggestor(val textField: JTextField, val container: Window, words: ArrayList<String>, popUpBackground: Color, private val suggestionsTextColor: Color, private val suggestionFocusedColor: Color, opacity: Float, private val callback: (String) -> Unit = {}) {
private val suggestionsPanel: JPanel
val autoSuggestionPopUpWindow: JWindow
private var typedWord: String? = null
private val dictionary = ArrayList<String>()
private var currentIndexOfSpace: Int = 0
private var tW: Int = 0
private var tH: Int = 0
private val documentListener = object : DocumentListener {
override fun insertUpdate(de: DocumentEvent) {
checkForAndShowSuggestions()
}
override fun removeUpdate(de: DocumentEvent) {
checkForAndShowSuggestions()
}
override fun changedUpdate(de: DocumentEvent) {
checkForAndShowSuggestions()
}
}
val addedSuggestionLabels: ArrayList<SuggestionLabel>
get() {
val sls = ArrayList<SuggestionLabel>()
for (i in 0 until suggestionsPanel.componentCount) {
if (suggestionsPanel.getComponent(i) is SuggestionLabel) {
val sl = suggestionsPanel.getComponent(i) as SuggestionLabel
sls.add(sl)
}
}
return sls
}
//get newest Word after last white space if any or the first Word if no white spaces
val currentlyTypedWord: String
get() {
val text = textField.text
var wordBeingTyped = ""
if (text.contains(" ")) {
val tmp = text.lastIndexOf(" ")
if (tmp >= currentIndexOfSpace) {
currentIndexOfSpace = tmp
wordBeingTyped = text.substring(text.lastIndexOf(" "))
}
} else {
wordBeingTyped = text
}
return wordBeingTyped.trim { it <= ' ' }
}
init {
this.textField.document.addDocumentListener(documentListener)
setDictionary(words)
typedWord = ""
currentIndexOfSpace = 0
tW = 0
tH = 0
autoSuggestionPopUpWindow = JWindow(container)
autoSuggestionPopUpWindow.opacity = opacity
suggestionsPanel = JPanel()
suggestionsPanel.layout = GridLayout(0, 1)
suggestionsPanel.background = popUpBackground
addFocusListenersToHandleVisibilityOfPopUpWindow()
addKeyBindingToRequestFocusInPopUpWindow()
}
private fun addFocusListenersToHandleVisibilityOfPopUpWindow() {
textField.addFocusListener(object:FocusListener {
override fun focusLost(e: FocusEvent?) {
var focusOnPopUp = false
for (i in 0 until suggestionsPanel.componentCount) {
if (suggestionsPanel.getComponent(i) is SuggestionLabel) {
val label = suggestionsPanel.getComponent(i) as SuggestionLabel
if (label.isFocused)
focusOnPopUp = true
}
}
if (!focusOnPopUp && !shouldShowPopUpWindow) {
autoSuggestionPopUpWindow.isVisible = false
}
}
override fun focusGained(e: FocusEvent?) {
shouldShowPopUpWindow = false
}
})
}
private fun addKeyBindingToRequestFocusInPopUpWindow() {
textField.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, true), "Escape released")
textField.actionMap.put("Escape released", object : AbstractAction() {
override fun actionPerformed(ae: ActionEvent) {// Hide the popwindow
shouldShowPopUpWindow = false
autoSuggestionPopUpWindow.isVisible = false
}
})
textField.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, true), "Down released")
textField.actionMap.put("Down released", object : AbstractAction() {
override fun actionPerformed(ae: ActionEvent) {//focuses the first label on popwindow
for (i in 0 until suggestionsPanel.componentCount) {
if (suggestionsPanel.getComponent(i) is SuggestionLabel) {
(suggestionsPanel.getComponent(i) as SuggestionLabel).isFocused = true
autoSuggestionPopUpWindow.toFront()
autoSuggestionPopUpWindow.requestFocusInWindow()
suggestionsPanel.requestFocusInWindow()
suggestionsPanel.getComponent(i).requestFocusInWindow()
break
}
}
}
})
textField.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, true), "Up released")
textField.actionMap.put("Up released", object : AbstractAction() {
override fun actionPerformed(ae: ActionEvent) {//focuses the last label on popwindow
for (i in 0 until suggestionsPanel.componentCount) {
val reverseIndex = suggestionsPanel.componentCount-1 - i
if (suggestionsPanel.getComponent(reverseIndex) is SuggestionLabel) {
(suggestionsPanel.getComponent(reverseIndex) as SuggestionLabel).isFocused = true
autoSuggestionPopUpWindow.toFront()
autoSuggestionPopUpWindow.requestFocusInWindow()
suggestionsPanel.requestFocusInWindow()
suggestionsPanel.getComponent(reverseIndex).requestFocusInWindow()
break
}
}
}
})
suggestionsPanel.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, true), "Escape released")
suggestionsPanel.actionMap.put("Escape released", object : AbstractAction() {
override fun actionPerformed(ae: ActionEvent) {// Hide the popwindow
shouldShowPopUpWindow = false
autoSuggestionPopUpWindow.isVisible = false
}
})
suggestionsPanel.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, true), "Up released")
suggestionsPanel.actionMap.put("Up released", object : AbstractAction() {
override fun actionPerformed(ae: ActionEvent) {//allows scrolling of labels in pop window (I know very hacky for now :))
val sls = addedSuggestionLabels
val max = sls.size
var indexOfFocusedSuggestion = -1
for (i in 0 until max) {
val sl = sls[i]
if ( sl.isFocused )
indexOfFocusedSuggestion = i
}
if (indexOfFocusedSuggestion - 1 < 0) {
sls[indexOfFocusedSuggestion].isFocused = false
autoSuggestionPopUpWindow.isVisible = false
setFocusToTextField()
checkForAndShowSuggestions()//fire method as if document listener change occured and fired it
}
else {
sls[indexOfFocusedSuggestion].isFocused = false
sls[indexOfFocusedSuggestion-1].isFocused = true
autoSuggestionPopUpWindow.toFront()
autoSuggestionPopUpWindow.requestFocusInWindow()
suggestionsPanel.requestFocusInWindow()
suggestionsPanel.getComponent(indexOfFocusedSuggestion-1).requestFocusInWindow()
}
}
})
suggestionsPanel.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, true), "Down released")
suggestionsPanel.actionMap.put("Down released", object : AbstractAction() {
override fun actionPerformed(ae: ActionEvent) {//allows scrolling of labels in pop window (I know very hacky for now :))
val sls = addedSuggestionLabels
val max = sls.size
var indexOfFocusedSuggestion = -1
for (i in 0 until max) {
val sl = sls[i]
if ( sl.isFocused )
indexOfFocusedSuggestion = i
}
if (indexOfFocusedSuggestion + 1 >= max) {
sls[indexOfFocusedSuggestion].isFocused = false
autoSuggestionPopUpWindow.isVisible = false
setFocusToTextField()
checkForAndShowSuggestions()//fire method as if document listener change occured and fired it
}
else {
sls[indexOfFocusedSuggestion].isFocused = false
sls[indexOfFocusedSuggestion+1].isFocused = true
autoSuggestionPopUpWindow.toFront()
autoSuggestionPopUpWindow.requestFocusInWindow()
suggestionsPanel.requestFocusInWindow()
suggestionsPanel.getComponent(indexOfFocusedSuggestion+1).requestFocusInWindow()
}
}
})
}
private fun setFocusToTextField() {
container.toFront()
container.requestFocusInWindow()
textField.requestFocusInWindow()
}
var shouldShowPopUpWindow = false
private fun checkForAndShowSuggestions() {
typedWord = currentlyTypedWord
suggestionsPanel.removeAll()//remove previos words/jlabels that were added
//used to calcualte size of JWindow as new Jlabels are added
tW = 0
tH = 0
val added = wordTyped(typedWord)
if (!added) {
if (autoSuggestionPopUpWindow.isVisible) {
autoSuggestionPopUpWindow.isVisible = false
}
} else {
shouldShowPopUpWindow = true
showPopUpWindow()
setFocusToTextField()
}
}
protected fun addWordToSuggestions(Word: String) {
val suggestionLabel = SuggestionLabel(Word, suggestionFocusedColor, suggestionsTextColor, this, callback)
calculatePopUpWindowSize(suggestionLabel)
suggestionsPanel.add(suggestionLabel)
}
private fun calculatePopUpWindowSize(label: JLabel) {
//so we can size the JWindow correctly
if (tW < label.preferredSize.width) {
tW = label.preferredSize.width
}
tH += label.preferredSize.height
}
private fun showPopUpWindow() {
autoSuggestionPopUpWindow.contentPane.add(suggestionsPanel)
autoSuggestionPopUpWindow.minimumSize = Dimension(textField.width, 30)
autoSuggestionPopUpWindow.setSize(tW, tH)
autoSuggestionPopUpWindow.isVisible = true
var windowX = 0
var windowY = 0
windowX = container.getX() + textField.x + 5
if (suggestionsPanel.height > autoSuggestionPopUpWindow.minimumSize.height) {
windowY = container.getY() + textField.y + textField.height + autoSuggestionPopUpWindow.minimumSize.height
} else {
windowY = container.getY() + textField.y + textField.height + autoSuggestionPopUpWindow.height
}
autoSuggestionPopUpWindow.setLocation(windowX, windowY)
autoSuggestionPopUpWindow.minimumSize = Dimension(textField.width, 30)
autoSuggestionPopUpWindow.revalidate()
autoSuggestionPopUpWindow.repaint()
}
fun setDictionary(words: ArrayList<String>?) {
dictionary.clear()
if (words == null) {
return //so we can call constructor with null value for dictionary without exception thrown
}
for (Word in words) {
dictionary.add(Word)
}
}
fun addToDictionary(Word: String) {
dictionary.add(Word)
}
open fun wordTyped(typedWord: String?): Boolean {
if (typedWord!!.isEmpty()) {
return false
}
var suggestionAdded = false
for (Word in dictionary) {//get words in the dictionary which we added
var fullyMatches = Word.length >= typedWord.length
for (i in 0 until typedWord.length) {//each string in the Word
if (Word.length > i && !typedWord.toLowerCase().startsWith(Word.toLowerCase()[i].toString(), i)) {//check for match
fullyMatches = false
break
}
}
if (fullyMatches) {
addWordToSuggestions(Word)
suggestionAdded = true
}
}
return suggestionAdded
}
}
internal class SuggestionLabel(string: String, private val suggestionBorderColor: Color, private val suggestionsTextColor: Color, private val autoSuggestor: AutoSuggestor, private val callback: (String) -> Unit) : JLabel(string) {
var isFocused = false
set(focused) {
if (focused) {
border = LineBorder(suggestionBorderColor)
} else {
border = null
}
repaint()
field = focused
}
private val autoSuggestionsPopUpWindow: JWindow
private val textField: JTextField
init {
this.textField = autoSuggestor.textField
this.autoSuggestionsPopUpWindow = autoSuggestor.autoSuggestionPopUpWindow
initComponent()
}
private fun initComponent() {
isFocusable = true
foreground = suggestionsTextColor
addMouseListener(object : MouseAdapter() {
override fun mouseClicked(me: MouseEvent) {
super.mouseClicked(me)
replaceWithSuggestedText()
autoSuggestionsPopUpWindow.isVisible = false
}
})
getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, true), "Enter released")
actionMap.put("Enter released", object : AbstractAction() {
override fun actionPerformed(ae: ActionEvent) {
replaceWithSuggestedText()
autoSuggestionsPopUpWindow.isVisible = false
}
})
getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, true), "Escape released")
actionMap.put("Escape released", object : AbstractAction() {
override fun actionPerformed(ae: ActionEvent) {// Hide the popwindow
autoSuggestionsPopUpWindow.isVisible = false
}
})
}
private fun replaceWithSuggestedText() {
val suggestedWord = text
val text = textField.text
val typedWord = autoSuggestor.currentlyTypedWord
val t = text.substring(0, text.lastIndexOf(typedWord))
val tmp = t + text.substring(text.lastIndexOf(typedWord)).replace(typedWord, suggestedWord)
textField.text = tmp
callback(tmp)
}
}
Remarque: Le texte ci-dessus est écrit en Kotlin, mais si vous voulez vraiment du code Java, vous pouvez facilement le reconvertir en Java .
Je voulais l'auto-complétion pour l'éditeur dans mon assembleur AVR IDE alors j'ai écrit une implémentation qui fonctionne exactement comme l'auto-complétion dans Eclipse (activation CTRL-SPACE, liste déroulante avec barres de défilement, curseur touches + navigation de la souris). Il n'a pas de dépendances externes et est juste une classe unique. Cela devrait fonctionner pour toutes les sous-classes JTextComponent; vous pouvez trouver un exemple d'utilisation dans le dossier src/test.
Une méthode de travail que j'ai utilisée dans un projet consistait à placer un JTextField au-dessus d'un JComboBox et à ouvrir la liste déroulante sous-jacente lorsque vous tapez dans le JTextField à l'aide d'un écouteur de document. Vous voulez probablement qu'un modèle de liste déroulante personnalisé permette de modifier les éléments plus efficacement, car le modèle par défaut autorise uniquement l'ajout d'éléments, ce qui peut nuire à la performance. pour ouvrir la liste déroulante, je pense qu'il existe une méthode pour l'afficher si vous obtenez son interface utilisateur. Je me suis heurté à quelques problèmes de défilement lorsque j'ai essayé de modifier les éléments alors qu'il était ouvert. Vous devrez peut-être le fermer, modifier les éléments et rétablir le mode d'affichage. Pour tout ce qui concerne le clavier, vous pouvez saisir les touches du clavier dans JTextField et appeler JComboBox de manière appropriée.
ajoute ces lignes au void privé addKeyBindingToRequestFocusInPopUpWindow () de la première réponse afin de mettre en œuvre la clé UP. Il répond est parfait.
//here I have to do my code for up key
//---------------------------------------------------------------------
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
textField.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, true), "Up released");
textField.getActionMap().put("Up released", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent ae) {//focuses the first label on popwindow
for (int i = suggestionsPanel.getComponentCount()-1; i >=0; i--) {
if (suggestionsPanel.getComponent(i) instanceof SuggestionLabel) {
((SuggestionLabel) suggestionsPanel.getComponent(i)).setFocused(true);
autoSuggestionPopUpWindow.toFront();
autoSuggestionPopUpWindow.requestFocusInWindow();
suggestionsPanel.requestFocusInWindow();
suggestionsPanel.getComponent(i).requestFocusInWindow();
break;
}
}
}
});
suggestionsPanel.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, true), "Up released");
suggestionsPanel.getActionMap().put("Up released", new AbstractAction() {
//######int lastFocusableIndex = 0;
int lastFocusableIndex = 0;
//lastFocusableIndex=lastFocusableIndex___;
@Override
public void actionPerformed(ActionEvent ae) {//allows scrolling of labels in pop window (I know very hacky for now :))
ArrayList<SuggestionLabel> sls = getAddedSuggestionLabels();
int max = sls.size();
lastFocusableIndex=lastFocusableIndex___;
System.out.println("UP UP UP UP");//***//
System.out.println("max = "+String.valueOf(max));//***//
System.out.println("lastFocusableIndex = "+String.valueOf(lastFocusableIndex));//***//
System.out.println("UP UP UP UP");//***//
if (max > 1) {//more than 1 suggestion
for (int i = max-1; i >=0; i--) {
SuggestionLabel sl = sls.get(i);
if (sl.isFocused()) {
if (lastFocusableIndex == 0) {
lastFocusableIndex = max - 1;
lastFocusableIndex___=lastFocusableIndex;
sl.setFocused(false);
autoSuggestionPopUpWindow.setVisible(false);
setFocusToTextField();
checkForAndShowSuggestions();//fire method as if document listener change occured and fired it
} else {
sl.setFocused(false);
lastFocusableIndex = i;
lastFocusableIndex___=lastFocusableIndex;
}
} else if (lastFocusableIndex > i) {
if (i < max ) {
sl.setFocused(true);
autoSuggestionPopUpWindow.toFront();
autoSuggestionPopUpWindow.requestFocusInWindow();
suggestionsPanel.requestFocusInWindow();
suggestionsPanel.getComponent(i).requestFocusInWindow();
lastFocusableIndex = i;
lastFocusableIndex___=lastFocusableIndex;
break;
}
}
}
} else {//only a single suggestion was given
autoSuggestionPopUpWindow.setVisible(false);
setFocusToTextField();
checkForAndShowSuggestions();//fire method as if document listener change occured and fired it
}
}
});