populate multiple combobox with same model but select diff - java

Having problems with the ComboBox, I have populated multiple ComboBoxes with the same model, but when I run my program and select a value from one ComboBox it selects the same value for the rest.
ComboHBoy.setModel(defaultComboBoxModel);
ComboHGirl.setModel(defaultComboBoxModel);
ComboDHBoy.setModel(defaultComboBoxModel);
ComboDHGirl.setModel(defaultComboBoxModel);

That's because they all are referenced to the same model, any change of the model will affect the all the other combos.
There is no way to solve this except that every combobox have it's own DefaultComboBoxModel.
private DefaultComboBoxModel hBoyModel= new DefaultComboBoxModel();
private DefaultComboBoxModel hGirlModel= new DefaultComboBoxModel();
//....
ComboHBoy.setModel(hBoyModel);
ComboHGirl.setModel(hGrilModel);
//....

Use just a ListModel to manage your data and create a ComboboxModel adapter that is based on the ListModel. This ComboboxModel will only add the selection capability. Remember that a ComboboxModel extends ListModel. So it is easy to adapt the interfaces.
The only tricky part is to handle the update events.
For example:
public class ListAdapterComboboxModel implements ComboBoxModel {
private ListModel dataModel;
private Object selectedObject;
private DataModelListDataListenerAdapter listDataListenerAdapter;
public ListAdapterComboboxModel(ListModel ListModel) {
dataModel = ListModel;
this.listDataListenerAdapter = new DataModelListDataListenerAdapter();
dataModel.addListDataListener(listDataListenerAdapter);
}
public int getSize() {
return dataModel.getSize();
}
public Object getElementAt(int index) {
return dataModel.getElementAt(index);
}
public void addListDataListener(ListDataListener l) {
listDataListenerAdapter.addListDataListener(l);
}
public void removeListDataListener(ListDataListener l) {
listDataListenerAdapter.removeListDataListener(l);
}
public void setSelectedItem(Object anObject) {
if ((selectedObject != null && !selectedObject.equals(anObject))
|| selectedObject == null && anObject != null) {
selectedObject = anObject;
ListDataEvent e = new ListDataEvent(this,
ListDataEvent.CONTENTS_CHANGED, -1, -1);
listDataListenerAdapter.delegateListDataEvent(e);
}
}
public Object getSelectedItem() {
return selectedObject;
}
private class DataModelListDataListenerAdapter implements ListDataListener {
protected EventListenerList listenerList = new EventListenerList();
public void removeListDataListener(ListDataListener l) {
listenerList.remove(ListDataListener.class, l);
}
public void addListDataListener(ListDataListener l) {
listenerList.add(ListDataListener.class, l);
}
public void intervalAdded(ListDataEvent e) {
delegateListDataEvent(e);
}
public void intervalRemoved(ListDataEvent e) {
checkSelection(e);
delegateListDataEvent(e);
}
public void contentsChanged(ListDataEvent e) {
checkSelection(e);
delegateListDataEvent(e);
}
private void checkSelection(ListDataEvent e) {
Object selectedItem = getSelectedItem();
ListModel listModel = (ListModel) e.getSource();
int size = listModel.getSize();
boolean selectedItemNoLongerExists = true;
for (int i = 0; i < size; i++) {
Object elementAt = listModel.getElementAt(i);
if (elementAt != null && elementAt.equals(selectedItem)) {
selectedItemNoLongerExists = false;
break;
}
}
if (selectedItemNoLongerExists) {
ListAdapterComboboxModel.this.selectedObject = null;
}
}
protected void delegateListDataEvent(ListDataEvent lde) {
ListDataListener[] listeners = listenerList
.getListeners(ListDataListener.class);
for (ListDataListener listDataListener : listeners) {
listDataListener.contentsChanged(lde);
}
}
}
}
And then just use it like this
public class ComboboxModelTest extends JFrame{
public static void main(String[] args) {
ComboboxModelTest comboboxModelTest = new ComboboxModelTest();
comboboxModelTest.pack();
comboboxModelTest.setVisible(true);
}
public ComboboxModelTest() {
Container contentPane = getContentPane();
contentPane.setLayout(new FlowLayout());
DefaultListModel defaultListModel = new DefaultListModel();
defaultListModel.addElement("Element 1");
defaultListModel.addElement("Element 2");
ComboBoxModel firstComboboxModel = new ListAdapterComboboxModel(defaultListModel);
ComboBoxModel secondComboboxModel = new ListAdapterComboboxModel(defaultListModel);
JComboBox jComboBox1 = new JComboBox(firstComboboxModel);
JComboBox jComboBox2 = new JComboBox(secondComboboxModel);
contentPane.add(jComboBox1);
contentPane.add(jComboBox2);
}
}
Then you only have to manage the data in one ListModel and you have distinct selection models.
Also take a look at The MVC pattern and SWING.

Related

setAutoCreateRowSorter doesn't sort table column correctly after update

While developing a small task manager, I have noticed that columns aren't sorted correctly. To discard problems with my program, I have created a minimal version but it still fails to order the unique column right.
import java.awt.BorderLayout;
import java.util.List;
import java.util.Random;
import javax.swing.*;
import javax.swing.table.AbstractTableModel;
public class TableSortTest extends JFrame
{
private final JTable table;
private final ATableModel model;
public TableSortTest ()
{
setDefaultCloseOperation (EXIT_ON_CLOSE);
setSize (1366, 768);
setLocationRelativeTo (null);
model = new ATableModel ();
table = new JTable ();
table.setFillsViewportHeight (true);
table.setAutoCreateRowSorter (true);
table.setModel (model);
add (new JScrollPane (table), BorderLayout.CENTER);
setVisible (true);
Worker worker = new Worker ();
worker.execute ();
}
private class Pair
{
int index;
int value;
}
private class Worker extends SwingWorker <Void, Pair>
{
#Override
protected Void doInBackground ()
{
while (!isCancelled ())
{
Random r = new Random ();
for (int i = 0; i < 100; i++)
{
int indice = getIndexInRange (0, 99);
Pair p = new Pair ();
p.index = indice;
p.value = Math.abs (r.nextInt ());
publish (p);
}
try
{
Thread.sleep (1000);
}
catch (InterruptedException ie)
{
ie.printStackTrace ();
}
}
return null;
}
#Override
public void process (List <Pair> items)
{
for (Pair p : items)
{
model.setValueAt (p.value, p.index, 0);
}
}
}
public static int getIndexInRange (int min, int max)
{
return (min + (int) (Math.random () * ((max - min) + 1)));
}
private class ATableModel extends AbstractTableModel
{
private final Integer [] data;
public ATableModel ()
{
data = new Integer [100];
Random r = new Random ();
for (int i = 0; i < 100; i++)
{
data [i] = Math.abs (r.nextInt ());
}
}
#Override
public int getColumnCount ()
{
return 1;
}
#Override
public int getRowCount ()
{
return data.length;
}
#Override
public Object getValueAt (int rowIndex, int columnIndex)
{
return data [rowIndex];
}
#Override
public void setValueAt (Object value, int rowIndex, int columnIndex)
{
data [rowIndex] = (Integer) value;
fireTableRowUpdated (rowIndex, columnIndex);
}
#Override
public Class getColumnClass (int columnIndex)
{
return Integer.class;
}
#Override
public String getColumnName (int col)
{
return "Column";
}
}
public static final void main (String [] args)
{
SwingUtilities.invokeLater (() ->
{
try
{
new TableSortTest ();
}
catch (Exception e)
{
e.printStackTrace ();
}
});
}
}
I have tried with a ScheduledExecutorService + Runnable and a Timer + TimerTask just to test if it was a threading problem, but the behavior is the same. I have also read the Java Tutorial page about the subject. Given that my table only uses standard types I think that a simple table.setAutoCreateRowSorter (true); should do the job, shouldn't it?
Shouldn't the table be sorted after every modification/addition/removal even is fired?
Thanks for your quick answer trashgod. You're right, I meant fireTableRowsUpdated () but I made a mistake when I wrote the code, sorry. The point is that fireTableRowsUpdated (rowIndex, rowIndex) and fireTableCellUpdated (rowIndex, columnIndex) both fail to sort the column correctly. In the real program most of the table rows do change from one iteration to the next so calling fireTableDataChanged () makes perfect sense. But I didn't want to use it because if I select one or more rows to send a signal to the processes or whatever the selection is lost on every update. I have explored this way and found two forms of preserving the selection but it's a bit annoying and one of them breaks the selection with the keyboard. I show the necessary additions to the original code next.
The first form saves the selection before modifying the model and restores it after every update:
...
private class Worker extends SwingWorker <Void, Pair>
{
private int [] selectedRows;
#Override
protected Void doInBackground ()
{
while (!isCancelled ())
{
// Save the selection before modifying the model
int x = table.getSelectedRowCount ();
if (x > 0)
{
selectedRows = new int [x];
int [] tableSelection = table.getSelectedRows ();
for (int i = 0; i < x; i++)
{
selectedRows [i] = table.convertRowIndexToModel (tableSelection [i]);
}
}
Random r = new Random ();
for (int i = 0; i < table.getRowCount (); i++)
{
int indice = getIndexInRange (0, table.getRowCount () - 1);
Pair p = new Pair ();
p.index = indice;
p.value = Math.abs (r.nextInt ());
publish (p);
}
// If I put the code to restore the selection here, it doesn't work...
try
{
Thread.sleep (1000);
}
catch (InterruptedException ie)
{
ie.printStackTrace ();
}
}
return null;
}
#Override
public void process (List <Pair> items)
{
for (Pair p : items)
{
model.setValueAt (p.value, p.index, 1);
}
// Restore the selection on every update
if (selectedRows != null && selectedRows.length > 0)
{
for (int i = 0; i < selectedRows.length; i++)
{
table.addRowSelectionInterval (table.convertRowIndexToView (selectedRows [i]), table.convertRowIndexToView (selectedRows [i]));
}
}
}
}
...
The second form uses a ListSelectionListener, a KeyListener, and a flag. Selection with the keyboard doesn't work. To be honest, I don't know how did I come to get this solution. It probably was by chance:
public class TableSortTestSolucionConSelectionListener extends JFrame implements KeyListener
{
...
private boolean ctrlOrShiftDown = false;
private int [] selectedRows;
#Override
public void keyPressed (KeyEvent e)
{
ctrlOrShiftDown = e.isControlDown () || e.isShiftDown ();
}
#Override
public void keyReleased (KeyEvent e)
{
ctrlOrShiftDown = e.isControlDown () || e.isShiftDown ();
}
#Override
public void keyTyped (KeyEvent e)
{
ctrlOrShiftDown = e.isControlDown () || e.isShiftDown ();
}
public TableSortTestSolucionConSelectionListener ()
{
...
ListSelectionListener lsl = new ListSelectionListener ()
{
#Override
public void valueChanged (ListSelectionEvent e)
{
if (!e.getValueIsAdjusting ())
{
if (!ctrlOrShiftDown)
{
int x = table.getSelectedRowCount ();
if (x > 0)
{
selectedRows = new int [x];
int [] tableSelection = table.getSelectedRows ();
for (int i = 0; i < x; i++)
{
selectedRows [i] = table.convertRowIndexToModel (tableSelection [i]);
}
}
}
// Disable the listener to avoid infinite recursion
table.getSelectionModel ().removeListSelectionListener (this);
if (selectedRows != null && selectedRows.length > 0)
{
for (int i = 0; i < selectedRows.length; i++)
{
table.addRowSelectionInterval (table.convertRowIndexToView (selectedRows [i]), table.convertRowIndexToView (selectedRows [i]));
}
}
table.getSelectionModel ().addListSelectionListener (this);
}
}
};
table.getSelectionModel ().addListSelectionListener (lsl);
...
}
Fortunately today I have found a simple way to get the column sorted correctly and keep the current selection. You only have to add the following to your code:
TableRowSorter trs = (TableRowSorter) table.getRowSorter ();
trs.setSortsOnUpdates (true);
With this both fireTableCellUpdated () and fireTableRowsUpdated () work as I expected. To my understanding, setAutoCreateRowSorter () is only used to sort the rows when you click on the table header.
Greetings.
Using setSortsOnUpdates(), suggested here by #trcs, is the best general solution, but you may be able to optimize updates by the choice of TableModelEvent available to subclasses of AbstractTableModel.
The critical issue is the implementation of setValueAt(). If you meant fireTableRowsUpdated(), instead of fireTableRowUpdated(), note that the parameters represent a range of rows, not a row & column. In this case, because "all cell values in the table's rows may have changed," the revised example below invokes fireTableDataChanged(). I've also changed the model to manage a List<Integer> and normalized the size, N.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.*;
import javax.swing.table.AbstractTableModel;
/** #see https://stackoverflow.com/a/36522182/230513 */
public class TableSortTest extends JFrame {
private final JTable table;
private final ATableModel model;
public TableSortTest() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
model = new ATableModel();
table = new JTable(model){
#Override
public Dimension getPreferredScrollableViewportSize() {
return new Dimension(200, 500);
}
};
table.setFillsViewportHeight(true);
table.setAutoCreateRowSorter(true);
add(new JScrollPane(table), BorderLayout.CENTER);
pack();
setLocationRelativeTo(null);
setVisible(true);
Worker worker = new Worker();
worker.execute();
}
private class Pair {
int index;
int value;
}
private class Worker extends SwingWorker<Void, Pair> {
private static final int N = 100;
private final Random r = new Random();
#Override
protected Void doInBackground() {
while (!isCancelled()) {
for (int i = 0; i < N; i++) {
int index = r.nextInt(N);
Pair p = new Pair();
p.index = index;
p.value = Math.abs(r.nextInt());
publish(p);
}
try {
Thread.sleep(1000);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
return null;
}
#Override
public void process(List<Pair> items) {
for (Pair p : items) {
model.setValueAt(p.value, p.index, 0);
}
}
}
private class ATableModel extends AbstractTableModel {
private static final int N = 100;
private final List<Integer> data = new ArrayList<>(N);
public ATableModel() {
final Random r = new Random();
for (int i = 0; i < N; i++) {
data.add(Math.abs(r.nextInt()));
}
}
#Override
public int getColumnCount() {
return 1;
}
#Override
public int getRowCount() {
return data.size();
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
return data.get(rowIndex);
}
#Override
public void setValueAt(Object value, int rowIndex, int columnIndex) {
data.set(rowIndex, (Integer) value);
fireTableDataChanged();
}
#Override
public Class getColumnClass(int columnIndex) {
return Integer.class;
}
#Override
public String getColumnName(int col) {
return "Column";
}
}
public static final void main(String[] args) {
SwingUtilities.invokeLater(() -> {
new TableSortTest();
});
}
}
Recognizing that this is just an example, the variation below optimizes updates by publishing a List<Integer>, which is passed en bloc to the TableModel via process().
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.*;
import javax.swing.table.AbstractTableModel;
/**
* # see https://stackoverflow.com/a/36522182/230513
*/
public class TableSortTest extends JFrame {
private final JTable table;
private final ATableModel model;
public TableSortTest() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
model = new ATableModel();
table = new JTable(model) {
#Override
public Dimension getPreferredScrollableViewportSize() {
return new Dimension(200, 500);
}
};
table.setFillsViewportHeight(true);
table.setAutoCreateRowSorter(true);
add(new JScrollPane(table), BorderLayout.CENTER);
pack();
setLocationRelativeTo(null);
setVisible(true);
Worker worker = new Worker();
worker.execute();
}
private class Worker extends SwingWorker<List<Integer>, List<Integer>> {
private static final int N = 100;
private final Random r = new Random();
private final List<Integer> data = new ArrayList<>(N);
#Override
protected List<Integer> doInBackground() throws Exception {
while (!isCancelled()) {
data.clear();
for (int i = 0; i < N; i++) {
data.add(Math.abs(r.nextInt()));
}
publish(data);
try {
Thread.sleep(1000);
} catch (InterruptedException ie) {
ie.printStackTrace(System.err);
}
}
return data;
}
#Override
protected void process(List<List<Integer>> chunks) {
for (List<Integer> chunk : chunks) {
model.update(chunk);
}
}
}
private class ATableModel extends AbstractTableModel {
private List<Integer> data = new ArrayList<>();
public void update(List<Integer> data) {
this.data = data;
fireTableDataChanged();
}
#Override
public int getColumnCount() {
return 1;
}
#Override
public int getRowCount() {
return data.size();
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
return data.get(rowIndex);
}
#Override
public Class getColumnClass(int columnIndex) {
return Integer.class;
}
#Override
public String getColumnName(int col) {
return "Column";
}
}
public static final void main(String[] args) {
SwingUtilities.invokeLater(() -> {
new TableSortTest();
});
}
}

Custom JSpinner Model not working

I tried to implement my own JSpinner model to accept an enumeration (including I18N), so I did like that:
searchSpinner.setModel(new AbstractSpinnerModel() {
int index = 0;
int minIndex = 0;
int maxIndex = MY_ENUM.values().length - 1;
Object selected = MY_ENUM.values()[index];
#Override
public Object getValue() {
return selected;
}
#Override
public void setValue(Object value) {
selected = value;
fireStateChanged();
}
#Override
public Object getNextValue() {
if (index < maxIndex) {
index++;
}
fireStateChanged();
return MY_ENUM.values()[index];
}
#Override
public Object getPreviousValue() {
if (index > minIndex) {
index--;
}
fireStateChanged();
return MY_ENUM.values()[index];
}
#Override
public void addChangeListener(ChangeListener l) {
}
#Override
public void removeChangeListener(ChangeListener l) {
}
});
The problem is that did not work, and even the spinner list looks like disabled. What am I doing wrong?
UPDATE: Based on first answer
You should extend from AbstractSpinnerModel (note to folks new to his question -- note that his original question had the class implementing the SpinnerModel interface. He later changed his code to reflect my recommendation) and be sure to call the fireStateChanged() method when appropriately. Also you've not taken into account edge cases and beyond edge cases.
e.g.,
import javax.swing.*;
import javax.swing.JSpinner.DefaultEditor;
public class MySpinnerPanel extends JPanel {
public static void main(String[] args) {
JSpinner spinner = new JSpinner(new MyEnumSpinnerModel());
JSpinner.DefaultEditor editor = (DefaultEditor) spinner.getEditor();
editor.getTextField().setColumns(5);
JPanel panel = new JPanel();
panel.add(spinner);
JOptionPane.showMessageDialog(null, panel);
}
}
enum MyEnum {
FE, FI, FO, FUM, FOO, FUBAR, SPAM
}
class MyEnumSpinnerModel extends AbstractSpinnerModel {
private int index = 0;
#Override
public Object getValue() {
return MyEnum.values()[index];
}
#Override
public void setValue(Object value) {
if (value instanceof MyEnum) {
index = ((MyEnum) value).ordinal();
fireStateChanged();
} else {
String text = value.toString() + " is not a valid enum item";
throw new IllegalArgumentException(text);
}
}
#Override
public Object getNextValue() {
if (index >= MyEnum.values().length - 1) {
return null;
} else {
return MyEnum.values()[index + 1];
}
}
#Override
public Object getPreviousValue() {
if (index <= 0) {
return null;
} else {
return MyEnum.values()[index - 1 ];
}
}
}
Edit
Note that the model itself should not require a listener to notify the view (as per the other answer to this question) as that's what the AbstractSpinnerModel does internally. It's fireStateChange() method is what the model itself should call to trigger this notification, same as most all other similar model structures in Swing such as any TableModel object that you create that derives from the AbstractTableModel. For details, please see the source code for the SpinnerListModel. Your code should emulate this class.
You should use ChangeListener to notify the view of changes in the model.
spinner = new JSpinner(new SpinnerModel() {
private ChangeListener l;
#Override
public void setValue(Object value) {
...
if(l != null) {
l.stateChanged(new ChangeEvent(this));
}
}
...
#Override
public void addChangeListener(ChangeListener l) {
this.l = l;
}
#Override
public void removeChangeListener(ChangeListener l) {
if(this.l == l) {
this.l = null;
}
}
});
Edit: You can use List to register many listeners.

How to change description image in JList java

Below is my code that displays images in a JList. I want to edit the description by each of the images shown in the JList. I don't know how to do it & need help. Thanks...
import java.util.*;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.Serializable;
public class DesignPicture2 {
private static String imageName;
static ArrayList<String> imgName = new ArrayList<String>();
public static void main(String[] args) throws Exception {
DesignPicture2 mm = new DesignPicture2();
mm.getImageName("C:\\Images 2 display");
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
JFrame frame = new JFrame("Image panel");
frame.setSize(800, 500);
//frame.setLocationByPlatform(true);
frame.setLocation(600, 300);
JList imageList = createImageList();
frame.getContentPane().add(new JScrollPane(imageList));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
private static JList createImageList() {
JList imageList = new JList(createModel("C:\\Images 2 display"));
imageList.setCellRenderer(new ImageCellRenderer());
imageList.setLayoutOrientation(JList.HORIZONTAL_WRAP);
imageList.setVisibleRowCount(0);
imageList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
imageList.setFixedCellWidth(240);
imageList.setFixedCellHeight(120);
// imageList.setDragEnabled(false);
//imageList.setDropMode(DropMode.INSERT);
imageList.setTransferHandler(new ImageTransferHandler(imageList));
return imageList;
}
private static DefaultListModel createModel(String path) {
File folder = new File(path);
File[] listOfFiles = folder.listFiles();
DefaultListModel model = new DefaultListModel();
int count = 0;
for (int i = 0; i < listOfFiles.length - 1; i++) {
System.out.println("check path: " + listOfFiles[i]);
imageName = imgName.get(i).toString();
String name = listOfFiles[i].toString();
//load only JPEGS
if (name.endsWith("jpg")) {
try {
ImageIcon ii = new ImageIcon(ImageIO.read(listOfFiles[i]));
model.add(count, ii);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return model;
}
static class ImageTransferHandler extends TransferHandler {
private static final DataFlavor DATA_FLAVOUR = new DataFlavor(ColorIcon.class, "Images");
private final JList previewList;
private boolean inDrag;
ImageTransferHandler(JList previewList) {
this.previewList = previewList;
}
public int getSourceActions(JComponent c) {
return TransferHandler.MOVE;
}
protected Transferable createTransferable(JComponent c) {
inDrag = true;
return new Transferable() {
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[]{DATA_FLAVOUR};
}
public boolean isDataFlavorSupported(DataFlavor flavor) {
return flavor.equals(DATA_FLAVOUR);
}
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
return previewList.getSelectedValue();
}
};
}
public boolean canImport(TransferSupport support) {
if (!inDrag || !support.isDataFlavorSupported(DATA_FLAVOUR)) {
return false;
}
JList.DropLocation dl = (JList.DropLocation) support.getDropLocation();
if (dl.getIndex() == -1) {
return false;
} else {
return true;
}
}
public boolean importData(TransferSupport support) {
if (!canImport(support)) {
return false;
}
Transferable transferable = support.getTransferable();
try {
Object draggedImage = transferable.getTransferData(DATA_FLAVOUR);
JList.DropLocation dl = (JList.DropLocation) support.getDropLocation();
DefaultListModel model = (DefaultListModel) previewList.getModel();
int dropIndex = dl.getIndex();
if (model.indexOf(draggedImage) < dropIndex) {
dropIndex--;
}
model.removeElement(draggedImage);
model.add(dropIndex, draggedImage);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
protected void exportDone(JComponent source, Transferable data, int action) {
super.exportDone(source, data, action);
inDrag = false;
}
}
static class ImageCellRenderer extends JPanel implements ListCellRenderer {
int count = 0;
DefaultListCellRenderer defaultListCellRenderer = new DefaultListCellRenderer();
JLabel imageLabel = new JLabel();
JLabel descriptionLabel = new JLabel();
ImageCellRenderer() {
setLayout(new BorderLayout());
Border emptyBorder = BorderFactory.createEmptyBorder(5, 5, 5, 5);
imageLabel.setBorder(emptyBorder);
descriptionLabel.setBorder(emptyBorder);
add(imageLabel, BorderLayout.AFTER_LINE_ENDS);
add(descriptionLabel, BorderLayout.SOUTH);
// imageLabel.setText(imgName.get(0).toString());
}
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
defaultListCellRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
setBorder(defaultListCellRenderer.getBorder());
setBackground(defaultListCellRenderer.getBackground());
imageLabel.setIcon((Icon) value);
if (count > imgName.size() - 1) {
count = 0;
} else {
descriptionLabel.setText(imgName.get(count).toString());
}
return this;
}
}
public void getImageName(String path) {
int c = 0;
final File dir = new File(path);
// array of supported extensions (use a List if you prefer)
final String[] EXTENSIONS = new String[]{
"jpg", "gif", "png", "bmp" // and other formats you need
// filter to identify images based on their extensions
};
final FilenameFilter IMAGE_FILTER = new FilenameFilter() {
#Override
public boolean accept(final File dir, final String name) {
for (final String ext : EXTENSIONS) {
if (name.endsWith("." + ext)) {
return (true);
}
}
return (false);
}
};
if (dir.isDirectory()) { // make sure it's a directory
for (final File f : dir.listFiles(IMAGE_FILTER)) {
BufferedImage img = null;
c++;
try {
img = ImageIO.read(f);
// you probably want something more involved here
// to display in your UI
System.out.println("image: " + f.getName());
imgName.add(f.getName().toString());
} catch (final IOException e) {
// handle errors here
System.out.println("Error!");
}
}
System.out.println("C: " + c);
} else {
System.out.println("Invalid Directory!");
}
}
static class ColorIcon implements Icon, Serializable {
private Color color;
ColorIcon(Color color) {
this.color = color;
}
public void paintIcon(Component c, Graphics g, int x, int y) {
g.setColor(color);
g.fillRect(x, y, getIconWidth(), getIconHeight());
}
public int getIconWidth() {
return 200;
}
public int getIconHeight() {
return 100;
}
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) {
return false;
}
return color.equals(((ColorIcon) o).color);
}
}
}
When I run the above code, it show the image in proper way, but the description of each image is fixed and I don't know how to change it. Hope anyone can help me.
I agree with trashgod (+1 to his suggestion), a JTable will be a simpler solution, here's why...
JList doesn't support editability, so you'd need to create it...
So, first, we'd need some kind of ListModel that provided some additional functionality, in particular, the ability to set the value at a particular index...
import javax.swing.ListModel;
public interface MutableListModel<E> extends ListModel<E> {
public void setElementAt(E value, int index);
public boolean isCellEditable(int index);
}
Next, we'd need some kind editor, in this case, following standard Swing API conventions, this asks for some kind of base interface
import java.awt.Component;
import javax.swing.CellEditor;
import javax.swing.JList;
public interface ListCellEditor<E> extends CellEditor {
public Component getListCellEditorComponent(
JList<E> list,
E value,
boolean isSelected,
int index);
public void applyEditorValue(E value);
}
Now, we need to create ourselves a custom JList capable of actually performing all the required functionality of editing a cell value...
Things like...
Recognising a "start editing" event
Determine if the cell can be edited
Managing the editing process, preparing and showing the editor, knowing when the editor has stopped or canceled and clean up appropriately...
Handling selection changes while editing is in progress
Handling component focus change (which I've not done cause that's an awesome amount of fun in itself...)
For example...
import java.awt.Component;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JList;
import javax.swing.KeyStroke;
import javax.swing.ListModel;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
public class EditableList<E> extends JList<E> {
private ListCellEditor<E> editor;
private int editingCell = -1;
private Component editorComponent;
private CellEditorHandler handler;
public EditableList(MutableListModel<E> model) {
this();
setModel(model);
}
public EditableList() {
InputMap im = getInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0), "editorCell");
ActionMap am = getActionMap();
am.put("editorCell", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Edit baby");
int cell = getSelectedIndex();
editCellAt(cell);
}
});
addListSelectionListener(new ListSelectionListener() {
#Override
public void valueChanged(ListSelectionEvent e) {
if (isEditing()) {
if (!stopCellEditing()) {
cancelCellEditing();
}
}
}
});
}
public boolean isEditing() {
return editorComponent != null;
}
public void cancelCellEditing() {
getEditor().cancelCellEditing();
}
public boolean stopCellEditing() {
return getEditor().stopCellEditing();
}
public CellEditorHandler getCellEditorHandler() {
if (handler == null) {
handler = new CellEditorHandler();
}
return handler;
}
public void setEditor(ListCellEditor<E> value) {
if (value != editor) {
ListCellEditor old = editor;
editor = value;
firePropertyChange("editor", old, editor);
}
}
public ListCellEditor<E> getEditor() {
return editor;
}
public boolean isCellEditable(int cell) {
boolean isEditable = false;
ListModel model = getModel();
if (model instanceof MutableListModel) {
MutableListModel mcm = (MutableListModel) model;
isEditable = mcm.isCellEditable(cell);
}
return isEditable;
}
protected void editCellAt(int index) {
if (isCellEditable(index)) {
ListCellEditor<E> editor = getEditor();
if (editor != null) {
Rectangle cellBounds = getCellBounds(index, index);
E value = getModel().getElementAt(index);
boolean selected = isSelectedIndex(index);
editingCell = index;
editor.addCellEditorListener(getCellEditorHandler());
editorComponent = editor.getListCellEditorComponent(this, value, selected, index);
editorComponent.setBounds(cellBounds);
ensureIndexIsVisible(index);
add(editorComponent);
revalidate();
}
}
}
public int getEditingCell() {
return editingCell;
}
protected void editingHasStopped(ListCellEditor editor) {
editingCell = -1;
if (editorComponent != null) {
remove(editorComponent);
}
if (editor != null) {
editor.removeCellEditorListener(getCellEditorHandler());
}
}
public class CellEditorHandler implements CellEditorListener {
#Override
public void editingStopped(ChangeEvent e) {
E value = getModel().getElementAt(getEditingCell());
getEditor().applyEditorValue(value);
((MutableListModel) getModel()).setElementAt(value, getEditingCell());
editingHasStopped((ListCellEditor)e.getSource());
}
#Override
public void editingCanceled(ChangeEvent e) {
editingHasStopped((ListCellEditor)e.getSource());
}
}
}
Now, having done all that, you will need change the way you've structured your program, instead of using a List and ListModel to manage the descriptions and images separately, you should probably merge the concept into a single, manageable object, for example...
public class ImagePreview {
private String name;
private ImageIcon image;
public ImagePreview(String name, ImageIcon image) {
this.name = name;
this.image = image;
}
public String getDescription() {
return name;
}
public ImageIcon getImage() {
return image;
}
protected void setDescription(String description) {
this.name = description;
}
}
Even if you choose to use a JTable instead, you'll find this easier to manage...
Now we need some way to render and edit these values, to this end, I choose to start with a base component which could display the image and text...
public class ImagePreviewPane extends JPanel {
private JLabel imageLabel = new JLabel();
private JLabel descriptionLabel = new JLabel();
public ImagePreviewPane() {
setLayout(new BorderLayout());
Border emptyBorder = BorderFactory.createEmptyBorder(5, 5, 5, 5);
imageLabel.setBorder(emptyBorder);
descriptionLabel.setBorder(emptyBorder);
add(imageLabel, BorderLayout.CENTER);
add(descriptionLabel, BorderLayout.SOUTH);
}
protected JLabel getDescriptionLabel() {
return descriptionLabel;
}
protected JLabel getImageLabel() {
return imageLabel;
}
public void setImage(ImageIcon icon) {
imageLabel.setIcon(icon);
}
public void setDescription(String text) {
descriptionLabel.setText(text);
}
}
Create an extended version that could handle editing...
public static class ImagePreviewEditorPane extends ImagePreviewPane {
private JTextField editor;
public ImagePreviewEditorPane() {
super();
editor = new JTextField();
remove(getDescriptionLabel());
add(editor, BorderLayout.SOUTH);
}
#Override
public void setDescription(String text) {
editor.setText(text);
}
public String getDescription() {
return editor.getText();
}
public void setImagePreview(ImagePreview preview) {
setImage(preview.getImage());
setDescription(preview.getDescription());
}
#Override
public void addNotify() {
super.addNotify();
editor.requestFocusInWindow();
}
}
This is done to try and make it easier to modify the components later...
Next, a ListCellRenderer
public class ImageCellRenderer extends ImagePreviewPane implements ListCellRenderer {
public ImageCellRenderer() {
}
#Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
Color bg = null;
Color fg = null;
JList.DropLocation dropLocation = list.getDropLocation();
if (dropLocation != null
&& !dropLocation.isInsert()
&& dropLocation.getIndex() == index) {
bg = DefaultLookup.getColor(this, getUI(), "List.dropCellBackground");
fg = DefaultLookup.getColor(this, getUI(), "List.dropCellForeground");
isSelected = true;
}
if (isSelected) {
setBackground(bg == null ? list.getSelectionBackground() : bg);
setForeground(fg == null ? list.getSelectionForeground() : fg);
} else {
setBackground(list.getBackground());
setForeground(list.getForeground());
}
if (value instanceof ImagePreview) {
ImagePreview ip = (ImagePreview) value;
setImage(ip.getImage());
setDescription(ip.getDescription());
} else {
setImage(null);
setDescription("??");
}
setEnabled(list.isEnabled());
setFont(list.getFont());
return this;
}
}
And editor...
public class ImagePreviewListCellEditor extends AbstactListCellEditor<ImagePreview> {
private ImagePreviewEditorPane previewPane;
public ImagePreviewListCellEditor() {
previewPane = new ImagePreviewEditorPane();
InputMap im = previewPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "accept");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "cancel");
ActionMap am = previewPane.getActionMap();
am.put("accept", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
stopCellEditing();
}
});
am.put("cancel", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
cancelCellEditing();
}
});
}
public void applyEditorValue(ImagePreview preview) {
preview.setDescription(previewPane.getDescription());
}
#Override
public Component getListCellEditorComponent(JList<ImagePreview> list, ImagePreview value, boolean isSelected, int index) {
Color bg = null;
Color fg = null;
JList.DropLocation dropLocation = list.getDropLocation();
if (dropLocation != null
&& !dropLocation.isInsert()
&& dropLocation.getIndex() == index) {
bg = DefaultLookup.getColor(previewPane, previewPane.getUI(), "List.dropCellBackground");
fg = DefaultLookup.getColor(previewPane, previewPane.getUI(), "List.dropCellForeground");
isSelected = true;
}
if (isSelected) {
previewPane.setBackground(bg == null ? list.getSelectionBackground() : bg);
previewPane.setForeground(fg == null ? list.getSelectionForeground() : fg);
} else {
previewPane.setBackground(list.getBackground());
previewPane.setForeground(list.getForeground());
}
if (value instanceof ImagePreview) {
ImagePreview preview = (ImagePreview)value;
previewPane.setImagePreview(preview);
} else {
previewPane.setImagePreview(null);
}
return previewPane;
}
}
And finally, putting it altogether...
public class DesignPicture2 {
public static void main(String[] args) throws Exception {
DesignPicture2 mm = new DesignPicture2();
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
JFrame frame = new JFrame("Image panel");
frame.setSize(800, 500);
frame.setLocation(600, 300);
JList imageList = createImageList();
frame.getContentPane().add(new JScrollPane(imageList));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
private static JList createImageList() {
EditableList<ImagePreview> imageList = new EditableList(createModel("..."));
imageList.setEditor(new ImagePreviewListCellEditor());
imageList.setCellRenderer(new ImageCellRenderer());
imageList.setLayoutOrientation(JList.HORIZONTAL_WRAP);
imageList.setVisibleRowCount(0);
imageList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
imageList.setFixedCellWidth(240);
imageList.setFixedCellHeight(120);
return imageList;
}
private static MutableListModel<ImagePreview> createModel(String path) {
File folder = new File(path);
File[] listOfFiles = folder.listFiles();
DefaultMutableListModel<ImagePreview> model = new DefaultMutableListModel<>();
int count = 0;
for (int i = 0; i < listOfFiles.length - 1; i++) {
System.out.println("check path: " + listOfFiles[i]);
String name = listOfFiles[i].toString();
if (name.endsWith("jpg")) {
try {
ImageIcon ii = new ImageIcon(ImageIO.read(listOfFiles[i]));
model.addElement(new ImagePreview(name, ii));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return model;
}
}
JList does not support the notion of a cell editor. Instead, use a two-column JTable. Some important points:
Your model's isCellEditable() implementation should return true for the description column in order to make it editable.
Your model's implementation of getColumnClass() can let the default renderer display your image by returning ImageIcon or Icon .

How to use Ctrl+Z and Ctrl+Y with all Text Components?

In fact i know how to implement using CTRL+Z (Undo) and CTRL+Y (Redo) with one JTextField. But i have hundreds of Text Components in my Swing application, so is there a way to apply this for all Text Components in my application, so when i click CTRL+Z in any Text Component it would undo the last entry in that Field ?
I have tried to implement it in EventQueue, but it did not work !
To make all your text components "undoable", you can simply create them using your own subclass like:
public class MyTextField extends JTextField {
public MyTextField() {
final UndoManager undoMgr = new UndoManager();
// Add listener for undoable events
getDocument().addUndoableEditListener(new UndoableEditListener() {
public void undoableEditHappened(UndoableEditEvent pEvt) {
undoMgr.addEdit(pEvt.getEdit());
}
});
// Add undo/redo actions
getActionMap().put(UNDO_ACTION, new AbstractAction(UNDO_ACTION) {
public void actionPerformed(ActionEvent pEvt) {
try {
if (undoMgr.canUndo()) {
undoMgr.undo();
}
} catch (CannotUndoException e) {
e.printStackTrace();
}
}
});
getActionMap().put(REDO_ACTION, new AbstractAction(REDO_ACTION) {
public void actionPerformed(ActionEvent pEvt) {
try {
if (undoMgr.canRedo()) {
undoMgr.redo();
}
} catch (CannotRedoException e) {
e.printStackTrace();
}
}
});
// Create keyboard accelerators for undo/redo actions (Ctrl+Z/Ctrl+Y)
getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_DOWN_MASK),
UNDO_ACTION);
getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_Y, InputEvent.CTRL_DOWN_MASK),
REDO_ACTION);
}
}
Then instead of creating JTextFields, create MyTextFields. The limitation is that you may also want to create another subclass for JTextArea and so on for other JTextComponents. So it is also possible to use an utility method to add Undo/Redo features to any existing JTextCompoent:
public final static String UNDO_ACTION = "Undo";
public final static String REDO_ACTION = "Redo";
public static void makeUndoable(JTextComponent pTextComponent) {
final UndoManager undoMgr = new UndoManager();
// Add listener for undoable events
pTextComponent.getDocument().addUndoableEditListener(new UndoableEditListener() {
public void undoableEditHappened(UndoableEditEvent evt) {
undoMgr.addEdit(evt.getEdit());
}
});
// Add undo/redo actions
pTextComponent.getActionMap().put(UNDO_ACTION, new AbstractAction(UNDO_ACTION) {
public void actionPerformed(ActionEvent evt) {
try {
if (undoMgr.canUndo()) {
undoMgr.undo();
}
} catch (CannotUndoException e) {
e.printStackTrace();
}
}
});
pTextComponent.getActionMap().put(REDO_ACTION, new AbstractAction(REDO_ACTION) {
public void actionPerformed(ActionEvent evt) {
try {
if (undoMgr.canRedo()) {
undoMgr.redo();
}
} catch (CannotRedoException e) {
e.printStackTrace();
}
}
});
// Create keyboard accelerators for undo/redo actions (Ctrl+Z/Ctrl+Y)
pTextComponent.getInputMap().put(
KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_DOWN_MASK), UNDO_ACTION);
pTextComponent.getInputMap().put(
KeyStroke.getKeyStroke(KeyEvent.VK_Y, InputEvent.CTRL_DOWN_MASK), REDO_ACTION);
}
The final and absolutely transparent solution would be to implement your own UI class using Lnf features, but you may want to think twice before making all TextComponents undoable, for memory consumptions reasons for example if you often perform huge text modifications to these components...
you can gel list of built_in KeyBindings short_cuts implemented in the API's
notice you have to check or prepare your code for all accesible Look and Feels
you can get built_in KeyBindings short_cuts and replace that as you expecting, System ClipBoard is very often modified,
never tried but on this forum you can foud out rellevant info How to change, replace KeyBindings short_cuts
list of built_in KeyBindings short_cuts
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.table.*;
import javax.swing.filechooser.*;
public class KeyBindings implements ItemListener {
private static final String PACKAGE = "javax.swing.";
private static final String[] COLUMN_NAMES = {"Action", "When Focused", "When In Focused Window", "When Ancestor"};
private static String selectedItem;
private JComponent contentPane;
private JMenuBar menuBar;
private JTable table;
private JComboBox comboBox;
private Hashtable<String, DefaultTableModel> models;
/*
* Constructor
*/
public KeyBindings() {
models = new Hashtable<String, DefaultTableModel>();
contentPane = new JPanel(new BorderLayout());
contentPane.add(buildNorthComponent(), BorderLayout.NORTH);
contentPane.add(buildCenterComponent(), BorderLayout.CENTER);
resetComponents();
}
/*
* The content pane should be added to a high level container
*/
public JComponent getContentPane() {
return contentPane;
}
/*
* A menu can also be added which provides the ability to switch
* between different LAF's.
*/
public JMenuBar getMenuBar() {
if (menuBar == null) {
menuBar = createMenuBar();
}
return menuBar;
}
/*
* This panel is added to the North of the content pane
*/
private JComponent buildNorthComponent() {
comboBox = new JComboBox();
JLabel label = new JLabel("Select Component:");
label.setDisplayedMnemonic('S');
label.setLabelFor(comboBox);
JPanel panel = new JPanel();
panel.setBorder(new EmptyBorder(15, 0, 15, 0));
panel.add(label);
panel.add(comboBox);
return panel;
}
/*
* Check the key name to see if it is the UI property
*/
private String checkForUIKey(String key) {
if (key.endsWith("UI") && key.indexOf('.') == -1) {
String componentName = key.substring(0, key.length() - 2);// Ignore these components
if (componentName.equals("PopupMenuSeparator") || componentName.equals("ToolBarSeparator") || componentName.equals("DesktopIcon")) {
return null;
} else {
return componentName;
}
}
return null;
}
/*
** Build the emtpy table to be added in the Center
*/
private JComponent buildCenterComponent() {
DefaultTableModel model = new DefaultTableModel(COLUMN_NAMES, 0);
table = new JTable(model) {
private static final long serialVersionUID = 1L;
#Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
table.setAutoCreateColumnsFromModel(false);
table.getColumnModel().getColumn(0).setPreferredWidth(200);
table.getColumnModel().getColumn(1).setPreferredWidth(200);
table.getColumnModel().getColumn(2).setPreferredWidth(200);
table.getColumnModel().getColumn(3).setPreferredWidth(200);
Dimension d = table.getPreferredSize();
d.height = 350;
table.setPreferredScrollableViewportSize(d);
table.getTableHeader().setFocusable(true);
return new JScrollPane(table);
}
/*
* When the LAF is changed we need to reset all the items
*/
private void resetComponents() {
models.clear();
((DefaultTableModel) table.getModel()).setRowCount(0);
Vector<String> comboBoxItems = new Vector<String>(50);// buildItemsMap();
UIDefaults defaults = UIManager.getLookAndFeelDefaults();
for (Object key : defaults.keySet()) { // All Swing components will have a UI property.
String componentName = checkForUIKey(key.toString());
if (componentName != null) {
comboBoxItems.add(componentName);
}
}
Collections.sort(comboBoxItems);
comboBox.removeItemListener(this);
comboBox.setModel(new DefaultComboBoxModel(comboBoxItems));
comboBox.setSelectedIndex(-1);
comboBox.addItemListener(this);
comboBox.requestFocusInWindow();
if (selectedItem != null) {
comboBox.setSelectedItem(selectedItem);
}
}
/**
* Create menu bar
*/
private JMenuBar createMenuBar() {
JMenuBar menuBar1 = new JMenuBar();
menuBar1.add(createFileMenu());
menuBar1.add(createLAFMenu());
return menuBar1;
}
/**
* Create menu items for the Application menu
*/
private JMenu createFileMenu() {
JMenu menu = new JMenu("Application");
menu.setMnemonic('A');
menu.addSeparator();
menu.add(new ExitAction());
return menu;
}
/**
* Create menu items for the Look & Feel menu
*/
private JMenu createLAFMenu() {
ButtonGroup bg = new ButtonGroup();
JMenu menu = new JMenu("Look & Feel");
menu.setMnemonic('L');
String lafId = UIManager.getLookAndFeel().getID();
UIManager.LookAndFeelInfo[] lafInfo = UIManager.getInstalledLookAndFeels();
for (int i = 0; i < lafInfo.length; i++) {
String laf = lafInfo[i].getClassName();
String name = lafInfo[i].getName();
Action action = new ChangeLookAndFeelAction(laf, name);
JRadioButtonMenuItem mi = new JRadioButtonMenuItem(action);
menu.add(mi);
bg.add(mi);
if (name.equals(lafId)) {
mi.setSelected(true);
}
}
return menu;
}
/*
* Implement the ItemListener interface
*/
#Override
public void itemStateChanged(ItemEvent e) {
String componentName = (String) e.getItem();
changeTableModel(getClassName(componentName));
selectedItem = componentName;
}
/*
* Use the component name to build the class name
*/
private String getClassName(String componentName) {
if (componentName.equals("TableHeader")) {// The table header is in a child package
return PACKAGE + "table.JTableHeader";
} else {
return PACKAGE + "J" + componentName;
}
}
/*
* Change the TabelModel in the table for the selected component
*/
private void changeTableModel(String className) {
DefaultTableModel model = models.get(className); // Check if we have already built the table model for this component
if (model != null) {
table.setModel(model);
return;
}
model = new DefaultTableModel(COLUMN_NAMES, 0); // Create an empty table to start with
table.setModel(model);
models.put(className, model);
JComponent component = null; // Create an instance of the component so we can get the default Action map and Input maps
try {
if (className.endsWith("JFileChooser")) {// Hack so I don't have to sign the jar file for usage in Java Webstart
component = new JFileChooser(new DummyFileSystemView());
} else {
Object o = Class.forName(className).newInstance();
component = (JComponent) o;
}
} catch (Exception e) {
Object[] row = {e.toString(), "", "", ""};
model.addRow(row);
return;
}
ActionMap actionMap = component.getActionMap(); // Not all components have Actions defined
Object[] keys = actionMap.allKeys();
if (keys == null) {
Object[] row = {"No actions found", "", "", ""};
model.addRow(row);
return;
}
// In some ActionMaps a key of type Object is found (I have no idea why)
// which causes a ClassCastExcption when sorting so we will ignore it
// by converting that entry to the empty string
for (int i = 0; i < keys.length; i++) {
Object key = keys[i];
if (key instanceof String) {
continue;
} else {
keys[i] = "";
}
}
Arrays.sort(keys);
for (int i = 0; i < keys.length; i++) { // Create a new row in the model for every Action found
Object key = keys[i];
if (key != "") {
Object[] row = {key, "", "", ""};
model.addRow(row);
}
}
// Now check each InputMap to see if a KeyStroke is bound the the Action
updateModelForInputMap(model, 1, component.getInputMap(JComponent.WHEN_FOCUSED));
updateModelForInputMap(model, 2, component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW));
updateModelForInputMap(model, 3, component.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT));
}
/*
* The model is potentially update for each of the 3 different InputMaps
*/
private void updateModelForInputMap(TableModel model, int column, InputMap inputMap) {
if (inputMap == null) {
return;
}
KeyStroke[] keys = inputMap.allKeys();
if (keys == null) {
return;
}
// The InputMap is keyed by KeyStroke, however we want to be able to
// access the action names that are bound to a KeyStroke so we will create
// a Hashtble that is keyed by action name.
// Note that multiple KeyStrokes can be bound to the same action name.
Hashtable<Object, String> actions = new Hashtable<Object, String>(keys.length);
for (int i = 0; i < keys.length; i++) {
KeyStroke key = keys[i];
Object actionName = inputMap.get(key);
Object value = actions.get(actionName);
if (value == null) {
actions.put(actionName, key.toString().replace("pressed ", ""));
} else {
actions.put(actionName, value + ", " + key.toString().replace("pressed ", ""));
}
}
for (int i = 0; i < model.getRowCount(); i++) {
// Now we can update the model for those actions that have KeyStrokes mapped to them
String o = actions.get(model.getValueAt(i, 0));
if (o != null) {
model.setValueAt(o.toString(), i, column);
}
}
}
/*
* Change the LAF and recreate the UIManagerDefaults so that the properties
* of the new LAF are correctly displayed.
*/
private class ChangeLookAndFeelAction extends AbstractAction {
private static final long serialVersionUID = 1L;
private String laf;
protected ChangeLookAndFeelAction(String laf, String name) {
this.laf = laf;
putValue(Action.NAME, name);
putValue(Action.SHORT_DESCRIPTION, getValue(Action.NAME));
}
#Override
public void actionPerformed(ActionEvent e) {
try {
JMenuItem mi = (JMenuItem) e.getSource();
JPopupMenu popup = (JPopupMenu) mi.getParent();
JRootPane rootPane = SwingUtilities.getRootPane(popup.getInvoker());
Component c = rootPane.getContentPane().getComponent(0);
rootPane.getContentPane().remove(c);
UIManager.setLookAndFeel(laf);
KeyBindings bindings = new KeyBindings();
rootPane.getContentPane().add(bindings.getContentPane());
SwingUtilities.updateComponentTreeUI(rootPane);
rootPane.requestFocusInWindow();
} catch (Exception ex) {
System.out.println("Failed loading L&F: " + laf);
System.out.println(ex);
}
}
}
private class ExitAction extends AbstractAction {
private static final long serialVersionUID = 1L;
public ExitAction() {
putValue(Action.NAME, "Exit");
putValue(Action.SHORT_DESCRIPTION, getValue(Action.NAME));
putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_X));
}
#Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
}
private class DummyFileSystemView extends FileSystemView {
#Override
public File createNewFolder(File containingDir) {
return null;
}
#Override
public File getDefaultDirectory() {
return null;
}
#Override
public File getHomeDirectory() {
return null;
}
}
private static void createAndShowGUI() {
KeyBindings application = new KeyBindings();
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame("Key Bindings");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setJMenuBar(application.getMenuBar());
frame.getContentPane().add(application.getContentPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
//UIManager.put("swing.boldMetal", Boolean.FALSE);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowGUI();
}
});
}
}
If you want to run "global events" on your application regardless of where you your current focus is, you'll need to work with the KeyboardFocusManager :
KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
kfm.addKeyEventDispatcher(new KeyEventDispatcher() {
#Override
public boolean dispatchKeyEvent(KeyEvent e) {
// do your stuff here
return done;
}
});
Hope this helps.

java comboBox autocomplete

Can someone tell me how to change this code to have autoselection and I could be able to write not existing items, because it doesnt let me to write new items.
public class ComboBoxFill extends PlainDocument
{
ComboBoxModel model;
JComboBox comboBox=new JComboBox();
JTextComponent editor;
public ComboBoxFill(ComboBoxModel model, JComboBox comboBox,JTextComponent editor)
{
this.model = model;
this.comboBox=comboBox;
this.editor=editor;
}
public void insertString (int offs,String str,AttributeSet a) throws BadLocationException
{
String currentText=getText(0,getLength());
String beforeOffset=currentText.substring(0,offs);
String afterOffset=currentText.substring(offs,currentText.length());
String futureText = beforeOffset+str+afterOffset;
Object item =lookupItem(futureText);
if (item!=null)
{
comboBox.setSelectedItem(item);
}else
{
item = comboBox.getSelectedItem();
offs=offs-str.length();
comboBox.getToolkit().beep();
}
super.remove(0, getLength());
super.insertString(0, item.toString(), a);
if (item.toString().equals(str)&&offs==0)
{
highlightCompletedText(0);
}else{
highlightCompletedText(offs+str.length());
comboBox.setPopupVisible(true);
}
}
private boolean startsWithIgnoreCase(String str1, String str2) {
return str1.toUpperCase().startsWith(str2.toUpperCase());
}
private void highlightCompletedText(int start)
{
editor.setCaretPosition (getLength());
editor.moveCaretPosition(start);
}
private Object lookupItem(String pattern)
{
Object selectedItem=model.getSelectedItem();
if (selectedItem!=null && startsWithIgnoreCase(selectedItem.toString(), pattern)){
return selectedItem;
}else{
for (int i=0, n=model.getSize();i<n;i++){
Object currentItem = model.getElementAt(i);
if (startsWithIgnoreCase(currentItem.toString(),pattern))
{
return currentItem;
}
}
}
return null;
}
}
I call it this way:
JTextComponent editor3 = (JTextComponent) comboBox_2.getEditor().getEditorComponent();
editor3.setDocument(new ComboBoxFill(comboBox_2.getModel(),comboBox_2, editor3));
Java2s has an example for this: AutocompleteComboBox

Categories