0

I am writing code in java, when I enter some letter in the JTextField then the related items should be picked up from my database and should be shown in a drop down menu/list. Here is the code that I am using but there is a problem:

    package rough2;

    import java.awt.*;
    import javafx.scene.input.KeyEvent;
    import java.awt.event.KeyListener;
    import javax.swing.*;


    public class Rough2 extends JFrame{


        public static final int MAXITEMS = 100;
        JPanel panel = new JPanel();
        JTextField textField = new JTextField(10);
        String[] myDataBase = { "Alice", "Bob", "Rose", "Coggu", "Alpha", "david","peter", "max" };
        String[] listItems;
        JList theList = new JList();

        public Rough2() {
            this.add(panel);
            panel.setPreferredSize(new Dimension(500, 300));
            panel.add(textField);
            panel.add(theList);

            textField.addKeyListener(new KeyListener() {

                @Override
                public void keyTyped(java.awt.event.KeyEvent e) {
                    String compareString = ("" + textField.getText()+ e.getKeyChar());
                    listItems = new String[MAXITEMS];

                    if (compareString.trim().length() > 0 ){
                        int counter = 0;
                        for (int i = 0; i < myDataBase.length; i++) {
                            if (counter < MAXITEMS) {
                                if (myDataBase[i].length() >= compareString.length() &&
                                        myDataBase[i].substring(0, compareString.length()).equalsIgnoreCase(compareString)) {
                                    listItems[counter] = myDataBase[i];
                                    counter++;
                                }
                            }
                        }
                    }

                    theList.setListData(listItems);
                }

                @Override
                public void keyPressed(java.awt.event.KeyEvent e) {
                }

                @Override
                public void keyReleased(java.awt.event.KeyEvent e) {
                }
            });
        }

    public static void main(String[] args) {
        // TODO code application logic here

        final Rough2 answer = new Rough2();
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                answer.pack();
                answer.setVisible(true);
            }
        });
    }

}

The problem is that the result is showing in a list not in a drop down menu under the text field which I want.

Also there is another problem. That is when I write suppose "Al" to find the result, it gives me "Alice" as result but as soon as I delete "l" from the "Al" it doesn't show me anything. All the result or output goes away or in other words I get a blank list.

Kindly help me solve these two problems:

  1. Show relative result to the letter written under the text field as in drop down menu and
  2. Show result even after I erase some letter/s from the written letters as explained in the above example.
geisterfurz007
  • 5,292
  • 5
  • 33
  • 54

1 Answers1

0

The two problems of your code are:

  1. In order to display the list underneath the textfield, you should use a layout. By default they are put the one next to the other since there is space.
  2. In order to have results when you delete a character from the textfield, you should filter non-printable characters (as delete key), to be excluded from your compareString.

See the code below with the corrections:

public class Rough2 extends JFrame{
    public static final int MAXITEMS = 100;
    JPanel panel = new JPanel(new BorderLayout()); // You should use a layout on the panel for the textfield and the list
    JTextField textField = new JTextField(5);

    String[] myDataBase = { "Alice", "Bob", "Rose", "Coggu", "Alpha", "david","peter", "max" };
    String[] listItems;
    JList theList = new JList();

    public Rough2() {
        this.add(panel);
        panel.setPreferredSize(new Dimension(500, 300));
        panel.add(textField, BorderLayout.NORTH); // you should add the components using the layout
        panel.add(theList, BorderLayout.WEST); // added using the layout also

        textField.addKeyListener(new KeyListener() {

            @Override
            public void keyTyped(java.awt.event.KeyEvent e) {
                char newChar = e.getKeyChar();

                String compareString = "";
                if (isAsciiPrintable(newChar)) { //you should check if the key that triggered the event is a printable character
                    compareString = ("" + textField.getText() + newChar); // add the character if it's printable
                }
                else {
                    compareString = ("" + textField.getText()); // do not add it if it's not printable
                }

                System.out.println(compareString);

                listItems = new String[MAXITEMS];

                if (compareString.trim().length() > 0 ){
                    int counter = 0;
                    for (int i = 0; i < myDataBase.length; i++) {
                        if (counter < MAXITEMS) {
                            if (myDataBase[i].length() >= compareString.length() &&
                                    myDataBase[i].substring(0, compareString.length()).equalsIgnoreCase(compareString)) {
                                listItems[counter] = myDataBase[i];
                                counter++;
                            }
                        }
                    }
                }

                theList.setListData(listItems);
            }

            @Override
            public void keyPressed(java.awt.event.KeyEvent e) {
            }

            @Override
            public void keyReleased(java.awt.event.KeyEvent e) {
            }
        });
    }

    public static boolean isAsciiPrintable(char ch) {
        return ch >= 32 && ch < 127;
    }

    public static void main(String[] args) {
        // TODO code application logic here

        final Rough2 answer = new Rough2();
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                answer.pack();
                answer.setVisible(true);
            }
        });
    }
}

If you really need the behaviour to be similar to a combo box, then in my opinion you should probably use JComboBox instead of JTextField, because it offers the functionality you require out of the box - see example.

Now if you insist making it using JTextField, I found an interesting solution here that is using a Popup for the list of options, and I modified it a bit in order to simplify it:

import java.awt.Dimension;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Arrays;
import java.util.List;

import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

public class Rough4 extends JFrame {
    Popup pop;
    JTextField mainTxt;
    List<String> options;
    DefaultListModel model;
    JList l;
    String[] myDataBase = { "Alice", "Bob", "Rose", "Coggu", "Alpha", "david","peter", "max" };


    Rough4() {
        options = Arrays.asList(myDataBase);

        mainTxt = new JTextField();
        mainTxt.setPreferredSize(new Dimension(100,20));
        mainTxt.addKeyListener(new KeyListener() {

            @Override
            public void keyTyped(KeyEvent e) {
                char newChar = e.getKeyChar();
                if (isAsciiPrintable(newChar)) {
                    csearch(mainTxt.getText()+newChar);
                }
                else {
                    csearch(mainTxt.getText());
                }
            }

            @Override
            public void keyPressed(KeyEvent e) {
            }

            @Override
            public void keyReleased(KeyEvent e) {
            }
        });


        JPanel panel = new JPanel();
        panel.add(mainTxt);


        this.add(panel);
        this.setPreferredSize(new Dimension(500,500));


        PopupFactory factory= PopupFactory.getSharedInstance();
        int x=200;
        int y=30;

        model = new DefaultListModel();
        l = new JList(model);
        l.setOpaque(true);
        l.addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e)
            {
                if(l.getSelectedIndex()!=-1)
                {
                    mainTxt.setText((String)l.getSelectedValue());
                }
            }
        });
        pop = factory.getPopup(mainTxt,l,x+5,y+30);


        this.pack();
        this.setVisible(true);
    }

    public boolean isAsciiPrintable(char ch) {
        return ch >= 32 && ch < 127;
    }

    public void csearch(String letter) {
        model.removeAllElements();
        for (String option: options) {
            if (option.toLowerCase().startsWith(letter.toLowerCase())) {
                model.addElement(option);
            }
        }

        l.setModel(model);

        pop.show();
    }

    public final static void main(String[] args) {
        Rough4 r = new Rough4();
    }
}

Good Luck!

sanastasiadis
  • 1,182
  • 1
  • 15
  • 23
  • Yes, this works fine for the delete characters but as for the 1. point, what I was trying to say was that, I want to display the related word as the letters written in the text field like for example google works. When you write some letters in the search field, it displays related word. Also, I do not want to use "JList" because I want to add some components like button underneath the text field and if I use the "JList" it will move the location of those components to left or right but I want them on their same location, again same as the google search field and buttons work. – Maqsood Ahmad Jun 29 '18 at 16:09
  • @MaqsoodAhmad Please add the extra specifications on your question. You can check this question for a better filtering example: https://stackoverflow.com/questions/10368856/jcombobox-filter-in-java-look-and-feel-independent, and of course you can update your drop down entries with any panel you want by following `CustomComboboxDemo` here: https://docs.oracle.com/javase/tutorial/uiswing/components/combobox.html – sanastasiadis Jun 29 '18 at 17:05
  • Yes I have seen the links but they are about JComboBox, I want to do it using JTextField. In other words, I want the same result as JComboBox as shown in the link: (https://stackoverflow.com/questions/10368856/jcombobox-filter-in-java-look-and-feel-independent) but using JTextField. – Maqsood Ahmad Jun 30 '18 at 10:07
  • @MaqsoodAhmad check my edited answer and the 2nd code sample I added. Cheers. – sanastasiadis Jul 02 '18 at 12:43