JFileChooser Hanging After Dialog Closes - java

I want to start by saying that I'm new to swing. So all that I am trying to do if use a JFileChooser to select a directory. I can open, navigate and select a directory. The problem comes when I press any button that closes the dialog. When I do that then my application freezes. When ever it freezes just the panel that the dialog box is returning to turns white. When I step with the debugger the hang happens immediately aftet the dialog closes and the if statement is not reached. Also I am doing this inside of an Eclipse plugin if that makes a different. In particular it is hosted inside of a View. Code below:
public class TexturePacker extends ViewPart {
public void createPartControl(Composite parent) {
Composite composite = new Composite(parent, SWT.EMBEDDED | SWT.NO_BACKGROUND);
frame = SWT_AWT.new_Frame(composite);
frame.add(new TexturePackerPanel(frame));
}
}
public class TexturePackerPanel extends JPanel {
//This is called from initialize(), which is called in the constructor
private void initializeConfigPanel() {
JPanel configPanel = new JPanel();
JTextBoxk outputDirectory = new JTextField();
configPanel.add(inputDirectory);
JButton fileButton = new JButton("Folder");
fileButton.addMouseListener(new MouseListener(){
#Override
public void mouseClicked(MouseEvent arg0) {
JFileChooser file = new JFileChooser(outputDirectory.getText());
file.setDialogTitle("Select Output Directory");
file.setDialogType(JFileChooser.OPEN_DIALOG);
file.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
int returnVal = file.showDialog(frame, "Choose");
if(returnVal == JFileChooser.APPROVE_OPTION) {
outputDirectory.setText(file.getSelectedFile().getAbsolutePath());
}
}
//Other blank MouseListener methods//
});
configPanel.add(fileButton);
}
}
System Info:
Windows 8 64bit
Java 7
Eclipse 4.2 SR1 EE Edition
I'm pretty sure that the problem is caused by Swing not playing nice inside of eclipse. I have successfully gotten it working using SWT Directory Dialog. So I am going to just convert the whole JPanel to SWT. Thanks everyone's help, I now know a lot more about how Swing works.

For this you really should be using an ActionListener instead of a MouseListener.
Aside from that I think this is a threading issue. You should read the documents on concurrency in swing.
Surround the JFileChooser part with
SwingUtilities.invokeLater(new Runnable() {
public void run() {
\\Your JFileChooser bit
}
Edit 1:
I've run the following slightly edited code but can't reproduce your problem
public static void main(final String[] args){
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
final JPanel configPanel = new JPanel();
final JButton fileButton = new JButton("Folder");
final JFrame frame = new JFrame();
frame.setVisible(true);
frame.add(configPanel);
// JButton outputDirectory = new JButton("XX");
fileButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(final ActionEvent arg0) {
final JFileChooser file = new JFileChooser();
file.setDialogTitle("Select Output Directory");
file.setDialogType(JFileChooser.OPEN_DIALOG);
file.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
final int returnVal = file.showDialog(frame, "Choose");
if(returnVal == JFileChooser.APPROVE_OPTION) {
// outputDirectory.setText(file.getSelectedFile().getAbsolutePath());
System.out.println(returnVal);
}
}
});
configPanel.add(fileButton);
}
});
}

Related

JFileChooser Thread & JLabel

I'm creating a parser that's why I use JFileChooser.
When I select a file with JFileChooser, I would like to have a JLabel that says : "parsing in progress" or smth like that.
And when it's done : "parsing done".
(My first aim was to use progress bars, but it's a bit complicated for me now)
The ReadFile class will take array of files and create Callable for each file. If 5 files : 5 threads will be called. I used Callable because I need to get back Strings of data for each Threads and write it in a same csv file.
Well, when I click on Cancel on JFileChooser, the JLabel displays correctly at the right moment but when I select files / file for the parsing function, the JLabel waits the entire execution of my Callables and then "processing" appears (but when it has already ended ^^).
I cannot manage to display processing at the beginning of the threads.
Note : I called CardLayout at this moment, but it is not used yet.
Here is my code :
public class Main {
private static final String CARD_MAIN = "Card Main";
private static final String CARD_FILE = "Card File";
public static void main(String[] args) throws IOException {
createGUI();
}
public static void createGUI(){
// the JFrame
final JFrame window = new JFrame();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setLocationRelativeTo(null);
window.setTitle("TMG Parser - Thales");
window.setSize(400, 100);
// the buttonPanel ( one to open JFileChooser & one to quit )
JPanel container = new JPanel();
JPanel buttonPanel = new JPanel();
final JButton fileButton = new JButton("Choose File");
fileButton.setBackground(Color.BLACK);
fileButton.setForeground(Color.WHITE);
final JButton quitButton = new JButton("Quit");
quitButton.setBackground(Color.RED);
quitButton.setForeground(Color.WHITE);
// adding buttons to panel
buttonPanel.add(fileButton);
buttonPanel.add(quitButton);
// the status label that says : processing or done
final JLabel status = new JLabel();
container.add(status);
fileButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
JFileChooser dialogue = new JFileChooser(new File("."));
dialogue.setMultiSelectionEnabled(true) ;
if (dialogue.showOpenDialog(null)==
JFileChooser.APPROVE_OPTION) {
status.setText("Processing");
File[] fichiers=dialogue.getSelectedFiles();
for( int i = 1; i<fichiers.length; ++i){
fichiers[i].getName();
fichiers[i].getAbsolutePath();
}
// calling my execution function (threads)
ReadFile readProgram = new ReadFile(fichiers);
}
else{status.setText("Action cancelled");}
}
});
quitButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
System.exit(0);
}
});
window.add(container, BorderLayout.CENTER);
window.add(buttonPanel, BorderLayout.PAGE_END);
window.setVisible(true);
}
}
Ok so #tobias_k was right ! Thank you man.
When I launched ReadFile, that was freezing my swing thread until ReadFile was done.
I changed ReadFile to a thread (and calling callables), and now it works perfectly.
Thanks !

JDialog opening very slow

I'm having some problems while working on a project for school. The JDialog renders very slow. Let me show you.
This is the GUI:
When I click "Advance time" it takes around 3 seconds to open the JDialog. When it's open I get this (which is fine):
But when I drag that JDialog around, I get this (which is not ok):
It also takes very long to close the JDialog. It closes, but you can still see it:
This is the snippet of code where I think the problem lays, it's the code for the menu-bar:
private JMenu editMenu()
{
JMenu editMenu = new JMenu("Edit");
editMenu.setMnemonic(KeyEvent.VK_E);
JMenuItem advanceTimeMenuItem = new JMenuItem("Advance time");
advanceTimeMenuItem.setMnemonic(KeyEvent.VK_A);
advanceTimeMenuItem.setToolTipText("Advance the internal clock");
advanceTimeMenuItem.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent event)
{
//We first create panel to add to the dialog.
JPanel panel = new JPanel();
//Calendar
AdvanceTimePanel calendar = new AdvanceTimePanel(internalClockController);
//Button that will be used to confirm the system time change.
JButton btnSave = new JButton("Save");
//Add actionlistener to the save button
btnSave.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e)
{
Date selectedDate = calendar.getDate();
try
{
internalClockController.updateDateTime(selectedDate);
} catch (InvalidInternalClockException e1)
{
System.out.println("InvalidInternalClockException: " + e1.getMessage());
}
}
});
//Add the components to the panel.
panel.add(btnSave);
//This is the calendar added to the panel.
panel.add(calendar);
//Create the dialog and add the panel to it.
JDialog jDialog = new JDialog();
jDialog.add(panel);
jDialog.setBounds(100, 100, 400, 200);
jDialog.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
jDialog.setVisible(true);
}
});
editMenu.add(advanceTimeMenuItem);
Does someone have an idea how to speed things up?
Thanks in advance.
Events are handled on one single thread. (Also repaint events.) For the application to remain
responsive, perform longer actions a bit later by using invokeLater, as below:
#Override
public void actionPerformed(ActionEvent event)
{
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
... // All code here
}
});
}
This is quite wordy; Java 8 allows:
advanceTimeMenuItem.addActionListener(
(event) -> {
EventQueue.invokeLater(
() -> {
... // All code
});
});

opening only one window on actionPerformed

I've looked through topics on how to open only one window when a button is clicked but none of the solutions there helped, perhaps because my code was structured a bit differently.
So I have a main window class extending JFrame and one of the buttons is supposed to open a new window when clicked. I have defined the widgets/panels etc for the new window in a separate class. At the moment, every time I click on the button a new window is opened. I want to make it so that if a window is already opened then it would switch to that window once the button is clicked again.
Here is a bit of my code:
public class MainWindow extends JFrame{
/*
* create widgets and panels
*/
Button.addActionListener(new ActionListener() { // the button that opens
//a new window
#Override
public void actionPerformed(ActionEvent e) {
Window2 ww = new Window2(); //creating the new window here
}
});
}
NB. The Window2 class is also extending JFrame, if that's of any help.
Thanks
pull out ojbect creation from actionPerformed method beacuse each time you click button it's create new object. below can help you :-
Make a Window2 class singalton for more detail about singalton click here.
2 . add null check as below :-
....
Window2 ww = null; // static or instence variable
......
#Override
public void actionPerformed(ActionEvent e) {
if(ww==null)
{
ww = new Window2();
ww.someMethod();
}
else
{
ww.someMethod();
}
}
});
Here is a full working example:
Window2.java
public class Window2 extends JFrame {
private static final long serialVersionUID = 7843480295403205677L;
}
MainWindow.java
public class MainWindow extends JFrame {
private static final long serialVersionUID = -9170930657273608379L;
public static void main(String[] args) {
MainWindow mw = new MainWindow();
mw.go();
}
private void go() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowGUI();
}
});
}
private void createAndShowGUI() {
JButton button = new JButton("Click me");
button.addActionListener(new ActionListener() {
private Window2 ww = null;
#Override
public void actionPerformed(ActionEvent e) {
if (ww==null) {
ww = new Window2(); //creating the new window here
ww.setDefaultCloseOperation(HIDE_ON_CLOSE);
ww.setTitle("Window2 created on " + new Date());
ww.setSize(500, 200);
}
pack();
ww.setVisible(true);
}
});
setLayout(new BorderLayout());
add(button);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
pack();
setVisible(true);
}
}
What you can try is make two windows and put the actionPeformed method in the main class so that when the button is pressed it displays the second window

Use value of a variable from another class

I have this jFrame class:
public class Frame1 extends javax.swing.JFrame {
........
String name;
File file;
JFileChooser FileChooser = new JFileChooser();
if (FileChooser.getSelectedFile().isFile()) {
try {
file = FileChooser.getSelectedFile();
name = FileChooser.getSelectedFile().getName();
System.out.println( name );
} catch (FileNotFoundException ex) {
Logger.getLogger(Frame1.class.getName()).log(Level.SEVERE, null, ex);
}
}
........
private void Button1 (java.awt.event.ActionEvent evt) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
Frame2 obj = new Frame2 ();
}
});
}
}
Then I created the class "Frame2":
public class Frame2 extends javax.swing.JFrame {
.......
}
As you can image, when my program starts I use a JFileChooser to choose a file;
after that I click a button that opens another jFrame; in this jFrame (Frame2)
What I would need is to use the file that I have chosen in the previous jFrame (Frame1).
So I need to use "file" variable from "Frame1" in "Frame2".
I tried to do this in Frame2:
Frame1 obj1 = new Frame1();
File file2 = obj1.file;
System.out.println( file2 );
So when I run the program and choose a file and then I click "Button1" to run "Frame2", it first prints the file name ("name") from "Frame1"
and after that it prints "null" so I can't get correct "file" value from "Frame1" and use it in "Frame2".
How can I do that?
Thanks
This won't work:
Frame1 obj1 = new Frame1();
File file2 = obj1.file;
System.out.println( file2 );
because it falls into a common newbie trap: thinking that a new instance of a class (here Frame1) holds the same information as another previously used instance of the class (the previous Frame1 instance that was displayed), and this simply isn't true unless you use static variables -- something I strongly urge you not to do.
Instead why not:
Change your first JFrame into a modal JDialog or JOptionPane
Give it a public method getSelectedFile() that returns the selected file. This is what your question is really about -- sharing the state of one object with another object -- and one way to do this is via your basic getter and setter methods.
Then show your dialog, and when it returns, call the above method on the above object.
Or why not instead simply show a JFileChooser dialog since it does all of this for you?
For example:
import java.io.File;
import javax.swing.*;
public class Foo {
private static void createAndShowGui() {
JFileChooser fileChooser = new JFileChooser();
int result = fileChooser.showOpenDialog(null);
if (result == JFileChooser.APPROVE_OPTION) {
File file = fileChooser.getSelectedFile();
JTextField field = new JTextField(file.getAbsolutePath(), 30);
JPanel panel = new JPanel();
panel.add(new JLabel("Selected File:"));
panel.add(field);
// create and open a new JFrame with the selected file's path
JFrame frame = new JFrame("Foo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(panel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

troubles with displaying image in window

I need to choose image with file open dialog and then show it in window. But When I choose image it is not shown in the window.
I've created class which create window with jmenubar and 1 jmenuitem. When I click on menuitem JfileChooser appears and then I choose some file. But then happens nothing.
I think the problem is in actionListener for JFileChooser(ImageFilter is a filter from docs java)
public Frame(){
//create bars and window
mainframe = new JFrame("Window");
mainframe.setVisible(true);
mainframe.setSize(300, 300);
menubar = new JMenuBar();
mainer = new JMenu("Menu");
menubar.add(mainer);
//create items
item = new JMenuItem("Open",KeyEvent.VK_T);
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_1, ActionEvent.ALT_MASK));
item.getAccessibleContext().setAccessibleDescription("open image");
//action listener
item.addActionListener(
new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//open file dialog
choser = new JFileChooser();
choser.addChoosableFileFilter(new ImageFilter());
final int returnval = choser.showOpenDialog(menubar);
//action listener for JFileChooser
choser.addActionListener(
new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (returnval == JFileChooser.APPROVE_OPTION){
fc = choser.getSelectedFile();
try{
Panel panel = new ShowImage(fc.getName());
mainframe.getContentPane().add(panel);
}catch(Exception exc){};
}
}
}
);
}
}
);
mainer.add(item);
mainframe.setJMenuBar(menubar);
}
ShowImage class
class ShowImage extends Panel{
BufferedImage image;
public ShowImage(String imagename) throws IOException {
File input = new File(imagename);
image = ImageIO.read(input);
}
public void paint(Graphics g){
g.drawImage(image,0,0,image.getWidth(),image.getHeight(),null);
}
}
P.S another problem is that it shows nothing until I change size of the window.
Extend JPanel instead of Panel, and override paintComponent method, ie:
class ShowImage extends JPanel{
public void paintComponent(Graphics g){
...
}
}
Also, there is no need to addActionListener on JFileChooser, just check the return value and act accordingly, ie:
final int returnval = choser.showOpenDialog(menubar);
if (returnval == JFileChooser.APPROVE_OPTION){
...
}
Im pretty sure this line will cause problems:
Panel panel = new ShowImage(fc.getName());
getName() will return the name of the file. So for example if you choose a image with JFileChooser named image.jpg, getName will return "image.jpg". This will make the image only show if the file you select is stored in the root folder of your project. I would change getName() to getAbsoultePath() which will return the full patch (e.i c:\desktop\image.jpg) which is most likley what you want.
Also as Max points out, you should override paintComponent rather then paint:
protected void paintComponent(Graphics g){
g.drawImage(image,0,0,image.getWidth(),image.getHeight(),null);
}

Categories