I am trying to code a small text editor and I was building the GUI.
I added a JMenu and added a JMenuItem to it. I gave the menu item the value of "open".
The reason is because I want that when "open" is pressed a JFileChooser appears on the screen
Here is what I have:
public void mousePressed(MouseEvent me) {
JFileChooser fs = new JFileChooser();
}
This method is in a class called listener which implements MouseListener. This is the step that I'm stuck at.
getContentPane()
..does not work:
Is it good code practice the way I'm approaching this? Is there a better way? If not how do I go around doing this?
While in general your approach could work, you might want to look into the Swing concept of Actions. JMenuItem has direct support for actions, you would not need a MouseListener (which is a bit to low-level for your usecase).
Try to look at the examples, it might look a little overwhelming at first, but in the end it is a nice and clean encapsulation of what you want. And it is reusable, meaning you could use the action on a different menu (maybe the context menu) as well.
And for your code, you are missing the call to fs.showOpenDialog(component).
Firstly, don't use a MouseListener for JMenuItem or JButton, this is not the appropriate means for managing these components, instead, use an ActionListener.
The main reason for this is that your menu item could be triggered via a keyboard shortcut or programmatically.
Secondly "does not work" is not information about what you problem is, but I assume it's because the method does not exist.
A simply solution would be to check the source the event to determine if it's a Component or not and use it instead, or null if the source of the event is not a Component...
public void actionPerformed(ActionEvent evt) {
Object source = evt.getSource();
Component parent = null;
if (source instanceof Component) {
parent = (Component)source;
}
// Show file chooser dialog...
}
Take a look at How to use menus for more details
You may also find How to use actions of some interest
Have a look at the Javadoc on the JFileChooser class. It has an example of how to open it.
The following code pops up a file chooser for the user's home directory that sees only .jpg and .gif images:
JFileChooser chooser = new JFileChooser();
FileNameExtensionFilter filter = new FileNameExtensionFilter(
"JPG & GIF Images", "jpg", "gif");
chooser.setFileFilter(filter);
int returnVal = chooser.showOpenDialog(parent);
if(returnVal == JFileChooser.APPROVE_OPTION) {
System.out.println("You chose to open this file: " +
chooser.getSelectedFile().getName());
}
Related
Problem statement
A directory chooser dialog is prepared. No files are allowed to be chosen, only directories. In order to do so, the JFileChooser is prepared:
private void prepareFileManagement()
{
// unrelated code
...
// export filters
this.exportFileChooser.setFileSelectionMode( JFileChooser.DIRECTORIES_ONLY );
this.exportFileChooser.setAcceptAllFileFilterUsed( false );
}
Dialog filters work as intended so far. However when displaying the dialog, there is still a "Files of type" label and the corresponding combobox shown:
Question
It does not seem to make sense to display the filetype section, when JFileChooser.DIRECTORIES_ONLY is set. Is there an API available to the JFileChooser to update the displayed dialog accordingly?
While I have found solutions, where components are iterated and identified using a barrage of instanceof, this seems like something that should be done by an API and not by tearing the Component apart.
Is there an API for the JFileChooser I have missed? How to solve this correctly?
Meta
I have looked for similiar questions on StackOverflow, the closest one in my opinion is this:
Java - Remove component (Files of Type) from JFileChooser
I have been trying to follow these set of Java tutorials from this website
http://www.homeandlearn.co.uk/java/java.html
However the tutorials are in Netbeans and I am using Eclipse.
Till now there has been no difficulties until now.
http://www.homeandlearn.co.uk/java/opening_files.html
In the given tutorial using JFileChooser to open files through a JMenuItem called 'Open' is shown. However when i use the code given in the website the following error occurs
The method showOpenDialog(Component) in the type JFileChooser is not applicable for the arguments (new ActionListener(){})
This is the code for which the error is occuring.
JMenuItem mntmNewMenuItem = new JMenuItem("Open");
mntmNewMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
int returnVal = db.showOpenDialog(this);
}
});
So, my question is, what should i change in the above code stub to be able to use the file chooser?
If you want to view the entire code, i will put it in on your request.
Meaning of the error: the method showOpenDialog requires a parameter of type Component but is being called with an ActionListener. More exactly, the given parameter is of an anonymous class implementing ActionListener and not a Component:
new ActionListener() { ... }
inside the methods declared where I used . . . the keyword this points to the instance of that anonymous class.
See the documentation of showOpenDialog(), it requires a parent or null:
Pops up an "Open File" file chooser dialog. Note that the text that
appears in the approve button is determined by the L&F.
Parameters:
parent - the parent component of the dialog, can be null; see showDialog for details
And the relevant documentation of showDialog():
The parent argument determines two things: the frame on which the open
dialog depends and the component whose position the look and feel should
consider when placing the dialog.
...
If the parent is null, then the dialog depends on no visible window, and
it's placed in a look-and-feel-dependent position such as the center of
the screen.
Usually the passed parameter is the JFrame or JPanel that should visually contain the dialog, but it can be null:
int returnVal = db.showOpenDialog(null);
i tried to build a FileChooser with java and RMI to browse the file system of a remote machine.
What I did until now is best shown in the following diagram. The exists() method-call is an example and all methods of RemoteFileView, RemoteFileSystemView and RemoteFile forward to the server.
In words:
I build a RemoteFileView (extends FileView), RemoteFileSystemView (extends FileSystemView) and a RemoteFile (extends File) and overrode all methods of the super-classes except File.hashCode() and FileSystemView.createFileSystemRoot(File) (this method is protected in FileSystemView). All overridden methods call methods on the RMI-Server where the FileView- and FileSystemView from the server call the server-methods (like the JFileChooser would do). I get the FileView and the FileSystemView on the server side from a dummy instantiated JFileChooser.
So now what the system does:
- Start RMI-Server
- Start RMI-Client
- JFileChooser gets the RemoteFileView
- JFileChooser gets the RemoteFileSystemView
- JFileChooser gets all the RemoteFiles from the server and shows folders as well as files in the JFileChooser
So the behavior is good until now. And now the problem (where I can’t get rid of):
The initial view of the JFileChooser (client) shows all Files of the home directory of the server. I can (per button click) switch to the parent directory until the system root (on windows for example the system drive „C:\“ ). From there (or from everywhere else) I can double-click on a folder to jump into it as long as this path exists on the client-system but the shown files and folders are from the server. If the path doesn’t exist on the client I can’t jump into it and browse this folder. So if anyone knows this behavior please help (I appreciate any solution :) ).
So I decided to code an own mouse listener that recognize double-clicks on the JFileChooser. But if I double-click on a folder (in the JFileChooser) nothing happens. If I highlight a folder (via click) and then double-click somewhere in the JFileChooser (not in the File-View or a button) the listener recognize my double-click and jumps into the highlighted folder (hope this is clear enough).
I think the FileView (on the JFileChooser) lies over the JFileChooser and should get it’s own listeners. Or I forgot something to code out.
The RMI-interface holds all methods which are called from the RemoteFileView, RemoteFileSystemView and the RemoteFile and from the behavior of the system this should be ok.
I can of course poste some codes as well as more informations about the whole program. Posting all codes would be too much I guess.
EDIT:
As this question may be "too broad" the more concrete version (which may solve my problem): Which listener fires on double click a folder in the JFileChooser? Can this listener be removed or set?
EDIT2:
I saw in this question: Repurposing JFileChooser that the JFileChooser fires on JFileChooser.APPROVE_SELECTION whenever a file is choosen by double click. So I implemented this code:
fileChooser.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Some action");
String command = e.getActionCommand();
if (command.equals(JFileChooser.APPROVE_SELECTION)) {
File file = fileChooser.getSelectedFile();
fileChooser.setCurrentDirectory(file);
fileChooser.rescanCurrentDirectory();
}
}
});
But unfortunately the action listener doesn't recognize any action inside the FileView (the component which shows the files) but does fire action events on button clicks (which I detected with the System.out..).
The problem as I described above are the components and their mouse listeners. So first you have to get your components and then add the listeners to it. So in a JFileChooser we got a JList and a JTable. Both views can be switched by button klick. The JList holds the files as well as the JTable.
I found kind of solution here: https://community.oracle.com/thread/1350166?start=0&tstart=0
So I used some codes from there and implemented my mouse listeners:
The Listener for the JList:
JList<?> list = SwingUtils.getDescendantOfType(JList.class, fileChooser, "Enabled", true);
MouseListener listener = new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
File file = fileChooser.getSelectedFile();
if (e.getClickCount() == 2 && file != null) {
if (e.getSource() == list) {
// Do your stuff
operateOnFile(file);
}
else {
// Default operation
}
}
}
};
list.addMouseListener(listener);
And the listener for the JTable:
final Container filePane = SwingUtilities.getAncestorOfClass(sun.swing.FilePane.class, list);
filePane.addContainerListener(new ContainerAdapter() {
#Override
public void componentAdded(ContainerEvent e) {
JTable table = SwingUtils.getDescendantOfType(JTable.class, fileChooser, "Enabled", true);
if (table != null) {
for (MouseListener l : table.getMouseListeners()) {
if (l == listener) {
return;
}
}
table.addMouseListener(listener);
}
}
});
With this solution I got the behavior I wanted.
I have a Java application that contains a lot of features, and to make life easier for the user, I have set up numerous mnemonics and accelerators. For instance, I have a JMenuItem that allows the user to save the state of the application, witht he following code:
JMenuItem saveItem = new JMenuItem("Save");
saveItem.setMnemonic('S');
saveItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_MASK));
This works as desired, but now I would like to give the user an option to change the hot keys. While CTRL + s would seem like a fairly obvious hot key to stick with, there are many features that use these short cuts, and simply picked Save as an example.
I have a JButton that I have arranged for testing purposes that allows the user to enter in a new shortcut when clicked. I was thinking that I would simply try and capture the keys that the user holds down (InputEvent) and presses (KeyEvent). I also though it might be smart to force the use of an InputMask to avoid complications in Text Fields and the like.
What I am wondering is: What is the best way to capture the new input that the user enters? I have looked up information regarding KeyBindings and they look right for the job, but the main issue I see is actually capturing the keys and saving them.
Sounds like you need to setup a KeyListener. When the user presses/releases a key, it triggers a KeyEvent from which you can retrieve the main key pressed (e.g. S) and the mask/modifiers (e.g. CTRL+SHIFT).
From there you can create a KeyStroke object and set this as the new accelerator of your menu.
public void keyReleased(KeyEvent e){
KeyStroke ks = KeyStroke.getKeyStroke(e.getKeyCode(), e.getModifiers());
menuItem.setAccelerator(ks);
}
The thing is you probably want this key listener to be removed right after the key released event, to avoid multiple keystrokes to be captured. So you could have this kind of logic:
JButton captureKeyButton = new JButton("Capture key");
JLabel captureText = new JLabel("");
KeyListener keyListener = new KeyAdapter(){
public void keyReleased(KeyEvent e){
KeyStroke ks = KeyStroke.getKeyStroke(e.getKeyCode(), e.getModifiers());
menuItem.setAccelerator(ks);
captureText.setText("Key captured: "+ks.toString());
captureKeyButton.removeKeyListener(this);
}
};
ActionListener buttonClicked = new ActionListener(){
public void actionPerformed(ActionEvent e){
captureKeyButton.addKeyListener(keyListener);
captureText.setText("Please type a menu shortcut");
}
};
captureKeyButton.addActionListener(buttonClicked);
I'm writing a simple Swing app. I tried adding a checkbox as listed below. Once I added the actionHandler loadPickers the name Foo disappeared from where it was sitting next to the right of chckbxNewCheckBox. I tried adding a call to setHideActionText(), but now nothing displays.
JCheckBox chckbxNewCheckBox = new JCheckBox("Foo");
chckbxNewCheckBox.setToolTipText("");
chckbxNewCheckBox.setName("");
chckbxNewCheckBox.setHideActionText(true);
chckbxNewCheckBox.setAction(loadPickers);
mainPanel.add(chckbxNewCheckBox, "flowy,cell 0 1");
If I change it to this it works properly. I see the text "Foo".
JCheckBox chckbxNewCheckBox = new JCheckBox("Foo");
chckbxNewCheckBox.setToolTipText("");
chckbxNewCheckBox.setName("");
chckbxNewCheckBox.setHideActionText(true);
chckbxNewCheckBox.setAction(loadPickers);
chckbxNewCheckBox.setText("Foo"); //THIS DOES NOT WORK IF IT COMES BEFORE SET ACTION
mainPanel.add(chckbxNewCheckBox, "flowy,cell 0 1");
I've included the action here for completeness. Why does it work this way? Am I missing something here? Currently I'm using the WindowBuilder plugin for Eclipse with the Mig layout system (which I really like). Unfortunately I haven't figure out if there's a way to make WindowBuilder use the .setText() method instead of using the constructor. Any help on what I'm doing wrong, any insight on why this behavior exists like this, or a good workaround for WindowBuilder would be great.
private class LoadPickers extends AbstractAction {
public LoadPickers() {
//putValue(NAME, "SwingAction_2");
putValue(SHORT_DESCRIPTION, "Some short description");
}
public void actionPerformed(ActionEvent e) {
}
}
As explained in the JavaDoc of AbstractButton.setAction:
Setting the Action results in immediately changing all the properties described in Swing Components Supporting Action. Subsequently, the button's properties are automatically updated as the Action's properties change.
So all the following properties can be impacted by setting an action:
enabled
toolTipText
actionCommand
mnemonic
text
displayedMnemonicIndex
icon (NA for JCheckBox)
accelerator (NA for JCheckBox)
selected