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).
Related
I have a table. If I right-click I got a JPopUpMenu but before the pop-up I want to select the row where the right-click event is done. Here is what I've tried.
path_tbl.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
System.out.println(e.getPoint());
Point point = e.getPoint();
int selectedRow = path_tbl.rowAtPoint(point);
path_tbl.setRowSelectionInterval(selectedRow, selectedRow);
}
});
In that event, I cannot get any output from the console when I right-click. However, when I left-click, points are printed to the console.
java.awt.Point[x=105,y=76]
So, this event only works when I left-click. How can I make this event work with right-click?
Since you want custom mouse behavior, you should not use setComponentPopupMenu.
Instead, display the JPopupMenu yourself, using JPopupMenu’s show method:
JPopupMenu menu = /* ... */;
path_tbl.addMouseListener(new MouseAdapter() {
private void showPopupMenuFor(MouseEvent e) {
if (menu.isPopupTrigger(e)) {
Point point = e.getPoint();
int row = path_tbl.rowAtPoint(point);
if (!path_tbl.isRowSelected(row)) {
path_tbl.setRowSelectionInterval(row, row);
}
menu.show(path_tbl, e.getX(), e.getY());
}
}
#Override
public void mousePressed(MouseEvent e) {
showPopupMenuFor(e);
}
#Override
public void mouseReleased(MouseEvent e) {
showPopupMenuFor(e);
}
#Override
public void mouseClicked(MouseEvent e) {
showPopupMenuFor(e);
}
});
You must check the MouseEvent in both mousePressed and mouseReleased, because exactly when a context menu is triggered depends on the platform and the look-and-feel. (Checking in mouseClicked may or may not be necessary, but it doesn’t hurt.)
In most cases, I'm lazy, so if I don't need to do something, then I'd prefer not to. In this case, I'd prefer to make use of the existing API works as much as possible, meaning, make use of JComponent#setComponentPopupMenu, as it will take care of the "how" and "when" the popup should be shown, based on the current platform.
However, as you have discovered, by default, JTable will NOT select the row when the user presses the "right" mouse button, for that, you could just continue with your current workflow, but, checking to see if the MouseEvent is actually a "right" click.
Lucky for us, some of the original Swing developers were also "lazy" and they provided us with SwingUtilities.isRightMouseButton, yea 🎉
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
public final class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new BorderLayout());
DefaultTableModel model = new DefaultTableModel(0, 10);
for (int row = 0; row < 10; row++) {
Vector data = new Vector(10);
for (int col = 0; col < 10; col++) {
String value = row + "x" + ((char) (col + 'A'));
data.add(value);
}
model.addRow(data);
}
JPopupMenu menu = new JPopupMenu();
menu.add("Hello");
menu.add("This looks interesting");
menu.add("I like bi-planes");
JTable table = new JTable(model);
table.setComponentPopupMenu(menu);
table.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if (SwingUtilities.isRightMouseButton(e)) {
Point point = e.getPoint();
int row = table.rowAtPoint(point);
if (!table.isRowSelected(row)) {
table.setRowSelectionInterval(row, row);
}
}
}
});
add(new JScrollPane(table));
}
}
}
I am trying to change the background colour of a number field based on the numbers that are typed in. Just like a number field turns red when you type a letter in it. I want it to also change red when you type numbers below 1 and above 7.
I understand that you can do this with a button, but I want it to change when you're typing.
This is my code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class applet03 extends JApplet {
private JButton bHoeveelheid = new JButton();
private JNumberField nfAantal = new JNumberField();
private JTextArea taLijst = new JTextArea("");
private JScrollPane taLijstScrollPane = new JScrollPane(taLijst);
public void init() {
Container cp = getContentPane();
cp.setLayout(null);
cp.setBounds(0, 0, 442, 478);
bHoeveelheid.setBounds(224, 56, 59, 33);
bHoeveelheid.setMargin(new Insets(2, 2, 2, 2));
bHoeveelheid.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
bHoeveelheid_ActionPerformed(evt);
}
});
cp.add(bHoeveelheid);
nfAantal.setBounds(304, 56, 99, 36);
nfAantal.setText("Vul getal in");
nfAantal.setHorizontalAlignment(SwingConstants.CENTER);
nfAantal.addFocusListener(new FocusAdapter() {
public void focusGained(FocusEvent evt) {
nfAantal_FocusGained(evt);
}
});
nfAantal.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent evt) {
nfAantal_KeyPressed(evt);
}
});
cp.add(nfAantal);
taLijstScrollPane.setBounds(224, 136, 168, 180);
cp.add(taLijstScrollPane);
}
public void bHoeveelheid_ActionPerformed(ActionEvent evt) {
if (nfAantal.getInt() < 1 || nfAantal.getInt() > 7) {
nfAantal.setBackground(Color.RED);
} else {
//some other code (not impotant for now)
}
}
public void nfAantal_FocusGained(FocusEvent evt) {
if (nfAantal.getText().equals("Vul getal in")) {
nfAantal.clear();
}
}
public void nfAantal_KeyPressed(KeyEvent evt) {
if (nfAantal.getInt() < 1 || nfAantal.getInt() > 7) {
nfAantal.setBackground(Color.RED);
} else {
//some other code (not impotant for now)
}
}
}
The button part works, but the KeyEvent not.
And when I run this I keep getting these errors:
Exception in thread "AWT-EventQueue-1" java.lang.NumberFormatException: empty String
But when I do this, it kinda works. I still get the same errors but it works. (By the way not optimal, because it only appends it to the text field every second key pressing.):
public void nfAantal_KeyPressed(KeyEvent evt) {
if (nfAantal.getInt() < 1 || nfAantal.getInt() > 7) {
taLijst.append(nfAantal.getText());
} else {
//some other code (not impotant for now)
}
}
So if someone knows why this doesn't work or knows a better way to accomplish this. Then that would be very appreciated!
(By the way I use Java 1.8)
Edit:
I now have (nfAantal.getText().length() > 0) && (nfAantal.getInt() < 1 || nfAantal.getInt() > 7) in the if statement and that got rid of the errors. (Thanks to #Joe)
But that still doesn't solve my question on how to turn the background red on certain values.
Aditional information about JNumberField:
I think this link has the code that makes up JNumberField and this link contains a download to the .jar file with in there the JNumberField Java file.
Another edit:
I think I found out for myself why it doesn't work with a JNumberfield; in the code it changes the background to white if its value is numeric so only if there is a way to get around this part of the code or change it (which I don't know how to do) my question can be answered for a JNumberField, if this isn't the case then I will use the JFormattedTextField instead.
This is the code that needs to be altered or circumvented:
protected void processKeyEvent(KeyEvent e) {
super.processKeyEvent(e);
if (isNumeric() || getText().equals("-") ||
getText().equals("") || getText().equals("."))
setBackground(Color.white);
else
setBackground(Color.red);
}
I don't know what a JNumberField is. It's not part of the JDK and when I searched with Google, it turned up several different ones.
I also don't understand why you are writing an applet.
Therefore, the below code may not be appropriate since it is a stand-alone Swing application that uses JFormattedTextField and DocumentListener.
Explanations after the code.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.text.NumberFormat;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.NumberFormatter;
public class RedNumbr implements DocumentListener, Runnable {
private JFormattedTextField aantal;
private JFrame frame;
#Override
public void insertUpdate(DocumentEvent event) {
handleDocumentEvent(event);
}
#Override
public void removeUpdate(DocumentEvent event) {
handleDocumentEvent(event);
}
#Override
public void changedUpdate(DocumentEvent event) {
// Never called for 'JFormattedTextField'
}
#Override
public void run() {
showGui();
}
private JPanel createNumberPanel() {
JPanel numberPanel = new JPanel();
NumberFormat format = NumberFormat.getIntegerInstance();
NumberFormatter formatter = new NumberFormatter(format);
aantal = new JFormattedTextField(formatter);
aantal.setColumns(10);
Document doc = aantal.getDocument();
doc.addDocumentListener(this);
numberPanel.add(aantal);
return numberPanel;
}
private void handleDocumentEvent(DocumentEvent event) {
Document doc = event.getDocument();
int len = doc.getLength();
if (len > 0) {
try {
String text = doc.getText(0, len);
int number = Integer.parseInt(text);
Color fg;
if (number < 1 || number > 7) {
fg = Color.red;
}
else {
fg = UIManager.getColor("TextField.foreground");
}
aantal.setForeground(fg);
}
catch (BadLocationException | NumberFormatException x) {
// Ignore.
}
}
}
private void showGui() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createNumberPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new RedNumbr());
}
}
Whenever the contents of the JFormattedTextField are changed, the relevant DocumentListener method is invoked. In those methods I check whether the JFormattedTextField contains a number and if it does then I change the foreground color of the JFormattedTextField according to your conditions, i.e. if the number is less than one (1) or greater than 7 (seven).
Note that the NumberFormatter does not prevent entering non-digits because JFormattedTextField handles that when it loses focus. Nonetheless it handles entering positive and negative numbers, which saves you some work. And the point of my answer is simply to demonstrate how to change the foreground color based on the entered text, which I believe answers your question.
EDIT
In order to change the background of the JFormattedTextField, rather than the foreground, you just need to change two lines in my code, above.
Replace
fg = UIManager.getColor("TextField.foreground");
with
fg = UIManager.getColor("TextField.background");
and also replace
aantal.setForeground(fg);
with
aantal.setBackground(fg);
I suppose that the JNumberField is an extension of JTextField and if it is the case it could be the synchronization problem between the main thread and the thread that is triggered by the KeyEvent action. To make sure that the event thread will be carried out you code it with invokeLater.
public void nfAantal_KeyPressed(KeyEvent evt) {
if (nfAantal.getText().length() > 0) && (nfAantal.getInt() < 1 || nfAantal.getInt() > 7) {
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
nfAantal.setBackground(Color.RED);
}
});
} else {
//some other code (not impotant for now)
}
}
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.
Wrting a chat application, I want the user to be able to send images out of his/her clipboard. For this, I would like to catch any CTRL+Vkeyboard input. Since pasting text should be possible as by default, the original ctrl+v-function (pasting text) must not be overridden.
I see can two approaches, of which none works for me:
1st: Taken from the official Java documentation: KEY LISTENER
editorPane.addKeyListener(new KeyListener() {
#Override
public void keyPressed(KeyEvent e) {
e.getKeyChar()
// when I press ctrl+v, ^ this is falsely a white square character, looks like (U+25A1). Plain v without ctrl does work.
e.getKeyCode()
// ^ this is falsely 0
// (e.getModifiersEx() correctly returns InputEvent.CTRL_DOWN_MASK)
}
2nd: KEY BINDING
InputMap iMap = editorPane.getInputMap(condition);
ActionMap aMap = editorPane.getActionMap();
iMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_DOWN_MASK), "ctrlV");
aMap.put("ctrlV", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
// works, but overrides natural ctrl+v function!
}
});
Any ideas?
Note: I am using a "foreign" keyboard layout (German). But I can't see why this should make any difference - I would pretty much like to have my application work internationally.
Cheers
edit. Alt+SomeKey however is correctly recognized by the KeyListener
edit2. after changing keyboard layout to US, problem persists.
Stick to Keybindings: KeyListener is a low-level API, while Keybindings will provide you consistent, predictable and robust behaviour.
The solution here is quite easy. You can simply combine the actions yourself by adding a CombinedAction class that will execute the "original" action bound to CTRL+V and the "custom" action you want to execute.
See a small example below combining both actions (here my custom action is a Sysout):
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.JComponent;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.KeyStroke;
import javax.swing.ScrollPaneConstants;
public class TestEditorPane {
private JEditorPane editorPane;
public static class CombinedAction implements ActionListener {
private final ActionListener action1;
private final ActionListener action2;
public CombinedAction(ActionListener action1, ActionListener action2) {
super();
this.action1 = action1;
this.action2 = action2;
}
#Override
public void actionPerformed(ActionEvent e) {
if (action1 != null) {
action1.actionPerformed(e);
}
if (action2 != null) {
action2.actionPerformed(e);
}
}
}
public TestEditorPane() {
}
private void initUI() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// JTEXTBOX
editorPane = new JEditorPane();
KeyStroke ctrlV = KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.CTRL_DOWN_MASK);
final ActionListener ctrlVAction = editorPane.getActionForKeyStroke(ctrlV);
editorPane.registerKeyboardAction(new CombinedAction(ctrlVAction, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("This is my action on CTRL+V");
}
}), ctrlV, JComponent.WHEN_FOCUSED);
// JSCROLLPANE
JScrollPane scroll1 = new JScrollPane(editorPane);
scroll1.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scroll1.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
frame.add(scroll1);
frame.setSize(400, 400);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
TestEditorPane test = new TestEditorPane();
test.initUI();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
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.