I am using javax.swing.JFileChooser swing component in my Java Project for opening file by dialog. How to list recently used files for selection in JFileChooser. Everytime I am going inside the directory and selecting file which is time-consuming.
How do I list last few recently used files in the component itself so that we dont need to navigate through the directories again and again to select a file?
JFileChooser allows you to supply a accessory Component which is added to the JFileChooser component, on the right side under Windows.
What you could do is ...
Create a JList and ListModel, set the JList as the JFileChoosers accessory (wrapping it in JScrollPane)
Each time you select a file, add it to a Set
Each time your go to open the JFileChooser, update the JList's model with the values from the Set (or back the model with the Set).
Each time the user selects a value from the list, you will need to change the JFileChoosers selectedFile property to reflect the change...
For more details, take a look at Providing an Accessory Component for more details...
Updated
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import javax.swing.AbstractListModel;
import javax.swing.DefaultListCellRenderer;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.filechooser.FileSystemView;
public class TestFileChooser {
public static void main(String[] args) {
new TestFileChooser();
}
public TestFileChooser() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JFileChooser fc;
private RectentFileList rectentFileList;
public TestPane() {
setLayout(new GridBagLayout());
JButton chooser = new JButton("Choose");
chooser.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (fc == null) {
fc = new JFileChooser();
rectentFileList = new RectentFileList(fc);
fc.setAccessory(rectentFileList);
fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
}
switch (fc.showOpenDialog(TestPane.this)) {
case JOptionPane.OK_OPTION:
File file = fc.getSelectedFile();
rectentFileList.add(file);
break;
}
}
});
add(chooser);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
public class RectentFileList extends JPanel {
private final JList<File> list;
private final FileListModel listModel;
private final JFileChooser fileChooser;
public RectentFileList(JFileChooser chooser) {
fileChooser = chooser;
listModel = new FileListModel();
list = new JList<>(listModel);
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list.setCellRenderer(new FileListCellRenderer());
setLayout(new BorderLayout());
add(new JScrollPane(list));
list.addListSelectionListener(new ListSelectionListener() {
#Override
public void valueChanged(ListSelectionEvent e) {
if (!e.getValueIsAdjusting()) {
File file = list.getSelectedValue();
// You might like to check to see if the file still exists...
fileChooser.setSelectedFile(file);
}
}
});
}
public void clearList() {
listModel.clear();
}
public void add(File file) {
listModel.add(file);
}
public class FileListModel extends AbstractListModel<File> {
private List<File> files;
public FileListModel() {
files = new ArrayList<>();
}
public void add(File file) {
if (!files.contains(file)) {
if (files.isEmpty()) {
files.add(file);
} else {
files.add(0, file);
}
fireIntervalAdded(this, 0, 0);
}
}
public void clear() {
int size = files.size() - 1;
if (size >= 0) {
files.clear();
fireIntervalRemoved(this, 0, size);
}
}
#Override
public int getSize() {
return files.size();
}
#Override
public File getElementAt(int index) {
return files.get(index);
}
}
public class FileListCellRenderer extends DefaultListCellRenderer {
#Override
public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (value instanceof File) {
File file = (File) value;
Icon ico = FileSystemView.getFileSystemView().getSystemIcon(file);
setIcon(ico);
setToolTipText(file.getParent());
setText(file.getName());
}
return this;
}
}
}
}
The question of persistence is broad question and will come down to your personal needs, for example, you could just dump the list of files out to a flat file, this is probably the simplest solution, as it means you can simply read the file from start to finish and know you have the entire contents. Also, writing out the file again will override any previous values, making it easy to manage.
Other solutions might require to provide a "count" property, which you would then suffix to a known key to list the values, which would require to manually remove the old values when you update the details. You could also try using a delimiter to save all the values as a single value in the persistence store, but this wrought with issues of picking a delimiter that won't be used within the file names (the path separator might do :D)
Take a look at How can I save the state of my program and then load it? for some more ideas...
Updated
After a little thought, you could use the Preferences API to store the list of files using a single key by using the File.pathSeparator, as this should be unique and not used by a file name/path.
For example, you could save the list using something like...
StringBuilder sb = new StringBuilder(128);
for (int index = 0; index < listModel.getSize(); index++) {
File file = listModel.getElementAt(index);
if (sb.length() > 0) {
sb.append(File.pathSeparator);
}
sb.append(file.getPath());
}
System.out.println(sb.toString());
Preferences p = Preferences.userNodeForPackage(TestFileChooser.class);
p.put("RectentFileList.fileList", sb.toString());
And load it again using something like...
Preferences p = Preferences.userNodeForPackage(TestFileChooser.class);
String listOfFiles = p.get("RectentFileList.fileList", null);
if (listOfFiles != null) {
String[] files = listOfFiles.split(File.pathSeparator);
for (String fileRef : files) {
File file = new File(fileRef);
if (file.exists()) {
add(file);
}
}
}
Use setSelectedFile(File file) method of JFileChooser.
The doc says:
public void setSelectedFile(File file)
Sets the selected file. If the file's parent directory is not the
current directory, changes the current directory to be the file's
parent directory.
This links may be helpful
example by peeskillet
Related
As simple as Renderers and Editors sound and despite the dozen or so SO bookmarks I return to regarding similar issues I’m missing something elementary. I want to drag any old text file into a 2-column JTable, have the first column display the filename and the second contain a JComboBox whose options depend on the contents of the dragged file. (In the code below I just fake a few entries.)
This all works fine until I make a selection from a combo box - the selection doesn’t display - just a combo box, populated correctly but no selection made. I know it must have something to do with my misuse of renderers/editors but after at least two weeks of flailing I’m seeking professional help. And if you think I’ve totally missed the boat on how renderers and editors are written, well, I’m glad you didn’t see my earlier attempts.
Hopefully this code qualifies as an SSCCE - sincere apologies if I’ve included something I shouldn’t have. I’ve retained the DnD stuff just in case it has some significance.
For what it’s worth, I use a static list of ComboBoxModels (one per row) since each JComboBox contains different options, and likewise TableCellEditors (although I don’t know if that’s the right way to go about it).
To run this just drag any file into the table that appears and then make a selection from the JComboBox in the right column and watch it ignore you. Thanks very much, even if you have some advice without taking the trouble of running this.
Java 1.7/OS X 10.9.5/Eclipse Mars.2
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.swing.AbstractCellEditor;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.MutableComboBoxModel;
import javax.swing.SwingUtilities;
import javax.swing.TransferHandler;
import javax.swing.event.ListDataListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
public class Main extends JFrame {
static List<AComboBoxModel> priceComboModels = new ArrayList<AComboBoxModel>();
static List<DefaultCellEditor> editors = new ArrayList<DefaultCellEditor>();
public Main() {
setLayout(new BorderLayout());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setPreferredSize(new Dimension(500, 400));
JPanel panel = new JPanel(new BorderLayout());
JTable table = new JTable(0, 2) {
public TableCellEditor getCellEditor(int rinx, int cinx) {
if (cinx == 0) {
return super.getCellEditor(rinx, cinx);
}
return editors.get(rinx);
}
};
table.setPreferredScrollableViewportSize(new Dimension(360, 80));
table.setTransferHandler(new ATransferHandler());
table.setModel(new ATableModel());
TableColumnModel tcm = table.getColumnModel();
tcm.getColumn(0).setHeaderValue("File Name");
tcm.getColumn(1).setHeaderValue("Selection");
TableColumn column = tcm.getColumn(1);
column.setCellRenderer(new ACellRenderer());
column.setCellEditor(new ACellEditor());
table.setDragEnabled(true);
table.setFillsViewportHeight(true);
JScrollPane sp = new JScrollPane(
table,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED
);
panel.add(sp, BorderLayout.CENTER);
panel.setPreferredSize(new Dimension(200, 300));
add(panel, BorderLayout.CENTER);
pack();
}
public static int addComboModel(AComboBoxModel model) {
priceComboModels.add(model);
return priceComboModels.size() - 1;
}
public static AComboBoxModel getComboModelAt(int inx) {
return priceComboModels.get(inx);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Main().setVisible(true);
}
});
}
}
class ATableModel extends DefaultTableModel {
List<ARecord> data = new ArrayList<ARecord>();
public void addRow(ARecord row) {
data.add(row);
fireTableRowsInserted(data.size() - 1, data.size() - 1);
}
#Override
public int getRowCount() {
return data == null ? 0 : data.size();
}
#Override
public int getColumnCount() {
return 2;
}
public void setValueAt(Object value, int rinx, int cinx) {
ARecord row = data.get(rinx);
switch (cinx) {
case 0:
row.setFilename((String) value);
break;
case 1:
row.setCbox((JComboBox) value);
break;
}
}
#Override
public Object getValueAt(int rinx, int cinx) {
Object returnValue = null;
ARecord row = data.get(rinx);
switch (cinx) {
case 0:
returnValue = row.getFilename();
break;
case 1:
returnValue = row.getCbox();
break;
}
return returnValue;
}
// I assume this is unnecessary since column 1 defaults to text
// and column 2 is handled by ACellRenderer. I think.
// #Override
// public Class getColumnClass(int cinx) {
// return cinx == 0 ? String.class : JComboBox.class;
// }
}
//////////////////////////////////////////////////////////////////////////////////
// This class handles the drag and drop.
class ATransferHandler extends TransferHandler {
int getSourceActions(JList<String> lst) {
return TransferHandler.COPY;
}
Transferable createTransferable(JList<String> list) {
return null;
}
void exportDone(JList<String> lst, Transferable data, int action) {
}
public boolean canImport(TransferHandler.TransferSupport info) {
return true;
}
//////////////////////////////////////////////////////////////////////////
// This is the method of interest where the dropped text file is handled.
//////////////////////////////////////////////////////////////////////////
public boolean importData(TransferHandler.TransferSupport info) {
if (! info.isDrop()) return false;
JTable table = (JTable)info.getComponent();
Transferable tr = info.getTransferable();
List<File> files = null;
try {
files = (List<File>)tr.getTransferData(DataFlavor.javaFileListFlavor);
} catch(UnsupportedFlavorException | IOException e) {
}
ATableModel tm = (ATableModel)table.getModel();
String[] options;
// For each dropped text file...
for (File fl : files) {
String fname = fl.getName();
// Just fill the JComboBox with some unique options for now
// (in practice this comes from the dropped text file contents).
String dummyText = fname.substring(0, 5);
options = new String[] { dummyText + "_A", dummyText + "_B", dummyText + "_C" };
// Create a ComboBoxModel for this JComboBox containing the selection options.
AComboBoxModel cboModel = new AComboBoxModel(options);
// Create the combo box itself.
JComboBox<String> cbox = new JComboBox<String>();
// Assign the model to the box.
cbox.setModel(cboModel);
// Create and add to the editor list the table cell editor.
Main.editors.add(new DefaultCellEditor(cbox));
// Also add the ComboBoxModel to the model list.
Main.addComboModel(cboModel);
// Add the row to the model data.
tm.addRow(new ARecord(fname, cbox));
}
return true;
}
}
///////////////////////////////////////////////////////////////////////////////////////////
class ARecord {
String filename;
JComboBox cbox;
// Just a bean to describe a table row (a filename and a JComboBox).
public ARecord(String filename, JComboBox cbox) {
super();
this.filename = filename;
this.cbox = cbox;
}
public String getFilename() {
return filename;
}
public void setFilename(String filename) {
this.filename = filename;
}
public JComboBox getCbox() {
return cbox;
}
public void setCbox(JComboBox cbox) {
this.cbox = cbox;
}
}
///////////////////////////////////////////////////////////////////////////////////////////
// This is the model for the JComboBoxes. A different model is instantiated
// for each row since each one has different contents.
class AComboBoxModel implements MutableComboBoxModel {
List<String> items = new ArrayList<String>();
public AComboBoxModel(String[] items) {
this.items = Arrays.asList(items);
}
#Override
public int getSize() {
return items.size();
}
#Override
public Object getElementAt(int index) {
return items.get(index);
}
#Override
public void addListDataListener(ListDataListener l) {
}
#Override
public void removeListDataListener(ListDataListener l) {
}
#Override
public void setSelectedItem(Object anItem) {
}
#Override
public Object getSelectedItem() {
return null;
}
#Override
public void addElement(Object item) {
}
#Override
public void removeElement(Object obj) {
}
#Override
public void insertElementAt(Object item, int index) {
}
#Override
public void removeElementAt(int index) {
}
}
//////////////////////////////////////////////////////////////////////////////////////
// I won't pretend that I'm confident as to how this should work. My guess is that
// I should just retrieve the appropriate ComboBoxModel, assign it and return.
class ACellRenderer extends JComboBox implements TableCellRenderer {
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
int rinx, int cinx) {
setModel(Main.getComboModelAt(rinx));
return this;
}
}
/////////////////////////////////////////////////////////////////////////////////////////
class ACellEditor extends AbstractCellEditor implements TableCellEditor {
static JComboBox box = null;
// This is where I think I'm actually lost. I don't understand the significance of
// returning a JComboBox when one was already created when the text file was
// dropped. Is it correct to just assign the appropriate ComboBoxModel to a JComboBox
// and return it here?
public Component getTableCellEditorComponent(JTable table,
Object value,
boolean isSelected,
int rinx,
int cinx) {
box = (JComboBox)(table.getModel().getValueAt(rinx, cinx));
box.setModel(Main.getComboModelAt(rinx));
return box;
}
#Override
public Object getCellEditorValue() {
return box;
}
}
make a selection from the JComboBox in the right column and watch it ignore you
Something is wrong with your custom editor and I'm not sure what. You have a big problem in that you are trying to use a JComboBox as the data of the editor. This is completely wrong.
But the good new is that there is no need for you to use a custom renderer or a custom editor.
You should NOT be storing a JComboBox in the TableModel. You simply store the String of the selected item from the combo box. (This will be done for you automatically by the default combo box editor).
There is no need for you to create a new editor for every file that is dragged to the table.
the second contain a JComboBox whose options depend on the contents of the dragged file
So the only part of the table that you need to customize is the getCellEditor(...) method.
I would guess you would have a different editor for a given file extension.
So the basic code might be something like:
int modelColumn = convertColumnIndexToModel( column );
if (modelColumn == 1)
{
String file = getModel.getValueAt(row, 0);
if (file.endsWith(".txt"))
return txtEditor;
else if (file.endsWith(".html"))
return htmlEditor;
}
return super.getCellEditor(row, column);
Check out:
How to add unique JComboBoxes to a column in a JTable (Java) for a working example. The logic in that posting does have a separate editor by row for demonstration purposes only. The example demonstrates that the code works with the default renderers and editors. All you need to do is provide the items for each combo box editor.
In your case the editor will be based on the file type so the logic needs to test the data in the first column.
Note: the nested if/else statement is not a good solution. You might want to use a Hashmap of filetype/editor. Then the getCellEditor(...) method would just be a Hashmap lookup once you extract the filetype for the File.
So your dragging code should have nothing to do with the editors of the table. You need to know before hand which file types you want to support and define the valid items for each of those file types.
Also, your TableModel should NOT extend DefaultTableModel. You are providing your own data storage and implementing all the methods so you should just be extending the AbstractTableModel.
In the following code, I create a jtable with a custom cell editor for the first column and then add undo capabilities to the table. When you run the program, the program allows you to change the values in the first column (test by appending a "d" and then an "e" to the "abc" already there). Now enter control-z (undo) and enter control-z again. It works as expected. But now enter control-z (undo) again. This time the "abc" is erased. It looks like the swing system is setting the initial value of the column and creating an undo event for that action which the user can then undo. My question - how do I write my code so that the user only can undo the actions the user makes?
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.DefaultCellEditor;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JRootPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.undo.AbstractUndoableEdit;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;
import javax.swing.undo.UndoableEdit;
public class UndoExample extends JFrame {
private static final long serialVersionUID = 1L;;
static Boolean objEnableUndoRedoActions = true;
UndoExample rootFrame;
public UndoExample() {
// This procedure starts the whole thing off.
//Create table
final String[] tableColumns = {"Column 1", "Column 2"};
JTable tabUndoExample = new JTable(
new DefaultTableModel(null, tableColumns) {
private static final long serialVersionUID = 1L;
});
final DefaultTableModel tabUndoExampleModel = (DefaultTableModel) tabUndoExample
.getModel();
tabUndoExampleModel.addRow(new Object[]{"abc", true});
tabUndoExampleModel.addRow(new Object[]{"zyw", false});
// Create the undo/redo manager
UndoManager objUndoManager = new UndoManager();
// Create a cell editor
JTextField tfTabField = new JTextField();
TableCellEditor objEditor = new DefaultCellEditor(tfTabField);
// Make the cell editor the default editor for this table's first column
tabUndoExample.getColumnModel().getColumn(0)
.setCellEditor(objEditor);
// Create the undo action on the field's document for the column
tfTabField.getDocument().addUndoableEditListener(
new uelUndoRedoTableCellField(objUndoManager, tabUndoExample));
// Allow undo and redo to be entered by the user
UndoRedoSetKeys(this, "Example", objUndoManager);
tabUndoExample.setInheritsPopupMenu(true);
//Add the table to the frame and show the frame
this.add(tabUndoExample);
this.pack();
setLocationRelativeTo(null);
}
public static void main(final String[] args) {
// Launches the application. This is required syntax.
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
final UndoExample rootFrame = new UndoExample();
rootFrame.setVisible(true);
} catch (final Exception e) {
}
}
});
}
#SuppressWarnings("serial")
static class aueUndoRedoTableCellField extends AbstractUndoableEdit {
// Wrap the text edit action item as we need to add the table
// row and column information. This code is invoked when the
// code sees an undo event created and then later when the
// user requests an undo/redo.
JTable objTable = null;
UndoableEdit objUndoableEdit;
int objCol = -1;
int objRow = -1;
public aueUndoRedoTableCellField(UndoableEdit undoableEdit,
JTable table, int row, int col) {
super();
objUndoableEdit = undoableEdit;
objTable = table;
objCol = col;
objRow = row;
}
public void redo() throws CannotRedoException {
// When the user enters redo (or undo), this code sets
// that we are doing an redo (or undo), sets the cursor
// to the right location, and then does the undo (or redo)
// to the table cell.
UndoRedoManagerSetEnabled(false);
super.redo();
#SuppressWarnings("unused")
boolean success = objTable.editCellAt(objRow, objCol);
objTable.changeSelection(objRow, objCol, false, false);
objUndoableEdit.redo();
UndoRedoManagerSetEnabled(true);
}
public void undo() throws CannotUndoException {
super.undo();
UndoRedoManagerSetEnabled(false);
#SuppressWarnings("unused")
boolean success = objTable.editCellAt(objRow, objCol);
objTable.changeSelection(objRow, objCol, false, false);
objUndoableEdit.undo();
UndoRedoManagerSetEnabled(true);
}
}
static class aUndoRedo extends AbstractAction {
// This code is bound to the undo/redo keystrokes and tells
// Java what commands to run when the keys are later entered
// by the user.
private static final long serialVersionUID = 1L;
Boolean objUndo = true;
UndoManager objUndoManager = null;
final String objLocation;
public aUndoRedo(Boolean Undo, UndoManager undoManager, String location) {
super();
objUndo = Undo;
objUndoManager = undoManager;
objLocation = location;
}
#Override
public void actionPerformed(ActionEvent ae) {
try {
// See if operation allowed
if (!objUndoManager.canUndo() && objUndo
|| !objUndoManager.canRedo() && !objUndo)
return;
UndoRedoManagerSetEnabled(false);
if (objUndo) {
objUndoManager.undo();
} else {
objUndoManager.redo();
}
UndoRedoManagerSetEnabled(true);
// Catch errors and let user know
} catch (Exception e) {
UndoRedoManagerSetEnabled(true);
}
}
}
static class uelUndoRedoTableCellField implements UndoableEditListener {
// This action is called when the user changes the table's
// text cell. It saves the change for later undo/redo.
private UndoManager objUndoManager = null;
private JTable objTable = null;
public uelUndoRedoTableCellField(UndoManager undoManager,
JTable table) {
objUndoManager = undoManager;
objTable = table;
}
#Override
public void undoableEditHappened(UndoableEditEvent e) {
// Remember the edit but only if the code isn't doing
// an undo or redo currently.
if (UndoRedoManagerIsEnabled()) {
objUndoManager.addEdit(new aueUndoRedoTableCellField(e
.getEdit(), objTable, objTable.getSelectedRow(),
objTable.getSelectedColumn()));
}
}
}
static public Boolean UndoRedoManagerIsEnabled() {
// See if we are currently doing an undo/redo.
// Return true if so.
return objEnableUndoRedoActions;
}
static public void UndoRedoManagerSetEnabled(Boolean state) {
// Set the state of whether we are in undo/redo code.
objEnableUndoRedoActions = state;
}
static void UndoRedoSetKeys(JFrame frame, final String location, UndoManager undoManager) {
// Allow undo and redo to be called via these keystrokes for this dialog
final String cntl_y = "CNTL_Y";
final KeyStroke ksCntlY = KeyStroke.getKeyStroke("control Y");
final String cntl_z = "CNTL_Z";
final KeyStroke ksCntlZ = KeyStroke.getKeyStroke("control Z");
JRootPane root = frame.getRootPane();
root.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
.put(ksCntlZ, cntl_z);
root.getActionMap().put(
cntl_z,
new aUndoRedo(true, undoManager, location));
root.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
.put(ksCntlY, cntl_y);
root.getActionMap().put(
cntl_y,
new aUndoRedo(false, undoManager, location));
}
}
When you press a key, a series of things occur. The JTable, process the key stroke, it checks to see if the cell is editable (as the TableModel), it then asks the editor for the currently selected cell if the event should edit the cell (CellEditor#isCellEditable(EventObject)).
If this method returns true, the editor is prepared, the value from the TableModel is applied to the editor (ie setText is called), and the editor is added to the JTable, finally, the event which triggered the edit mode is re-dispatched to the editor, in your case the Ctrl+Z, which then triggers and undo event, returning the editor it's initial state (before setText was called).
You can try and use something like...
TableCellEditor objEditor = new DefaultCellEditor(tfTabField) {
#Override
public boolean isCellEditable(EventObject anEvent) {
boolean isEditable = super.isCellEditable(anEvent); //To change body of generated methods, choose Tools | Templates.
if (isEditable && anEvent instanceof KeyEvent) {
KeyEvent ke = (KeyEvent) anEvent;
if (ke.isControlDown() && ke.getKeyCode() == KeyEvent.VK_Z) {
isEditable = false;
}
}
return isEditable;
}
};
to prevent the JTable from been placed into edit when a specific key stroke occurs
Updated
So based on Andrew's answer from JTextArea setText() & UndoManager, I devised a "configurable" UndoableEditListener which can be set to ignore undoable actions, for example...
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.text.Document;
import javax.swing.text.PlainDocument;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;
public class FixedField {
public static void main(String[] args) {
new FixedField();
}
public FixedField() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class UndoableEditHandler implements UndoableEditListener {
private static final int MASK
= Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
private UndoManager undoManager = new UndoManager();
private boolean canUndo = true;
public UndoableEditHandler(JTextField field) {
Document doc = field.getDocument();
doc.addUndoableEditListener(this);
field.getActionMap().put("Undo", new AbstractAction("Undo") {
#Override
public void actionPerformed(ActionEvent evt) {
try {
if (undoManager.canUndo()) {
undoManager.undo();
}
} catch (CannotUndoException e) {
System.out.println(e);
}
}
});
field.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_Z, MASK), "Undo");
field.getActionMap().put("Redo", new AbstractAction("Redo") {
#Override
public void actionPerformed(ActionEvent evt) {
try {
if (undoManager.canRedo()) {
undoManager.redo();
}
} catch (CannotRedoException e) {
System.out.println(e);
}
}
});
field.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_Y, MASK), "Redo");
}
#Override
public void undoableEditHappened(UndoableEditEvent e) {
if (canUndo()) {
undoManager.addEdit(e.getEdit());
}
}
public void setCanUndo(boolean canUndo) {
this.canUndo = canUndo;
}
public boolean canUndo() {
return canUndo;
}
}
public class TestPane extends JPanel {
public TestPane() {
JTextField field = new JTextField(10);
UndoableEditHandler handler = new UndoableEditHandler(field);
handler.setCanUndo(false);
field.setText("Help");
handler.setCanUndo(true);
add(field);
}
}
}
Now, you're going to have to devices your own TableCellEditor to support this, for example...
public static class MyCellEditor extends AbstractCellEditor implements TableCellEditor {
private JTextField editor;
private UndoableEditHandler undoableEditHandler;
public MyCellEditor(JTextField editor) {
this.editor = editor;
undoableEditHandler = new UndoableEditHandler(editor);
editor.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
fireEditingStopped();
}
});
}
#Override
public Object getCellEditorValue() {
return editor.getText();
}
#Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
undoableEditHandler.setCanUndo(false);
editor.setText(value == null ? null : value.toString());
undoableEditHandler.setCanUndo(true);
return editor;
}
}
I found this tutorial: Drag and dropping files to a Java desktop application
It correctly shows the panel and enables the drop-and-dragging but it sends out error
Can only iterate over an array or an instance of java.lang.Iterable
referring to the passage:
for (File file : files) {
// Print out the file path
System.out.println("File path is '" + file.getPath() + "'.");
}
I really don't know how to solve the problem...
Could you plese help me?
Update:
If I try doing this:
List File[] files = (File[]) transferable.getTransferData(flavor);
it keeps giving me an error...
So I tried doing this:
File[] files = (File[]) transferable.getTransferData(flavor);
and the code is no longer underlined but it keeps not working.
I also found another tutorial:
how to drag and drop files from a directory in java
It doesn't work of course -.-'
I think the closest thing I have to the solution is this complete example:
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.File;
import java.io.IOException;
import java.util.List;
import javax.swing.*;
#SuppressWarnings("serial")
public class FileDragDemo extends JPanel {
private JList list = new JList();
public FileDragDemo() {
list.setDragEnabled(true);
list.setTransferHandler(new FileListTransferHandler(list));
add(new JScrollPane(list));
}
private static void createAndShowGui() {
FileDragDemo mainPanel = new FileDragDemo();
JFrame frame = new JFrame("FileDragDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
#SuppressWarnings("serial")
class FileListTransferHandler extends TransferHandler {
private JList list;
public FileListTransferHandler(JList list) {
this.list = list;
}
public int getSourceActions(JComponent c) {
return COPY_OR_MOVE;
}
public boolean canImport(TransferSupport ts) {
return ts.isDataFlavorSupported(DataFlavor.javaFileListFlavor);
}
public boolean importData(TransferSupport ts) {
try {
#SuppressWarnings("rawtypes")
List data = (List) ts.getTransferable().getTransferData(
DataFlavor.javaFileListFlavor);
if (data.size() < 1) {
return false;
}
DefaultListModel listModel = new DefaultListModel();
for (Object item : data) {
File file = (File) item;
listModel.addElement(file);
}
list.setModel(listModel);
return true;
} catch (UnsupportedFlavorException e) {
return false;
} catch (IOException e) {
return false;
}
}
}
The only problem is that I want the panel to show all the images I upload, instead it only displays the last entry
Nice article... Just please change List files to List< File > files :) Again great article!
^First comment on that link.
also when coding be weary of some tutorials from 2011 etc. as they can often teach you the wrong way to do something. Not that i know enough about this topic to suggest anything better.
I have this code (this is all code). I want to write file path(choosing file) on JTextField. I run the program and i press button and file chooser open, i choose file but file path not write on JTextField.
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import org.dyno.visual.swing.layouts.Bilateral;
import org.dyno.visual.swing.layouts.Constraints;
import org.dyno.visual.swing.layouts.GroupLayout;
import org.dyno.visual.swing.layouts.Leading;
//VS4E -- DO NOT REMOVE THIS LINE!
public class xailabsPanel extends JFrame {
private static final long serialVersionUID = 1L;
private JButton jButton0;
public static String path;
private JTextField jTextField0;
private static final String PREFERRED_LOOK_AND_FEEL = "javax.swing.plaf.metal.MetalLookAndFeel";
public xailabsPanel() {
initComponents();
}
private void initComponents() {
setLayout(new GroupLayout());
add(getJText(), new Constraints(new Bilateral(12, 12, 4), new Leading(100, 10, 10)));
add(getJButton0(), new Constraints(new Bilateral(117, 117, 94), new Leading(57, 12, 12)));
setSize(328, 252);
}
private JButton getJButton0() {
if (jButton0 == null) {
jButton0 = new JButton();
jButton0.setText("jButton0");
jButton0.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent event) {
jButton0MouseMouseClicked(event);
}
});
}
return jButton0;
}
private JTextField getJText() {
if (jTextField0 == null) {
jTextField0 = new JTextField();
}
return jTextField0;
}
private static void installLnF() {
try {
String lnfClassname = PREFERRED_LOOK_AND_FEEL;
if (lnfClassname == null)
lnfClassname = UIManager.getCrossPlatformLookAndFeelClassName();
UIManager.setLookAndFeel(lnfClassname);
} catch (Exception e) {
System.err.println("Cannot install " + PREFERRED_LOOK_AND_FEEL
+ " on this platform:" + e.getMessage());
}
}
/**
* Main entry of the class.
* Note: This class is only created so that you can easily preview the result at runtime.
* It is not expected to be managed by the designer.
* You can modify it as you like.
*/
private void jButton0MouseMouseClicked(MouseEvent event) {
JFileChooser fileChooser = new JFileChooser();
fileChooser.showOpenDialog(null);
fileChooser.setCurrentDirectory(new File(System.getProperty("home/kerim")));
int result = fileChooser.showOpenDialog(null);
if (result == JFileChooser.APPROVE_OPTION) {
// user selects a file
File selectedFile = fileChooser.getSelectedFile();
path = selectedFile.getAbsolutePath().toString();
jTextField0.setText(path);
}
}
public static void main(String[] args) {
installLnF();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
xailabsPanel frame = new xailabsPanel();
frame.setDefaultCloseOperation(xailabsPanel.EXIT_ON_CLOSE);
frame.setTitle("xailabsPanel");
frame.getContentPane().setPreferredSize(frame.getSize());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
You are creating a new JTextField inside the method (and you are modfying its contents), but it's not added anywhere.
Drop jTextField0 = new JTextField() and it should work (assuming you already created the text field beforehand).
The code works fine, when I do the following
Change layout manager default BorderLayout (why? Because I don't have GroupLayout, it's not a standard Layout Manager - so I don't know if it's a direct cause)
Add the componenst to corresponding BorderLayout positions.
Changed setSize() to pack(). This is the preferred way.
create the text field the the constructor (new JTextField(int columns)). For some weird reason I feel like this is the culprit (as without this, the text field has no preferred size, and maybe you just weren't seeing it. Not 100% sure, hell probably not even 50% sure, as I couldn't test the GroupLayout
Got rid of frame.getContentPane().setPreferredSize(frame.getSize());, another suspected culprit (not really necessary to delete, but not preferred to keep).
Got rid of this unnecessary line, as it's redundant fileChooser.showOpenDialog(null); and causing the file chooser to open twice.
Here's the result
import java.awt.BorderLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
//VS4E -- DO NOT REMOVE THIS LINE!
public class xailabsPanel extends JFrame {
private static final long serialVersionUID = 1L;
private JButton jButton0;
public static String path;
private JTextField jTextField0;
private static final String PREFERRED_LOOK_AND_FEEL = "javax.swing.plaf.metal.MetalLookAndFeel";
public xailabsPanel() {
initComponents();
}
private void initComponents() {
//setLayout(new GroupLayout());
add(getJText(), BorderLayout.WEST);
add(getJButton0(), BorderLayout.EAST);
//setSize(328, 252);
pack();
}
private JButton getJButton0() {
if (jButton0 == null) {
jButton0 = new JButton();
jButton0.setText("jButton0");
jButton0.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent event) {
jButton0MouseMouseClicked(event);
}
});
}
return jButton0;
}
private JTextField getJText() {
if (jTextField0 == null) {
jTextField0 = new JTextField(20);
}
return jTextField0;
}
private static void installLnF() {
try {
String lnfClassname = PREFERRED_LOOK_AND_FEEL;
if (lnfClassname == null)
lnfClassname = UIManager.getCrossPlatformLookAndFeelClassName();
UIManager.setLookAndFeel(lnfClassname);
} catch (Exception e) {
System.err.println("Cannot install " + PREFERRED_LOOK_AND_FEEL
+ " on this platform:" + e.getMessage());
}
}
/**
* Main entry of the class. Note: This class is only created so that you can
* easily preview the result at runtime. It is not expected to be managed by
* the designer. You can modify it as you like.
*/
private void jButton0MouseMouseClicked(MouseEvent event) {
JFileChooser fileChooser = new JFileChooser();
//fileChooser.showOpenDialog(null);
//fileChooser.setCurrentDirectory(new File(System
//.getProperty("home/kerim")));
int result = fileChooser.showOpenDialog(null);
if (result == JFileChooser.APPROVE_OPTION) {
// user selects a file
File selectedFile = fileChooser.getSelectedFile();
path = selectedFile.getAbsolutePath().toString();
System.out.println(path);
jTextField0.setText(path);
}
}
public static void main(String[] args) {
installLnF();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
xailabsPanel frame = new xailabsPanel();
frame.setDefaultCloseOperation(xailabsPanel.EXIT_ON_CLOSE);
frame.setTitle("xailabsPanel");
//frame.getContentPane().setPreferredSize(frame.getSize());
((JPanel) frame.getContentPane()).setBorder(BorderFactory
.createEmptyBorder(20, 20, 20, 20));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
You never added JTextField to your JFrame (or whatever window you want the text field to be).
Right after your JTextFIeld0 = new JTextField(); add: myWindow.add(jTextField0)
also, you are displaying two open dialogs. i dont think it is your desired behavior, remove the file fileChooser.showOpenDialog(null);
Here is a quick example of what you are trying to accomplish:
public static void main(String[] args)
{
// you should not need this, use the frame you already have, where the button is.
JFrame window = new JFrame();
// This is what you are doing in your code, however, you should add a text field
// whereever you create and populate your jframe, and add the button etc, and simply
// set the jtextfield value here
JTextField tf = new JTextField();
// again in your case you should have this somewhere else, i assume if you are
// displaying a button, you must have a JFrame somewhere
window.setSize(100, 100);
window.add(tf);
window.setLocationRelativeTo(null);
/***** you DO NEED this code **************/
// create file chooser and open the dialog.
JFileChooser fc = new JFileChooser();
fc.showOpenDialog(null);
// get selected file object
File f = fc.getSelectedFile();
// disply file path in the text field
tf.setText(f.getAbsolutePath());
/****** end of the code you need *********/
// display a JFrame with the text field (dont need this obviously you
// already are displaying the frame)
window.setVisible(true);
}
I have an application that I run on a pc with a mouse, I want to launch edrawingsviewer with a particular file name from java and then when the user returns to the fullscreen app, if they haven't closed it I want to close it. This is what I've got so far for a quick demo but I cannot figure out what to put in the arguments in order to launch solidworks with a particular file.
package com.protocase.hmiclient.edrawings;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import javax.swing.JButton;
import javax.swing.JFrame;
/**
* #author DavidH
*/
public class EDrawingHelper {
public static File[] getEDrawingsForJob(final String jobNumber) {
File f = new File("\\\\itsugar\\www\\HMI\\POD EDRAWINGS");
File[] matchingFiles = f.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.startsWith(jobNumber) && (name.endsWith("EASM") || name.endsWith("EDRW"));
}
});
return matchingFiles;
}
public static void test(String[] args) {
File[] files = getEDrawingsForJob("G080111004-13162-1");
for (File file : files){
System.out.println(file.getName());
}
}
public static void openEDrawingForFileName(String fileName){
try {
final Process process = Runtime.getRuntime().exec("C:\\Program Files\\SolidWorks Corp\\SolidWorks eDrawings (2)\\EModelViewer.exe \\\\itsugar\\www\\HMI\\POD EDRAWINGS\\"+fileName);
JFrame frame = new JFrame();
JButton killButton = new JButton("KILL");
killButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
process.destroy();
System.exit(0);
}
});
frame.getContentPane().add(killButton);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
openEDrawingForFileName("G080111004-13162-1 ASSEMBLY.EASM");
}
}
I don't think this is a solidworks problem, I think this is just something I'm passing wrong or formatting wrong or something.
It appears as if running it through the FileProtocolHandler causes it to open fine.
final Process process = Runtime.getRuntime().exec("rundll32 url.dll,FileProtocolHandler \\\\itsugar\\www\\HMI\\POD EDRAWINGS\\"+fileName);