Using a Jfilechooser with Swing Gui Classes and Listeners

Using a JFileChooser with Swing GUI classes and listeners

As a general rule, you should not have your GUI classes, such as the class extending JPanel, implement any listener interfaces, and in fact you should strive for just the opposite -- to separate the control functions of the program (the listeners and the like) from the view functions of the program (the GUI). So my answer to your question of "how can I attach the JFileChooser to the actionPerformed method... [to my DrawingPanel class which extends JPanel], is to strive to not do this.

Instead have your view classes implement interfaces that would allow the control classes to more easily interact with them.

Edit 1: your new code you never display the JFileChooser dialog. You need to display the open dialog:

// first make sure that you've declared the JFrame frame as final
int result = theFileChooser.showOpenDialog(frame);
if (result == JFileChooser.APPROVE_OPTION) {
// ... code goes here
}

Edit 2

Swing Model-View-Control Example:

For example, here's an MVC or Model-View-Control implementation that shows the view, the model and the control. This is all very simplistic, and all it does at present is to open a text file and display it in a JTextField, that's it, and it tries to seperate out the control functions from the view.

MvcMain class

import javax.swing.SwingUtilities;

public class MvcMain {

private static void createAndShowGui() {
MvcView view = new ShowTextView("Show Text");
MvcModel model = new ShowTextModel();
ShowTextControl control = new ShowTextControl(view, model);

control.showView(true);
}

public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

MvcModel interface

import java.beans.PropertyChangeListener;

public interface MvcModel {
static final String TEXT = "text";
static final String STATUS = "STATUS";

String getText();

String getStatus();

void setText(String text);

void setStatus(String text);

void addPropertyChangeListener(PropertyChangeListener listener);

void removePropertyChangeListener(PropertyChangeListener listener);
}

MvcView interface

import java.awt.Window;
import javax.swing.Action;

public interface MvcView {

void setVisible(boolean visible);

void setFileAction(Action fileAction);

void setOpenFileAction(Action openFileAction);

void setSaveToFileAction(Action saveToFileAction);

void setExitAction(Action exitAction);

void setStatusText(String string);

String getTextAreaText();

void setTextAreaText(String text);

Window getTopWindow();

}

ShowTextView class

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.Window;
import javax.swing.*;

public class ShowTextView implements MvcView {
private JFrame frame = new JFrame();
private JMenuBar menuBar = new JMenuBar();
private JMenu fileMenu = new JMenu();
private StatusBar statusBar = new StatusBar();
private ViewDisplayText displayText = new ViewDisplayText();

public ShowTextView(String title) {
menuBar.add(fileMenu);

frame.setTitle(title);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(displayText.getMainComponent(), BorderLayout.CENTER);
frame.getContentPane().add(statusBar.getComponent(), BorderLayout.PAGE_END);
frame.setJMenuBar(menuBar);
}

@Override
public void setVisible(boolean visible) {
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}

@Override
public void setOpenFileAction(Action action) {
displayText.setOpenFileButtonAction(action);
fileMenu.add(new JMenuItem(action));
}

@Override
public void setSaveToFileAction(Action action) {
displayText.setSaveToFileAction(action);
fileMenu.add(new JMenuItem(action));
}

@Override
public void setExitAction(Action exitAction) {
displayText.setExitAction(exitAction);
fileMenu.add(new JMenuItem(exitAction));
}

@Override
public void setFileAction(Action fileAction) {
fileMenu.setAction(fileAction);
}

@Override
public String getTextAreaText() {
return displayText.getTextAreaText();
}

@Override
public void setTextAreaText(String text) {
displayText.setTextAreaText(text);
}

@Override
public Window getTopWindow() {
return frame;
}

@Override
public void setStatusText(String text) {
statusBar.setText(text);
}

}

class ViewDisplayText {
private static final int TA_ROWS = 30;
private static final int TA_COLS = 50;
private static final int GAP = 2;
private JPanel mainPanel = new JPanel();
private JButton openFileButton = new JButton();
private JButton saveToFileButton = new JButton();
private JButton exitButton = new JButton();
private JTextArea textArea = new JTextArea(TA_ROWS, TA_COLS);

public ViewDisplayText() {
JPanel buttonPanel = new JPanel(new GridLayout(1, 0, GAP, 0));
buttonPanel.add(openFileButton);
buttonPanel.add(saveToFileButton);
buttonPanel.add(exitButton);

mainPanel.setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
mainPanel.setLayout(new BorderLayout());
mainPanel.add(new JScrollPane(textArea), BorderLayout.CENTER);
mainPanel.add(buttonPanel, BorderLayout.PAGE_END);
}

public void setExitAction(Action exitAction) {
exitButton.setAction(exitAction);
}

public JComponent getMainComponent() {
return mainPanel;
}

public void setOpenFileButtonAction(Action action) {
openFileButton.setAction(action);
}

public void setSaveToFileAction(Action action) {
saveToFileButton.setAction(action);
}

public String getTextAreaText() {
return textArea.getText();
}

public void setTextAreaText(String text) {
textArea.setText(text);
}
}

class StatusBar {
private static final String STATUS = "Status: ";
private JLabel label = new JLabel(STATUS);

public StatusBar() {
label.setBorder(BorderFactory.createLineBorder(Color.black));
}

public JComponent getComponent() {
return label;
}

public void setText(String text) {
label.setText(STATUS + text);
}
}

ShowTextModel class

import java.beans.PropertyChangeListener;
import javax.swing.event.SwingPropertyChangeSupport;

public class ShowTextModel implements MvcModel {
private String text;
private String status;
private SwingPropertyChangeSupport propChangeSupport =
new SwingPropertyChangeSupport(this);

@Override
public String getText() {
return text;
}

@Override
public void setText(String text) {
String newValue = text;
String oldValue = this.text;
this.text = newValue;
propChangeSupport.firePropertyChange(TEXT, oldValue, newValue);
}

@Override
public void setStatus(String status) {
String newValue = status;
String oldValue = this.status;
this.status = newValue;
propChangeSupport.firePropertyChange(STATUS, oldValue, newValue);
}

@Override
public void addPropertyChangeListener(PropertyChangeListener listener) {
propChangeSupport.addPropertyChangeListener(listener);
}

@Override
public void removePropertyChangeListener(PropertyChangeListener listener) {
propChangeSupport.removePropertyChangeListener(listener);
}

@Override
public String getStatus() {
return status;
}

}

ShowTextControl class

import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
import java.util.concurrent.ExecutionException;
import javax.swing.*;

public class ShowTextControl {

private MvcView view;
private MvcModel model;

public ShowTextControl(MvcView view, MvcModel model) {
this.view = view;
this.model = model;

view.setFileAction(new FileAction("File", KeyEvent.VK_F));
view.setOpenFileAction(new OpenFileAction(view, model, "Open File",
KeyEvent.VK_O));
view.setSaveToFileAction(new SaveToFileAction(view, model,
"Save to File", KeyEvent.VK_S));
view.setExitAction(new ExitAction(view, model, "Exit", KeyEvent.VK_X));

model.addPropertyChangeListener(new ModelListener(view, model));
}

public void showView(boolean visible) {
view.setVisible(visible);
}
}

@SuppressWarnings("serial")
class OpenFileAction extends AbstractAction {
private MvcView view;
private MvcModel model;

public OpenFileAction(MvcView view, MvcModel model, String name, int keyCode) {
super(name);
putValue(MNEMONIC_KEY, keyCode);
this.view = view;
this.model = model;
}

@Override
public void actionPerformed(ActionEvent evt) {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setMultiSelectionEnabled(false);
int result = fileChooser.showOpenDialog(view.getTopWindow());
if (result == JFileChooser.APPROVE_OPTION) {
File file = fileChooser.getSelectedFile();
if (file.exists()) {
if (file.getName().endsWith(".txt")) {
model.setStatus("Opening file \"" + file.getName() + "\"");

OpenFileWorker openFileWorker = new OpenFileWorker(file);
openFileWorker.addPropertyChangeListener(
new OpenFileWorkerListener(model));
openFileWorker.execute();
} else {
model.setStatus("File \"" + file.getName()
+ "\" is not a text file");
}
} else {
model.setStatus("File \"" + file.getName() + "\" does not exist");
}
}
}

}

class OpenFileWorker extends SwingWorker<String, Void> {
private File file;

public OpenFileWorker(File file) {
this.file = file;
}

public File getFile() {
return file;
}

@Override
protected String doInBackground() throws Exception {
StringBuilder stringBuilder = new StringBuilder();
Scanner scan = null;
try {
scan = new Scanner(file);
while (scan.hasNextLine()) {
stringBuilder.append(scan.nextLine() + "\n");
}

} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (scan != null) {
scan.close();
}
}
return stringBuilder.toString();
}
}

class OpenFileWorkerListener implements PropertyChangeListener {
private MvcModel model;

public OpenFileWorkerListener(MvcModel model) {
this.model = model;
}

@Override
public void propertyChange(PropertyChangeEvent evt) {
if (SwingWorker.StateValue.DONE == evt.getNewValue()) {
OpenFileWorker openFileWorker = (OpenFileWorker) evt.getSource();
try {
String text = openFileWorker.get();
model.setText(text);
model.setStatus("File \"" + openFileWorker.getFile().getName() + "\" opened");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}

@SuppressWarnings("serial")
class FileAction extends AbstractAction {
public FileAction(String name, int keyCode) {
super(name);
putValue(MNEMONIC_KEY, keyCode);
}

@Override
public void actionPerformed(ActionEvent arg0) {
// pretty much empty
}
}

@SuppressWarnings("serial")
class SaveToFileAction extends AbstractAction {
private MvcView view;
private MvcModel model;

public SaveToFileAction(MvcView view, MvcModel model, String name,
int keyCode) {
super(name);
putValue(MNEMONIC_KEY, keyCode);
this.view = view;
this.model = model;
}

@Override
public void actionPerformed(ActionEvent e) {
// TODO finish!
}
}

@SuppressWarnings("serial")
class ExitAction extends AbstractAction {
private MvcView view;
// private MvcModel model; // TODO: may use this later

public ExitAction(MvcView view, MvcModel model, String name, int keyCode) {
super(name);
putValue(MNEMONIC_KEY, keyCode);
this.view = view;
// this.model = model; // TODO: may use this later
}

@Override
public void actionPerformed(ActionEvent e) {
view.getTopWindow().dispose();
}
}

class ModelListener implements PropertyChangeListener {
private MvcView view;
private MvcModel model;

public ModelListener(MvcView view, MvcModel model) {
this.view = view;
this.model = model;
}

@Override
public void propertyChange(PropertyChangeEvent pcEvt) {
if (MvcModel.TEXT.equals(pcEvt.getPropertyName())) {
view.setTextAreaText(model.getText());
}

else if (MvcModel.STATUS.equals(pcEvt.getPropertyName())) {
view.setStatusText(model.getStatus());
}
}

}

In this example, I've combined java classes in one file for brevity, but in the application, they'd be in their own files but would all share the same package. Note that while this may be "over-kill" for this simple application, I've used this sort of structure with several very large Swing applications with good success. The main benefit for me comes when I need to debug or enhance a program months after creation, since this separation of concerns and information and behavior hading makes it much easier for me make changes in one part of the program without offending or upsetting another part of the program.

Also, the reason for the interfaces is so that you can create new or different GUI's that look differently, but that can respond in the same way. I've also used them frequently to help create mock classes that allow me to better test my modules in isolation.

Implement a JFileChooser in Java following the MVC pattern

Here's a bare bones version. This method came from one of my ActionListener classes that was triggered by a JMenuItem.

You would have to pass an instance of your GUI Frame and an instance of your GUI model to the class that contains this method.

protected int chooseOpenFile() {
JFileChooser fileChooser = new JFileChooser(model.getSavedInputFile());

int status = fileChooser.showOpenDialog(frame.getFrame());

if (status == JFileChooser.APPROVE_OPTION) {
File selectedFile = fileChooser.getSelectedFile();
model.setSavedInputFile(selectedFile);
}

return status;
}

What is wrong with this JFileChooser

this:

 if(event.getSource() == btnBrowse)

should be

 if(event.getSource().equals(btnBrowse))

You can't use the == to identify an equal object in java, you always have to use equals() to make sure that two objects are the same.

This:

 JButton btnBrowse = new JButton("Browse");

should be

 btnBrowse = new JButton("Browse");

You are shadowing your class member variable with a local one so the if clause always comapres against a null value. The btnBrowse is never stored in your class.

FileChooser in actionListeners

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

how to add file chooser to swing GUI form Palette components IntelliJ IDEA

File chooser is something that usually pops up based on some button click.
So, what can you do is, inside button listener make an object JFileChooser and play with that.

fc = new JFileChooser();
fc.showOpenDialog(parentPanel);

File Chooser display with a button click. Java Swing

Choose another listener

ChooseButton1.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ChooseButton1MouseClicked(e);
}
});

Using Jfilechooser edit a file copy that is still open with appending sum at the end of the line

I had a really long answer written out then my computer crashed.. let's see if we can do this again.

Any one of these concepts can be tough to understand for a beginner (GUI, files, etc). So here's a working solution from what I understood with your instructions. I tried not to change the overall structure too much from yours, so it would be more readable for you.

import java.io.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class fileSumCompute extends JFrame implements ActionListener {

private JFileChooser fc;
private JButton copyButton;
private JButton chooseFileButton;
private JButton destinationButton;
private File workingDirectory;
private JLabel sourceLabel;
private JLabel destinationLabel;
private JTextField sourceText;
private JTextField sourceFileText;
private JTextField destinationText;
private File selectedSourceFile = null;
private File selectedDestinationFolder;
private static String textToWrite;
// my first time creating and opening files without direct command line input.

public fileSumCompute() {
// peiced together a couple JfileChooser examples and customized... I cant seem
// to get it to work without the other path selection and preprograming it into
// the same directory as source file.
// It works though.
super("Compute sum of row. New file = \" *_out.txt\" ");
setLayout(new GridLayout(3, 3, 5, 5));
fc = new JFileChooser();

// Open dialog box to make easier to find files
workingDirectory = new File(System.getProperty("user.dir"));
fc.setCurrentDirectory(workingDirectory);

// create labels and buttons
chooseFileButton = new JButton("CHOOSE SOURCE FILE");
destinationButton = new JButton("DESTINATION FOLDER");
copyButton = new JButton("COMPUTE & SAVE FILE"); // copies file so origonal is preserved
sourceLabel = new JLabel("SOURCE: ");
sourceText = new JTextField(10);
sourceText.setEditable(false);
destinationLabel = new JLabel("DESTINATION: ");
destinationText = new JTextField(10);
destinationText.setEditable(false);

// JFrame tools
add(sourceLabel);
add(sourceText);
add(chooseFileButton);
add(destinationLabel);
add(destinationText);
add(destinationButton);
add(copyButton);

// Add this as action listener.
chooseFileButton.addActionListener(this);
destinationButton.addActionListener(this);
copyButton.addActionListener(this);
// computeF(name);
}

@Override
public void actionPerformed(ActionEvent arg0) {
Object event = arg0.getSource();
int returnVal;

if (event == chooseFileButton) {
returnVal = fc.showOpenDialog(null);
if (returnVal == JFileChooser.APPROVE_OPTION) {
selectedSourceFile = fc.getSelectedFile();
sourceText.setText(selectedSourceFile.getName());
}
} else if (event == destinationButton) {
fc.setCurrentDirectory(new java.io.File("."));
fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
if (fc.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
selectedDestinationFolder = fc.getSelectedFile();
destinationText.setText(selectedDestinationFolder.getName());
}
} else if (event == copyButton) {
// where we implement the second file... here is where we'll call to compute the
// sum of the lines
String name = selectedSourceFile.getName();
// changed the output file to read ("Orig name here"_out.txt)
name = selectedSourceFile.getName().substring(0, name.lastIndexOf(".")) + "_out.txt";
File destinationFile = new File(selectedDestinationFolder, name);

try {
//Files.copy(selectedSourceFile.toPath(), destinationFileFolder.toPath()); // copying and computing
computeF(selectedSourceFile); // if we can get this to edit the _out.txt file we
// can do with out creating two seperate files- the previous *_.tmp can just be
// the *_out.txt
PrintWriter writer = new PrintWriter(destinationFile, "UTF-8");
writer.println(textToWrite);
writer.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}

public static void computeF(File selectedDestinationFile) throws IOException {
textToWrite = "";
int sum;
if (!selectedDestinationFile.isFile()) // IF CANNOT FIND FILE
{
System.out.println(selectedDestinationFile.getAbsolutePath() + " - Parameter is not an existing file");
return;
}

try (BufferedReader br = new BufferedReader(new FileReader(selectedDestinationFile.getAbsolutePath()))) {
String line;
while ((line = br.readLine()) != null) {
//Split each line, then check value in the array as an int and add to sum.
String[] temp = line.split(", ");
sum = 0;

for (int i = 0; i < temp.length; i++)
sum = Integer.parseInt(temp[i]);

textToWrite+= sum + System.getProperty("line.separator");
}
}

}

public static void main(String[] args) {
fileSumCompute cpy1 = new fileSumCompute();
cpy1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
cpy1.setSize(600, 150);
cpy1.setVisible(true);
}
}

I made a few major changes, as well as many minor. Overall, you were close. Let me elaborate on the big changes.

  • First, I made fileSumCompute just implement the ActionListener interface. This way, you don't need to write a private inner class to handle actions. You can just use the .addActionListener(this) on whatever component you need.
  • Next, I reworked the actionPerformed() method. I split it into 3 parts, one for each button. I also changed how the variables were assigned. You looked like you had it pretty close, but there were some things off. From what I understand, you need to get a source file, read the source file in, sum each line in the source file, and write those sums to a new file with the same name as the source file with _out appended. If I misunderstood, I apologize.
  • Lastly, I changed the computeF method. Again, you were close. I changed it to use a simple method for reading a file in line by line, found on this site here. It reads each line in, splits each line with the split() method, then gets the int value for each number.

There were a lot of minor changes. Try to work through and understand them - this code isn't perfect, but reading working code is helpful in understanding concepts.

Additionally, I know Java and Object Oriented programming as a whole can be daunting. I recommend checking out the Oracle Docs for examples on concepts like GUI - they have some good examples on there. Lastly, don't try to learn these overnight. There is a lot to learn, so just take it one day at a time. Also, don't be afraid to check out this site for code snippets. There are a lot of good solutions here, such as the one I found.

showOpenDialog() of JFileChooser doesn't open dialog box for opening files

I fixed your code and got the JFileChooser to open.

The major changes I made are:

  1. I started the Swing GUI with a call to the SwingUtilities invokeLater method. This method ensures that the Swing components are created and executed on the Event Dispatch Thread.

  2. I used a JFrame. I did not extend a JFrame. You only extend Swing components when you intend to override one or more of the class methods.

  3. Your code was confusing to read. I divided the code into logical methods. I left your confusing code alone, but when you create Swing layouts, you really should create the components in row, column order. You should also group all of the method calls for a particular component together. It makes finding and solving problems easier.

  4. You shouldn't have just one action listener for everything. You should have separate action listeners for each button or menu item.

Anyway, here's your code. Once I separated things logically, it was easier to find the mistakes which prevented your JFileChooser from displaying.

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;

public class PDFMerger implements ActionListener {

private JFrame frame;
private JMenuItem openItem;
private JMenuItem saveItem;
private JMenuItem exitItem;
private JTextArea textArea;
private JTextField textField;
private JButton bindButton;
private File[] files;
private File mergedFile;

public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new PDFMerger();
}
});
}

public PDFMerger() {
frame = new JFrame("PDF Merger");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JMenuBar menuBar = createJMenuBar();
frame.setJMenuBar(menuBar);

JPanel operationPanel = createOperationPanel();
frame.add(operationPanel, BorderLayout.NORTH);
JPanel textPanel = createTextPanel();
frame.add(textPanel, BorderLayout.CENTER);

frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}

private JPanel createOperationPanel() {
JPanel operationPanel = new JPanel();
BoxLayout layout = new BoxLayout(operationPanel, BoxLayout.LINE_AXIS);
operationPanel.setLayout(layout);
JLabel label = new JLabel("Result: ");
textField = new JTextField(30);
textField.setEditable(false);
bindButton = new JButton("Bind");
bindButton.addActionListener(this);
bindButton.setEnabled(false);
operationPanel.add(label);
operationPanel.add(textField);
operationPanel.add(bindButton);
return operationPanel;
}

private JPanel createTextPanel() {
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());

textArea = new JTextArea(40, 50);
JScrollPane scrollPane = new JScrollPane(textArea);
panel.add(scrollPane, BorderLayout.CENTER);
return panel;
}

private JMenuBar createJMenuBar() {
JMenu menu = new JMenu("File");
openItem = new JMenuItem("Open");
openItem.addActionListener(this);
saveItem = new JMenuItem("Save");
saveItem.setEnabled(false);
saveItem.addActionListener(this);
exitItem = new JMenuItem("Exit");
exitItem.addActionListener(this);
menu.add(openItem);
menu.add(saveItem);
menu.add(exitItem);
JMenuBar menuBar = new JMenuBar();
menuBar.add(menu);
return menuBar;
}

@Override
public void actionPerformed (ActionEvent event) {
if (event.getSource() == exitItem) {
frame.dispose();
System.exit(0);
} else if (event.getSource() == openItem) {
files = openFiles();
bindButton.setEnabled(false);
} else if (event.getSource() == bindButton) {
mergedFile = mergeFiles();
saveItem.setEnabled(true);
} else if (event.getSource() == saveItem)
saveFile();
}

public File[] openFiles () {
File[] selectedFiles = null;
JFileChooser chooser = new JFileChooser();
chooser.setCurrentDirectory(new File("."));
chooser.setMultiSelectionEnabled(true);
int option = chooser.showOpenDialog(frame);

if (option == JFileChooser.APPROVE_OPTION)
selectedFiles = chooser.getSelectedFiles();
return selectedFiles;
}

public File mergeFiles () {
File merged = null;
// TODO

return merged;
}
public void saveFile () {
//TODO
}
}


Related Topics



Leave a reply



Submit