ListSelectionListener on JList not working - java

i'm having problems with this listener, the gui in general constructs and works fine, also the jlist is there but when i select some items in the list i dont see the results and also not the printl() i wrote for test purpose, pls note this code is contained within the getJContentPane in order to add the event handler at init-time
private JList myList=new JList(dlm);//a defaultlistmodel
myList.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent evt) {
if (evt.getValueIsAdjusting()){
System.out.println("Eventhandler called");
return;
}
System.out.println("Eventhandler called");
doMyMethod(evt);
}
});
The doMyMethod():
private void doMyMethod(ListSelectionEvent e){
if(e.getValueIsAdjusting()){
return;
}else{
String item=(String)e.getSource();
accounter.add(item);
}
}
It is a very simple method which takes as parameter an instance of ListSelectionEvent
The main problem in my opinion is not the doMyMethod() which performs very basic actions but the fact that the eventHandler is not fired at all, it seems lik the gui does not "listen" to this list at all
Any idea?
here the initialisation code:
private JScrollPane getScrollBox() {
if (scrollboxBox == null) {
scrollboxBox = new JScrollPane();
scrollBox.setBounds(new Rectangle(280, 56, 245, 204));
scrollBox.getViewport().add(myList,null);
myList.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent evt) {
System.out.println("addListSelectionListener");
if (evt.getValueIsAdjusting()){
System.out.println("Eventhandler called");
return;
}
System.out.println("Eventhandler called");
doMyMethod(evt);
}
});
}
return scrollboxBox;
}

After trying to understand what is going on in your question I understood that you are failing to get selected item in the list, when the selection is changed.
To present you how this could be achieved I have built the below example. You can observe there when each part of the if else is called. The if(e.getValueIsAdjusting()) is execute always when you drag the moue over items. The else part is called when you release the mouse while previously clicked on an item.
There are some serious issues in the code that you have provided, therefore I tried to remove all that is unnecessary, e.g.
1.The doMyMethod() method and the if(e.getValueIsAdjusting()) piece of code that is in it would never be called since you already are checking that condition before it is called. Plus there is no need to code a method working on listener's events, this code should stay inside the listener which is private. Then if you want to call programmatically its code you would call the listener.valueChanged(evt).
2.The evt.getSource() returns the object which is author of the event in this case the myList not the selected item which I think you were after, for this use the getSelectedValue() on the source or myList directly since this listener serves only this list.
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
public class ListTest extends JPanel
{
private JScrollPane myScrollPane;
private JList myList;
private ListSelectionListener lSL = new ListSelectionListener()
{
#Override
public void valueChanged(ListSelectionEvent evt)
{
if(evt.getValueIsAdjusting())
{
System.out.println("Eventhandler called evt.getValueIsAdjusting() true");
return;
}
else
{
// String item = (String) evt.getSource();//!!!Exception casting JList to String
//maybe what you need is getSelectedValue()
System.out.println("else called myList.getSelectedValue() ="+myList.getSelectedValue());
}
}
};
private ListTest()
{
int noRows = 25;
Object[] listData = new String[noRows];
for(int i =0; i < noRows; i++)
listData[i]= "Oi "+i;
this.myList = new JList(listData);
this.myScrollPane = new JScrollPane(myList);
myList.addListSelectionListener(lSL);
add(myScrollPane);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
ListTest p = new ListTest();
JPanel contentPane = new JPanel();
contentPane.add(p);
JFrame f = new JFrame();
f.setContentPane(contentPane);
f.setSize(800, 600);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
});
}
}
Hope that even if it doesn't solve your problem it at least will be helpful in building an SSCCE for us.

Related

reading the value of jtable selected row

I am working with java RMI and swing and I have read the values from database but i am unable to read the value of selected row in this code. What i want to JTable to show all databases and it is showing all the available databases in server but i am unable to read the selected row value in this
package schoolclient;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.*;
import schoolserver.SchoolInterface;
public class DatabaseList {
JFrame jFrame = null;
JPanel jPanel = null;
JList jList = null;
JTable jTable = null;
String data = null;
schoolserver.SchoolInterface schoolInt = null;
public DatabaseList(SchoolInterface sii) {
schoolInt = sii;
jFrame = new JFrame();
jTable = new JTable(){
public boolean isCellEditable(int row, int column) {
return false;
}
};
jTable.setModel(createTable());
jTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
jTable.addMouseListener(new MouseAdapter() {
public void MouseClicked(MouseEvent e) {
if(SwingUtilities.isLeftMouseButton(e) && (e.getClickCount() == 2)) {
new createListSelection();
}
}
});
JScrollPane scrollPane = new JScrollPane(jTable);
jFrame.add(scrollPane);
jFrame.setSize(200, 200);
jFrame.setVisible(true);
}
private DefaultTableModel createTable() {
DefaultTableModel dtm = new DefaultTableModel();
dtm.addColumn("Databases", createArray());
return dtm;
}
private class createListSelection implements ListSelectionListener {
#Override
public void valueChanged(ListSelectionEvent e) {
if(!e.getValueIsAdjusting()) {
ListSelectionModel lsm = jTable.getSelectionModel();
data = (String) jTable.getValueAt(jTable.getSelectedRow(), 0);
System.out.println(data);
}
}
}
Object[] createArray() {
ArrayList<Object> al = null;
Object[] x = null;
try {
al = schoolInt.availableDatabases();
x = new Object[al.size()];
int i = 0;
for(Object o : schoolInt.availableDatabases())
x[i++] = o;
}
catch(Exception e) {
JOptionPane.showMessageDialog(null, "no connection to database or "
+ "remote server availabe", "Server Information", JOptionPane.OK_OPTION);
}
return x;
}
}
You look to be over-complicating things. Don't re-add listeners within a listener, but rather simply add one listener, a MouseListener to the JTable, and add it once. Within it check for double clicks (presses) and respond. Something like:
jTable.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) {
data = (String) jTable.getValueAt(jTable.getSelectedRow(), 0);
System.out.println(data);
}
}
});
Other problems, your method within your MouseAdapter will never be called, ever:
jTable.addMouseListener(new MouseAdapter() {
public void MouseClicked(MouseEvent e) {
// ....
}
});
Your capitalization is wrong, and since MouseAdapter/MouseListener does not have a MouseClicked method (it is mouseClicked) this method is never called. Always place an #Override annotation above any method that you think might be an override, and let the compiler warn you if it is not so. Had you done this, you'd get a prompt warning from the compiler.
Regarding your comment
You never add a selection listener to the JTable. Again the method within the MouseAdapter is never called since it is not capitalized correctly
Even if it did get called, what use is there repeatedly adding a ListSelectionListener?
If your goal is to only respond to double-clicks, a ListSelectionListener is not what you want. Only a MouseListener would work in this situation.
Do read the appropriate tutorials as they explain all of this and well. Please check out the links to be found within the Swing Info tag.

Java Swing adding mouse Listener (inner class) for an array of buttons leads to malfunction

Ok, so the program I want to build is simple. There are five buttons named from 0 to 4. If any of the buttons are pressed, then the number 0 to 4 is printed in console.
I have used a GridLayout to place the buttons in the frame. And to set up each button I have created a method, inicializarIG().
This inicializarIG() method creates an array of 5 buttons and inside a for loop it does:
Create an instance of a button for each cell in the array of buttons.
Set up a mouseListener for each button. The value to print in each Listener is different, it is determined by the index of the loop (AND I WANT TO DO IT BY USING THE INDEX!).
Add The button to the main frame.
Surprisingly, This simple program doesn´t work properly. It always print the number "5" no matter what button is pressed:
NOTE: I had to put the index var outside the inicializarIG() method in order to fulfill the var scope for the Listeners. I don't know if the problem is related, just saying in cause it might help.
THE CODE:
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
public class IGrafica {
private JFrame frame;
public int index=0;
public IGrafica(){
frame = new JFrame();
configureFrame();
inicializarIG();
}
public void configureFrame(){
frame.setBounds(100,100,400,400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new GridLayout(1,5)); //
}
public void inicializarIG(){
//Buttons
JButton [] botones = new JButton [5];
//Loop to set up buttons and add the mouseListener
for (index = 0; index < botones.length; index++) {
botones[index] = new JButton(Integer.toString(index));
//Set up each listener
botones[index].addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
System.out.println(index);
//texto.setBackground(colores[index]);
}
});
//Add the button
frame.getContentPane().add(botones[index]);
}
}
public void visualizate(){
frame.setVisible(true);
}
public static void main(String[] args) {
IGrafica window = new IGrafica();
EventQueue.invokeLater(new Runnable() {
public void run() {
window.visualizate();
}
});
}
}
Thank you in advance. Any idea will be welcomed.
Jesús
First of all, don't use a MouseListener for this, but rather use an ActionListener, since this works best for buttons. Next of all, you need to remember that your listener is a class of its own, and it needs a variable of its own to store its own index, else it uses the final value of the loop index which is not what you want. Either this or use the ActionEvent's actionCommand property, a value which will match the text of the button. So:
botones[index].addActionListener(new MyActionListener(index));
and
// a private inner class
private class MyActionListener implements ActionListener {
private int index;
public MyActionListener(int index) {
this.index = index;
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("index is: " + index);
System.out.println("Action Command is: " + e.getActionCommand());
}
}
Or if you want to use an anonymous inner class:
botones[index].addActionListener(new ActionListener() {
private int myIndex;
{
this.myIndex = index;
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("index is: " + myIndex);
}
});

Obtain currently highlighted item from JComboBox popup (not selected item)

I'd like to be able to react when currently highlighted item in a JComboBox drop down list changes. Note that I'm not looking for a way to get the currently selected item, but the highlighted one. When mouse hovers over this popup it highlights the item at mouse position, but this does not affect currently selected item, so I cannot simply listen via an ItemListener or ActionListener to achieve what I want.
I'm trying to create a component which consists of a JComboBox and a coupled tooltip which displays additional information (documentation) for the currently highlighted item.
As my first attempt I'm adding some code to my constructor (extended JComboBox):
import java.awt.BorderLayout;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.accessibility.AccessibleContext;
import javax.accessibility.AccessibleState;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.SwingUtilities;
import javax.swing.plaf.basic.ComboPopup;
public class SomeFrame extends JFrame {
private MyComboBox combo;
public SomeFrame() {
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setSize(100,20);
setLocationRelativeTo(null);
setLayout(new BorderLayout());
combo = new MyComboBox();
combo.setModel(new DefaultComboBoxModel(new String[]{"one", "two", "three", "four"}));
add(combo);
pack();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
SomeFrame frame = new SomeFrame();
frame.setVisible(true);
}
});
}
// this is the important part
private static class MyComboBox extends JComboBox {
public MyComboBox() {
getAccessibleContext().addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if (AccessibleContext.ACCESSIBLE_STATE_PROPERTY.equals(evt.getPropertyName())
&& AccessibleState.FOCUSED.equals(evt.getNewValue())
&& getAccessibleContext().getAccessibleChild(0) instanceof ComboPopup) {
ComboPopup popup = (ComboPopup) getAccessibleContext().getAccessibleChild(0);
JList list = popup.getList();
System.out.println("--> " + String.valueOf(list.getSelectedValue()));
}
}
});
}
}
}
It seems to work, but I got to this code through some shady channels and trial/error, so I'm thinking there has to be a better way of doing it. Any ideas? Is above code even production safe?
Good question and good solution - except that there seems to be bug in accessibleCombo which doesn't update its internal wiring on updateUI, that is, when toggling the LAF:
the accessible selection changes of the list are fired by an internal ListSelectionListener registered to the comboPopup list
the comboPopup is controlled by the ui-delegate and re/created in installUI
accessibleCombo doesn't update its internal list to the newly created and installed
Not much you can do about it. So I would listen directly to the list selection, then you have full control about re-wiring on LAF changes:
public static class XComboBox extends JComboBox {
private ListSelectionListener listener;
public XComboBox() {
uninstall();
install();
}
#Override
public void updateUI() {
uninstall();
super.updateUI();
install();
}
private void uninstall() {
if (listener == null) return;
getPopupList().removeListSelectionListener(listener);
listener = null;
}
protected void install() {
listener = new ListSelectionListener() {
#Override
public void valueChanged(ListSelectionEvent e) {
if (e.getValueIsAdjusting()) return;
JList list = getPopupList();
System.out.println("--> " + String.valueOf(list.getSelectedValue()));
}
};
getPopupList().addListSelectionListener(listener);
}
private JList getPopupList() {
ComboPopup popup = (ComboPopup) getUI().getAccessibleChild(this, 0);
return popup.getList();
}
}
I'm trying to create a component which consists of a JComboBox and a coupled tooltip
Create a custom renderer for the combo box. Then in the renderer use the setToolTipText(...) method.
The section Specifying Tool Tips For Cells from the JTable tutorial shows how to do this for tables. The concept should be the same for a comboBox renderer.

In Java how do you trap the event before the new JTab is switched to?

how do you trap the event before the new tab is switched to?
In every Tab I have JTable and i do something with it's data(delete, add , update). I would like to do data validation(save or cancel changes) before switching to the new tab. I use Java 1.5.
class ViewPanel extends JPanel
{
private void Components() {
setPreferredSize(new Dimension(700, 400));
tabbedPane.addTab("DC", ANSFER.getIcon(),new DcTabPanel(this), "DC");
tabbedPane.addTab("PC", THUMB4.getIcon(),new PcTabPanel(this), "PC");
tabbedPane.addChangeListener(this);
add(tabbedPane);
}
public void stateChanged(ChangeEvent e) {
}
}
JTabbedPane is backed by a SingleSelectionModel. If you extend DefaultSingleSelectionModel, you can override the setSelectedIndex method and implement your logic.
// in new selection model:
public void setSelectedIndex(int index) {
// do pre-switch things here
super.setSelectedIndex(index);
}
// in ViewPanel, on tabbedPane create:
tabbedPane.setModel(newSelectionModel);
The reason you can't simply use a ChangeListener is because that fires on change. By extending the selection model, you fire before the tab change.
You can prevent tab switching by extending JTabbedPane and override setSelectedIndex(int). Here is a small example illustrating that. It simply prevents from switching between non-contiguous tabs:
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
public class Test2 {
private static class BlockingTabbedPane extends JTabbedPane {
public static interface TabSwitchAllower {
public boolean allowTabSwitch(int from, int to);
}
private TabSwitchAllower allower;
public BlockingTabbedPane(TabSwitchAllower allower) {
super();
this.allower = allower;
}
#Override
public void setSelectedIndex(int index) {
if (allower == null || allower.allowTabSwitch(getSelectedIndex(), index)) {
super.setSelectedIndex(index);
}
}
}
protected static void initUI() {
final JFrame frame = new JFrame("test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
BlockingTabbedPane.TabSwitchAllower allower = new BlockingTabbedPane.TabSwitchAllower() {
#Override
public boolean allowTabSwitch(int from, int to) {
if (Math.abs(from - to) == 1) {
return true;
} else {
JOptionPane.showMessageDialog(frame, "You can only switch between contiguous tabs");
}
return false;
}
};
JTabbedPane tabbedPane = new BlockingTabbedPane(allower);
for (int i = 0; i < 10; i++) {
tabbedPane.addTab("Tab-" + i, new JLabel("Hello tab " + i));
}
frame.add(tabbedPane);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
initUI();
}
});
}
}
java actionlistener on a tab
How to Write a Change Listener (Oracle Docs)
JTabbedPane API (Oracle Docs)
Those two links should help you out. I haven't really worked with tabbedPanes, but I am assuming that the getSelectedComponent() will return the current selected tab. So you can have a handle to the currentTab which will be set during instantiation. Then you can have something like this.
class TabListener implements ChangeListener {
public void stateChanged(ChangeEvent e) {
// Replace JSlider with whatever your tab's data type is
JSlider source = (JSlider)e.getSource();
// Use the 'currentTab' handle to do what you want.
currentTab = getSelectedComponent();
// I'm assuming that the 'selected component' by the time this stuff
// runs is going to be the new selected tab.
}
}
I am not too confident about my answer, but I certainly hope that this will point you towards the right direction! Please say if you need any clarification or anything! If I happen to discover anything that I think might be useful, I'll be certain to edit my answer!

Auto-Completing JTextField and Arrow Keys

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).

Categories