With a JComboBox containing some elements beginning with repeated letters, typing in the character twice will return the character typed, followed by the first character of its type. For example, typing "bb" in a list containing ba, bb, and bc will return ba. However, if this list also contains bbd, continuing to press a "d" will return the bbd option. This is the same with numbers: Typing "33" returns 30, while typing "334" returns 334.
Is there a way to fix this so that a double keyPress really returns what is typed in?
Quick sample program:
String[] range = new String[401];
for (int i = 0; i <= 400; i++) {
range[i] = "" + i;
}
private javax.swing.JComboBox<String> jComboBox1;
jComboBox1 = new javax.swing.JComboBox<>();
getContentPane().setLayout(new java.awt.GridLayout());
jComboBox1.setModel(new javax.swing.DefaultComboBoxModel<>(range));
getContentPane().add(jComboBox1);
pack();
Item selection via keyboard is controlled by the JComboBox.KeySelectionManager, which, surprisingly, you can actually implement and change 😱
The one thing that the default implementation does is, it will try and find items which match the key stroke based on the first character of the item (when converted to a String via toString). The "neat" thing about this is, it will search from the currently selected item (if not null), if it can't find another matching item, it will start at the beginning of the model instead.
What this means is, if you type 3 repeatedly, it will, progressively move through all the items that start with 3. (30, 31, 32 ... 39, 300 ...)
Buuuut, this isn't what you apparently want, so, instead, you're going to have to supply your own algorithm.
One, very important consideration is, what happens when the user stops typing? If the user has typed 33, stops, then types 3 again, what should happen? Should it select 3 or 333?
The following is a VERY basic example, based on the DefaultKeySelectionManager used by JComoBox by default. It uses a StringBuilder to keep track of the key strokes and a Swing Timer which provides a 250 millisecond timeout, which will clear the StringBuilder after 250 milliseconds of inactivity (you could pass this value into the constructor to define your own)
When called by the JComboBox, it will simply do a linear search of the model for a item whose toString result starts with what's been typed.
This example is a case insensitivity, but you can modify it to meet your particular needs
public class MyKeySelectionManager implements KeySelectionManager {
private Timer timeout;
private StringBuilder pattern = new StringBuilder(32);
public MyKeySelectionManager() {
timeout = new Timer(250, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
pattern.delete(0, pattern.length());
}
});
timeout.setRepeats(false);
}
#Override
public int selectionForKey(char aKey, ComboBoxModel<?> model) {
timeout.stop();
pattern.append(Character.toLowerCase(aKey));
String match = pattern.toString();
for (int index = 0; index < model.getSize(); index++) {
String text = model.getElementAt(index).toString().toLowerCase();
if (text.startsWith(match)) {
timeout.start();
return index;
}
}
timeout.start();
return -1;
}
}
Runnable example
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JComboBox.KeySelectionManager;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.border.EmptyBorder;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
DefaultComboBoxModel<String> model = new DefaultComboBoxModel<>();
for (int index = 0; index < 50; index++) {
model.addElement(Integer.toString(index));
}
JComboBox cb = new JComboBox(model);
cb.setKeySelectionManager(new MyKeySelectionManager());
JFrame frame = new JFrame();
JPanel content = new JPanel(new GridBagLayout());
content.setBorder(new EmptyBorder(32, 32, 32, 32));
content.add(cb);
frame.setContentPane(content);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class MyKeySelectionManager implements KeySelectionManager {
private Timer timeout;
private StringBuilder pattern = new StringBuilder(32);
public MyKeySelectionManager() {
timeout = new Timer(250, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
pattern.delete(0, pattern.length());
}
});
timeout.setRepeats(false);
}
protected int indexOf(Object item, ComboBoxModel<?> model) {
for (int index = 0; index < model.getSize(); index++) {
if (model.getElementAt(index) == item) {
return index;
}
}
return -1;
}
#Override
public int selectionForKey(char aKey, ComboBoxModel<?> model) {
timeout.stop();
pattern.append(Character.toLowerCase(aKey));
String match = pattern.toString();
for (int index = 0; index < model.getSize(); index++) {
String text = model.getElementAt(index).toString().toLowerCase();
if (text.startsWith(match)) {
timeout.start();
return index;
}
}
timeout.start();
return -1;
}
}
}
Don't forget to take a look at JComboBox#setKeySelectionManager for more details
Related
I'm writing a thing that has a JLabel array that has something in the first index and then detects right keys that shifts the thing to the right. Basically, [x][][][][][][] starts, then if I press the right key, it shifts to [][x][][][][][]. Currently, I can't get the JLabel to properly update. It shows up correctly at first, but when I hit the right key, the entire thing gets messed up. Ie, it starts like this:
(I have the numbers to gauge the shifting, they'll go away when I figure this problem out)
Which is right, but when I hit the right key, everything disappears (just blank.) However, my test in the console still gives me the correct values though.
The numbers don't even show up :/
Here's the relevant code:
public Template() {
for (int i = 0; i < 7; i++) {
positions[i] = new JLabel();
positions[i].setFont(new Font("Times New Roman", Font.PLAIN, 15));
System.out.println("Yay");
}
// I initialize my JLabel array here instead of below because if I don't do this, there's no change whatsoever if I press the right key. I'm not sure if I did it correctly, though.
initialize(p1, 0);
}
private void initialize(String p, int index) {
frame = new JFrame();
JPanel header = new JPanel();
header.setBackground(Color.WHITE);
GridBagLayout gbl = new GridBagLayout();
GridBagConstraints c = new GridBagConstraints();
header.setLayout(gbl);
header.setPreferredSize(new Dimension(400, 50));
c.fill = GridBagConstraints.HORIZONTAL;
for (int i = 0; i < 7; i++) {
if (i == index) {
positions[i].setText(p + "");
System.out.println("indexed set");
} else {
positions[i].setText("" + i);
System.out.println(positions[i].getText());
System.out.println("set");
}
c.gridx = i;
c.gridy = 0;
header.add(positions[i], c);
}
frame.add(header, BorderLayout.NORTH);
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
playMove(p);
}
public void playMove(String p) {
...
frame.addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent keyEvent) {
System.out.println("Game.keyPressed -- event: " + keyEvent);
if (keyEvent.getKeyCode() == KeyEvent.VK_RIGHT) {
System.out.println("Right key pressed!");
int index = searchHeader();
System.out.println("index: " + index);
if (index != 6) {
int shift = index + 1;
System.out.println("shift: " + shift);
SwingUtilities.updateComponentTreeUI(frame);
initialize(p, shift, t);
}
}
}
#Override
public void keyReleased(KeyEvent keyEvent) {
System.out.println("Game.keyReleased -- event: " + keyEvent);
}
});
}
public int searchHeader() {
for (int i = 0; i < 7; i++) {
String val = positions[i].getText();
if (val == "x" || val == "o") {
System.out.println("i:" + i);
return i;
}
}
return 0;
}
My System.out.println(); tests all return the correct values (the correct index, shift, and numbers in the array) but I'm not sure why the thing isn't showing up :/
If my code needs clarification or missed something (I did cut some irrelevant info off after taking advice from my last post) please tell me
Since you didn't provide a minimal runnable example that we could copy into our IDE, run, and debug, I came up with this example GUI that shows an X shifting to the right.
I used the right arrow key to perform the shift.
Here's the GUI when starting the application.
Here's the GUI after shifting the X three positions.
Here's the GUI after shifting the X four positions.
Oracle has a helpful tutorial, Creating a GUI With Swing. Skip the Netbeans section.
The first thing I did was start the Swing application by calling the SwingUtilities invokeLater method. This method ensures that the Swing components are created and executed on the Event Dispatch Thread.
Next, I created a JFrame. The JFrame methods must be called in a specific order. This is the order I use for my Swing applications.
I created a main JPanel to hold the array of eight JLabels. I also created an int to hold the position of the X. I used a FlowLayout to lay out the array of JLabels. I( used the Box class to put some space between the JLabels.
As you're creating a more complicated game, create an application model using plain Java getter/setter classes.
I used Key Bindings to bind the right arrow key to the Action class. I used AbstractAction so I'd only have to code the actionPerformed method.
Here's the complete runnable code.
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
public class ShiftRightExample implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new ShiftRightExample());
}
private int position;
private JLabel[] spotLabel;
public ShiftRightExample() {
this.position = 0;
}
#Override
public void run() {
JFrame frame = new JFrame("Shift Right Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel mainPanel = createMainPanel();
frame.add(mainPanel, BorderLayout.CENTER);
setKeyBindings(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createMainPanel() {
JPanel panel = new JPanel(new FlowLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
this.spotLabel = new JLabel[8];
for (int index = 0; index < spotLabel.length; index++) {
spotLabel[index] = new JLabel(" ");
panel.add(spotLabel[index]);
if (index < (spotLabel.length - 1)) {
panel.add(Box.createHorizontalStrut(20));
}
}
updateMainPanel(position, "X");
return panel;
}
private void setKeyBindings(JPanel panel) {
panel.getInputMap().put(
KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "shiftRight");
panel.getActionMap().put("shiftRight", new ShiftRightAction());
}
public void updateMainPanel(int position, String value) {
spotLabel[position].setText(value);
}
public class ShiftRightAction extends AbstractAction {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent event) {
updateMainPanel(position, " ");
position++;
position = position % spotLabel.length;
updateMainPanel(position, "X");
}
}
}
What I currently have: There are red lines (errors) under the method fillArray and with its above if statement. Purpose is to create an array which will start with a button click and fill the array with random int ranging from 0 to 100
import java.awt.*; //imports data from library
import java.awt.event.*;
import javax.swing.*;
public class FinalArray extends JFrame implements ActionListener {
private JButton fill,
private JTextArea output;
public static void main(String[] args) { //creates window
FinalArray demo = new FinalArray();
demo.setSize(400,450);
demo.createGUI();
demo.setVisible(true);
}
private void createGUI() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
Container window = getContentPane();
window.setLayout(new FlowLayout());
fill = new JButton("fill");//creates button
window.add(fill); //and text area
fill.addActionListener(this);
public void actionPerformed(ActionEvent event) {
Object source = event.getSource();
if (source == fill) {
BigArray.fill();
}
class BigArray {
private int [] array;
public void fillArray() {
for(int i = 0; i < array.length; i++) {
array.fill(array[i]=0);
}
Random = new Random(101);
The argument that you can pass to the constructor of Random is the seed, not the range of the generated values. (The seed is some kind of initial value; if always use the same seed, the random generator will always generate the same number sequence).
If you want to get a random number within a certain range, use the method random.nextInt(int) instead:
int a = random.nextInt(101); // returns a random value between 0 and 100
watch the brackets '{' '}' I think you are missing one under actionPerformed, BigArray, and createGUI().
It can be helpful to code like this:
class myClass
{
int myInt;
public void setInt(int myInt)
{
this.myInt = myInt;
}
}
Each closing brace is below the starting brace.
I'm new to Java and have set myself the task of trying to create a simple calculator (and GUI) to advance my understanding and skills of the language.
Take this code:
import java.awt.FlowLayout;
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class calc extends JFrame {
public JTextField input;
public JTextField output;
public JPanel Window;
public JButton math_button[] = new JButton[5];
public JButton number_button[] = new JButton[10];
public String[] number_button_name = {"1","2","3","4","5","6","7","8","9","0"};
public String[] name = {"Add", "Mulitply", "Divide", "Subtract", "Equals"};
public JFrame frame = new JFrame();
public JPanel math_panel = new JPanel();
public JPanel number_panel = new JPanel();
public JTextField math_input = new JTextField();
boolean trrgger = false;
thehandler handler = new thehandler();
public void go()
{
for(int b=0; b<number_button.length; b++)
{
number_button[b] = new JButton(number_button_name[b]);
number_button[b].addActionListener(handler);
number_panel.add(number_button[b]);
}
for(int i=0; i<math_button.length;i++)
{
math_button[i] = new JButton(name[i]);
math_button[i].addActionListener(handler);
math_panel.add(math_button[i]);
}
frame.getContentPane().add(BorderLayout.NORTH, math_input);
frame.getContentPane().add(BorderLayout.SOUTH, math_panel);
frame.getContentPane().add(BorderLayout.CENTER, number_panel);
frame.setSize(400,400);
frame.setVisible(true);
}
//Method to handle the math and return the results of whichever 'button' was pressed
static int Math(String button_num, int first_num, int second_num)
{
int total = 0;
if(button_num == "Add")
{
total = first_num + second_num;
}
else if (button_num == "Mulitply") //multiply
{
total = first_num * second_num;
}
else if (button_num == "Divide") //divide
{
total = first_num / second_num;
}
else if (button_num == "Substract") //subtract
{
total = first_num - second_num;
}
else if (button_num == "Equals") //subtract
{
total = total;
}
return total;
}
//Action Events - Code that is triggered once the associated button is clicked
public class thehandler implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
for (int h = 0; h <math_button.length; h++)
{
if(event.getSource()==math_button[h])
{
int firstn = Integer.parseInt(math_input.getText());
math_input.setText("");
int secondn = Integer.parseInt(math_input.getText());
System.out.println(calc.Math(math_button[h].getText(), firstn, secondn));
}
}
for(int n=0; n<number_button.length; n++)
{
if(event.getSource()==number_button[n])
{
String number_clicked = (number_button[n].getText());
String number = math_input.getText();
math_input.setText(number + number_clicked);
}
}
}
}
}
The idea behind this code is to create a simple GUI and allows the user to input the desired amount of numbers and then press the 'equals' button to display the result. However, as stated I'm having a problem with the logic. I can get the first entered number from the JTextField, clear the text once the first variable has been initialized but this is where the program falls over. The variable 'second_num' is passed to the 'Math' method as blank (which throws up errors) because that's what I tell the ActionEvent to do in order to allow for more fluid use of the program, no user wants to have to keep clearing the input box when using a calculator.
Anybody got any ideas?
Thanks
int firstn = Integer.parseInt(math_input.getText());
math_input.setText("");
int secondn = Integer.parseInt(math_input.getText());
What exactly do you expect the above lines to do? You are getting the text from math_input. Then you set it to an empty string. And by immediately getting the string back you are expecting to get something other than empty string?
The correct approach would be:
First time the handler is called (i.e. a "math" button is clicked) collect the input. Store it somewhere.
Next time this handler will be called you will have your next input. And so on until the user clicks on "=" to evaluate the whole expression.
Advice: If you are new to java, you might find it easier to create a calculator on the command line first. The functionality of a calculator does not require a GUI. In command line collecting the input is more simple. If you get that working then you can proceed to more fancy stuff like Swing
I looked at your code but its sound complicated for me. I recommend you to use IDE like Netbeans. Create swing application. To add two number all you need to do is as follow
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
int input_1 = Integer.parseInt(jTextField1.getText());
int input_2 = Integer.parseInt(jTextField2.getText());
jTextField3.setText(String.valueOf((input_1+input_2)));
}
http://i.stack.imgur.com/1G4v7.jpg
I am using a for loop to create 9 JTextFields and this is working fine. My problem is, I want to check of all the these JTextField is empty or not' at one time. I know there is a method like:
if (textbox.getText().trim().equals(""))
to check if the JTextField is empty or not, But I am not sure if it is suitable for the method that I am using for JTextField. Below is my for loop:
for (int index = 1; index <=9; index++)
{
JTextField field = new JTextField(3);
field.setPreferredSize(new Dimension(150, 50));
field.setHorizontalAlignment(JTextField.CENTER);
field.setEditable(false);
second.add(field);
second.add(Box.createHorizontalStrut(10));
second.add(Box.createVerticalStrut(10));
}
Store your text fields in a List so that you can iterate over them later.
public class ClassContainingTextFields {
private final ArrayList<JTextField> textFields = new ArrayList<>();
// ... inside the method that creates the fields ...
for (int i = 0; i < 9; i++) {
JTextField field = new JTextField(3);
// .. do other setup
textFields.add(field);
}
/**
* This method returns true if and only if all the text fields are empty
**/
public boolean allFieldsEmpty() {
for (JTextField textbox : textFields) {
if (! textbox.getText().trim().isEmpty() ) {
return false; // one field is non-empty, so we can stop immediately
}
}
return true; // every field was empty (or else we'd have stopped earlier)
}
// ....
}
Consider this code.
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextField;
public class Test extends JFrame implements ActionListener {
JTextField tfs[];
JButton btn;
public Test(){
setLayout( new FlowLayout());
tfs = new JTextField[9];
for( int i=0; i< tfs.length; i++) {
tfs[i] = new JTextField(10);
add(tfs[i]);
}
add( btn = new JButton("Check"));
btn.addActionListener(this);
setSize(200,300);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void actionPerformed (ActionEvent ae){
boolean pass = true;
for(int i=0; i<tfs.length; i++)
if( tfs[i].getText().trim().equals(""))
pass = false;
System.out.println(pass?"Passed":"Failed");
}
public static void main (String args[]){
new Test();
}
}
How about implementing your own DocumentListener? You could have a Boolean that turns true when all fields are empty, and you could do your various hangman-related checks directly after every change in a fields Document.
I'm trying to build a javax.swing.JTextField with javax.swing.JList for auto-completing like Google.
When a write a word, Google show several matches and
when a press the â–¼ I can select some match using â–² and â–¼ and
can edit my input with â—€ and â–¶ .
When I press Enter key search the content in the box.
When a press Esc the box change to the original input.
My aplication is about the Bible and I want to looking for a particular word when I'm studying the Word. I have seen the Java2sAutoTextField but don't have this particular behavior with the arrow keys.
This needs a custom coded component. Definitely a class that extends JTextField and in that class you have a JPopupMenu that will contain your JList. You will have to position the JPopupMenu right under the text field so that it looks like 1 component.
Your next trick is to filter as you type. I usually do this using Java6 TableRowSorter coupled with a JTable to which I pre-fill it with data. You're gonna need some change listeners on the JTextField and intercept each key typed and fetch your data.
Key pressed
Perform query in DB (or some data storage to get similar entries)
Populate JTable with those entires
Set RowFilter with regex based on JTextField entry to filter through retrieved data
Manage your actions with key listeners
EDIT
I whipped up a sample swing app to show what I stated. This is a copy/paste example and should work right off the bat (need JDK 1.6+). I basically got what you wanted and I put comments in places where I tell you to fill in the blanks.. like for example the Escape key event is consumed and you can do whatever you want with it.
The method initTableModel() just initializes the table model with data. Normally you would want to dynamically populate the table model with data from a database or something. A lot could be tweaked, but this is for example sake ;) So this should be a good enough example for you to modify to your complete your goal. Any more than this and you have to pay me $$$ :)
package test.text.googleclone;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.regex.PatternSyntaxException;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.RowFilter;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableRowSorter;
public class SearchAutoFillTest {
private JFrame frame = null;
private JTextField searchField = null;
private JPopupMenu popup = null;
private JTable searchTable = null;
private TableRowSorter<DefaultTableModel> rowSorter = null;
private DefaultTableModel searchTableModel = null;
public SearchAutoFillTest() {
searchTableModel = new DefaultTableModel();
initTableModel();
rowSorter = new TableRowSorter<DefaultTableModel>(searchTableModel);
searchTable = new JTable(searchTableModel);
searchTable.setRowSorter(rowSorter);
searchTable.setFillsViewportHeight(true);
searchTable.getColumnModel().setColumnSelectionAllowed(false);
searchTable.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
searchTable.getTableHeader().setReorderingAllowed(false);
searchTable.setPreferredSize(new Dimension(775, 100));
searchTable.setGridColor(Color.WHITE);
searchField = new JTextField();
searchField.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void changedUpdate(DocumentEvent e) {
showPopup(e);
}
#Override
public void insertUpdate(DocumentEvent e) {
showPopup(e);
}
#Override
public void removeUpdate(DocumentEvent e) {
showPopup(e);
}
});
searchField.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
int code = e.getKeyCode();
switch(code)
{
case KeyEvent.VK_UP:
{
cycleTableSelectionUp();
break;
}
case KeyEvent.VK_DOWN:
{
cycleTableSelectionDown();
break;
}
case KeyEvent.VK_LEFT:
{
//Do whatever you want here
break;
}
case KeyEvent.VK_RIGHT:
{
//Do whatever you want here
break;
}
}
}
#Override
public void keyPressed(KeyEvent e) {
}
});
KeyStroke keyStroke = KeyStroke.getKeyStroke("ESCAPE");
searchField.getInputMap().put(keyStroke, "ESCAPE");
searchField.getActionMap().put("ESCAPE", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
//Do what you wish here with the escape key.
}
});
popup = new JPopupMenu();
popup.add(searchTable);
popup.setVisible(false);
popup.setBorder(BorderFactory.createEmptyBorder());
JPanel searchPanel = new JPanel(new BorderLayout(5, 5));
searchPanel.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
searchPanel.add(searchField, BorderLayout.CENTER);
frame = new JFrame();
frame.setLayout(new BorderLayout(5, 5));
frame.add(searchPanel, BorderLayout.NORTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 500);
center(frame);
frame.setVisible(true);
}
private final void newFilter() {
RowFilter<DefaultTableModel, Object> rf = null;
try {
rf = RowFilter.regexFilter(getFilterText(), 0);
}
catch(PatternSyntaxException e) {
return;
}
rowSorter.setRowFilter(rf);
}
private final String getFilterText() {
String orig = searchField.getText();
return "("+orig.toLowerCase()+")|("+orig.toUpperCase()+")";
}
private void showPopup(DocumentEvent e) {
if(e.getDocument().getLength() > 0) {
if(!popup.isVisible()) {
Rectangle r = searchField.getBounds();
popup.show(searchField, (r.x-4), (r.y+16));
popup.setVisible(true);
}
newFilter();
searchField.grabFocus();
}
else {
popup.setVisible(false);
}
}
private void cycleTableSelectionUp() {
ListSelectionModel selModel = searchTable.getSelectionModel();
int index0 = selModel.getMinSelectionIndex();
if(index0 > 0) {
selModel.setSelectionInterval(index0-1, index0-1);
}
}
private void cycleTableSelectionDown() {
ListSelectionModel selModel = searchTable.getSelectionModel();
int index0 = selModel.getMinSelectionIndex();
if(index0 == -1) {
selModel.setSelectionInterval(0, 0);
}
else if(index0 > -1) {
selModel.setSelectionInterval(index0+1, index0+1);
}
}
private void initTableModel() {
String[] columns = new String[] {"A"};
String[][] data = new String[][]
{
new String[] {"a"},
new String[] {"aa"},
new String[] {"aaab"},
new String[] {"aaabb"},
new String[] {"aaabbbz"},
new String[] {"b"},
new String[] {"bb"},
new String[] {"bbb"},
new String[] {"bbbbbbb"},
new String[] {"bbbbbbbeee"},
new String[] {"bbbbbbbeeexxx"},
new String[] {"ccc"},
new String[] {"cccc"},
new String[] {"ccccc"},
new String[] {"cccccaaaa"},
new String[] {"ccccccaaaa"},
};
searchTableModel.setDataVector(data, columns);
}
private void center(Window w) {
int screenWidth = Toolkit.getDefaultToolkit().getScreenSize().width;
int screenHeight = Toolkit.getDefaultToolkit().getScreenSize().height;
int windowWidth = w.getWidth();
int windowHeight = w.getHeight();
if (windowHeight > screenHeight) {
return;
}
if (windowWidth > screenWidth) {
return;
}
int x = (screenWidth - windowWidth) / 2;
int y = (screenHeight - windowHeight) / 2;
w.setLocation(x, y);
}
public static void main(String ... args) {
new SearchAutoFillTest();
}
}
This component is called autocomplete and is included in a so called swing extensions porject.
Just have a look at: http://swingx.java.net/
There is a webstart with demos: http://swinglabs-demos.java.net/demos/swingxset6/swingxset.jnlp
use AutoComplete JTextField placed into JToolBar / MenuBar, notice you must to sort ArrayList before usage,
use undecoratted JDialog instead of JPopup (still have got a few important bugs),
a) create only one JDialog with parent to the JTextField or JMenuBar or JFrame,
b) always to search for getBounds from AutoComplete JTextField before visible JDialog on the screen, this Bounds are for possitioning JDialog correctly on the screen
c) wrap JDialog#setVisible(true) to the invokeLater()
override Escape for JDialog.setVisible(false)
put there close / hide JButton to avoiding overrive rest of important methods on focusLost (this calendar have got excelent workaround on focusLost, mouseClick, etc ...., could it be very easy to replace calendar funcionality with result from Comparator, you have to download codesource)
you can put there (my view) 6 / 9 / max 12 buttons, you can remove JButton Feels by setBackground(Color.white) for example, you cann't, please don't do it something with JDialog and these JButtons, you job will be only to setText("result from Comparator")
in the case that your ArrayList for AutoComplete JTextField was sorted, then you have two choises
a) easiest override bias from AutoComplete funcionality by add fils separate array for setText() for 6 / 9 / max 12 buttons on popup JDialog, if you setBackground(Color.white), then you don't care somehow about to hide JButtons without text
b) another way could be to create own Comparator for searching (the same AutoComplete funcionality) first 6 / 9 / max 12 matches,
for capturing an events from 6 / 9 / max 12 JButtons use putClientProperty or EventHandler or Swing Actions, where you only to test if text isEmpty :-),
maybe Swing Actions could be the best of ways because its events are scallable and you can enabled/disable (if JButtons text isEmpty) output from this Action by default
It sounds like you want a JComboBox (see Swing guide) rather than a JTextField/JList.
Of course, then you have a drop-down button, but there are possible ways to deal with this - see here.
It would be something along these lines:
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import javax.swing.*;
public class Component extends JComponent {
private final static String[] terms = {"Jesus",
"Jesus walks on water" //...
};
private static ArrayList<String> recent = new ArrayList<String>();
JTextField jtf;
JList jl;
public Component(){
// set up design
jtf = new JTextField();
jtf.setSize(this.getWidth() - 25, 25);
this.add(jtf);
//...
// add key listeners
}
class Listener implements KeyListener{
#Override
public void keyPressed(KeyEvent arg0) {
}
#Override
public void keyReleased(KeyEvent arg0) {
}
#Override
public void keyTyped(KeyEvent arg0) {
if (arg0.getKeyCode() == KeyEvent.VK_DOWN){
// set next item on list
}
else if (arg0.getKeyCode() == KeyEvent.VK_UP){
// set previous item on list
}
else if (arg0.getKeyCode() == KeyEvent.VK_ENTER){
// search
}
else if (arg0.getKeyCode() == KeyEvent.VK_ESCAPE){
jtf.setText("");
}
else{
// check list for matches
}
}
}
}
The default behavior is that all key events go to the component which has the focus. So what you need to do is identify keys which should really go to the other component and install a KeyListener to both.
In that listener, you can forward the events to the other component.
See this answer how to dispatch an event to a new component. In your case, source must be the other component (the list, if your text field originally received the event and vice versa).