I came across a very strange problem in my program I wrote to copy Pictures, Documents, Videos, and Music (from the Windows file system) to a backup drive. I set a string array directories[] equal to {picturesDirectory, documentsDirectory, videosDirectory, musicDirectory} and use a for loop to loop through each one to copy the files. I use a GUI so I have a SwingWorker that runs the actual copy methods. However, when I run the program, it only loops through the "for" loop twice, only copying pictures and documents. I don't think I can really post a SSCCE that will help, so I'm just posting my entire class. inDrive is the main Windows drive ("C" by default), outDrive is the backup drive letter, username is the windows username, and space is the total disk space that the files/directories will take up.
package diana;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.text.DefaultCaret;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JButton;
import javax.swing.JProgressBar;
import javax.swing.JLabel;
import javax.swing.SwingWorker;
import org.apache.commons.io.FileUtils;
#SuppressWarnings("serial")
public class BasicCopy extends JFrame {
private JPanel contentPane;
private JPanel bottomPane;
private JTextArea txtCopiedDirs;
private JScrollPane scrollPane;
private JButton btnCancel;
private JProgressBar progressBar;
private JLabel lblCopying;
private JLabel lblProgress;
private static String mainDrive;
private static String backupDrive;
private static String username;
private static String backupDir;
double totalSize = 0; //total size of directories/files
double currentMB = 0; //size of already-copied files
static double currentSize = 0; //current size of files counting up to ONE_PERCENT
static int currentPercent = 0; //current progress in %
static double ONE_PERCENT; //totalSize / 100
private ManipulateDirectories md;
private Task task;
public BasicCopy() {
}
public BasicCopy(String inDrive, String outDrive, String username, long space) {
mainDrive = inDrive;
backupDrive = outDrive;
BasicCopy.username = username;
totalSize = space;
ONE_PERCENT = totalSize / 100;
createGUI();
}
public void createGUI() {
// Create frame
setTitle("Backup Progress");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 500, 350);
// Create panel for text area/scroll pane
contentPane = new JPanel(new BorderLayout());
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
// Create panel for progress bar/cancel button
bottomPane = new JPanel();
bottomPane.setLayout(new BoxLayout(bottomPane, BoxLayout.Y_AXIS));
lblCopying = new JLabel("Now backing up your files....\n");
lblCopying.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
contentPane.add(lblCopying, BorderLayout.NORTH);
// Create text area/scroll pane
txtCopiedDirs = new JTextArea(10, 50);
txtCopiedDirs.setEditable(false);
DefaultCaret caret = (DefaultCaret) txtCopiedDirs.getCaret();
caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
scrollPane = new JScrollPane(txtCopiedDirs);
contentPane.add(scrollPane, BorderLayout.CENTER);
lblProgress = new JLabel("Progress:");
progressBar = new JProgressBar(0, 100);
progressBar.setStringPainted(true);
progressBar.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
progressBar.setIndeterminate(true);
btnCancel = new JButton("Cancel");
btnCancel.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(null, "Backup Cancelled!");
closeWindow();
}
});
bottomPane.add(lblProgress, Component.LEFT_ALIGNMENT);
bottomPane.add(progressBar, Component.CENTER_ALIGNMENT);
bottomPane.add(btnCancel, Component.RIGHT_ALIGNMENT);
contentPane.add(bottomPane, BorderLayout.SOUTH);
PropertyChangeListener listener = new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent event) {
if ("progress".equals(event.getPropertyName())) {
currentPercent = (int) event.getNewValue();
progressBar.setValue((int) currentPercent);
progressBar.setString(Integer.toString(currentPercent) + "% ("
+ String.format("%.2f", (currentMB / 1048576))
+ "MB of " + String.format("%.2f", (totalSize / 1048576)) + "MB)");
}
}
};
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
this.setLocation(dim.width / 2 - this.getSize().width / 2, dim.height / 2 - this.getSize().height / 2);
setVisible(true);
task = new Task();
task.addPropertyChangeListener(listener);
task.execute();
}
/**
* Swing Worker class
*/
class Task extends SwingWorker<Void, String> {
public Task() {
md = new ManipulateDirectories(this);
}
#Override
public Void doInBackground() {
md.makeBackupDirectory();
// Directories to be copied
String pics = mainDrive + ":\\Users\\" + username + "\\Pictures\\";
String docs = mainDrive + ":\\Users\\" + username + "\\Documents\\";
String vids = mainDrive + ":\\Users\\" + username + "\\Videos\\";
String musc = mainDrive + ":\\Users\\" + username + "\\Music\\";
File[] directories = { new File(pics), new File(docs), new File(vids), new File(musc) };
/********** THIS ONLY LOOPS THROUGH PICS AND DOCS **********/
for (int i = 0; i < directories.length; i++) {
md.copyDirectory(directories[i], new File(backupDir));
}
/***********************************************************/
return null;
}
#Override
public void process(List<String> chunks) {
for (String path : chunks) {
txtCopiedDirs.append(path);
}
}
#Override
public void done() {
JOptionPane.showMessageDialog(null, "Backup complete!");
closeWindow();
}
public void updateProgress(int tick) {
if (progressBar.isIndeterminate())
progressBar.setIndeterminate(false);
progressBar.setString(Integer.toString(currentPercent) + "% ("
+ String.format("%.2f", (currentMB / 1048576)) + "MB of "
+ String.format("%.2f", (totalSize / 1048576)) + "MB)");
}
public void publishText(String filename) {
publish(filename + "\n");
}
}
public class ManipulateDirectories {
Task task;
public ManipulateDirectories(Task task) {
this.task = task;
}
public void makeBackupDirectory() {
// Create Backup Directory
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("MM-dd-yyyy_HHmmss");
String timestamp = sdf.format(date);
backupDir = backupDrive + ":\\" + "Backup_" + timestamp;
File backupDirectory = new File(backupDir);
backupDirectory.mkdir();
task.updateProgress(0);
}
// Recursive function to loop through and copy individual files
public void copyDirectory(File file, File dest) {
if (file.isFile()) {
try {
FileUtils.copyFileToDirectory(file, dest);
currentMB = currentMB + getDirSize(file);
currentSize = currentSize + getDirSize(file);
if (currentSize >= ONE_PERCENT) {
currentPercent = currentPercent + (int) (currentSize / ONE_PERCENT);
currentSize = currentSize % ONE_PERCENT;
}
task.updateProgress(currentPercent);
task.publishText(file.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}
} else if (file.isDirectory()) {
File newDir = new File(String.format("%s\\%s", dest.getAbsolutePath(), file.getName()));
if (!newDir.exists()) {
newDir.mkdir();
for (File f : file.listFiles()) {
copyDirectory(f, newDir);
}
}
}
}
public Long getDirSize(File file) {
long size = 0L;
if (file.isFile() && file != null) {
size += file.isDirectory() ? getDirSize(file) : file.length();
} else if (file.isDirectory()) {
for (File f : file.listFiles()) {
size += f.isDirectory() ? getDirSize(f) : file.length();
}
}
return size;
}
}
/* Close current window */
public void closeWindow() {
WindowEvent close = new WindowEvent(this, WindowEvent.WINDOW_CLOSING);
Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(close);
System.exit(0);
}
}
I added a comment around the for loop that is only being executed twice. I placed a breakpoint and it never gets there after copying documents, so it must call the SwingWorker's done() method before then.
Does anyone see what might cause this problem? I really hate posting all my code here, as I understand it's often a pain to read through it all. I'm hoping someone can find why it's ending prematurely though. Many thanks!
EDIT:
After further debugging (based on some of the suggestions from the comments), I have discovered there is a NPE due to the program looking for "My Music" within the Documents folder--a "link" that doesn't exist as a directory (hence the null value).
java.util.concurrent.ExecutionException: java.lang.NullPointerException
at java.util.concurrent.FutureTask$Sync.innerGet(Unknown Source)
at java.util.concurrent.FutureTask.get(Unknown Source)
at javax.swing.SwingWorker.get(Unknown Source)
at diana.BasicCopy$Task.done(BasicCopy.java:181)
at javax.swing.SwingWorker$5.run(Unknown Source)
at javax.swing.SwingWorker$DoSubmitAccumulativeRunnable.run(Unknown Source)
at sun.swing.AccumulativeRunnable.run(Unknown Source)
at javax.swing.SwingWorker$DoSubmitAccumulativeRunnable.actionPerformed(Unknown Source)
at javax.swing.Timer.fireActionPerformed(Unknown Source)
at javax.swing.Timer$DoPostEvent.run(Unknown Source)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$200(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
Caused by: java.lang.NullPointerException
at diana.BasicCopy$ManipulateDirectories.copyDirectory(BasicCopy.java:243)
at diana.BasicCopy$ManipulateDirectories.copyDirectory(BasicCopy.java:244)
at diana.BasicCopy$Task.doInBackground(BasicCopy.java:166)
at diana.BasicCopy$Task.doInBackground(BasicCopy.java:1)
at javax.swing.SwingWorker$1.call(Unknown Source)
at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
at java.util.concurrent.FutureTask.run(Unknown Source)
at javax.swing.SwingWorker.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
I was under the impression I wouldn't have to worry about this since I use the file.isFile() and file.isDirectory() checks. According to the javadocs, these only return true if the file is a file/directory AND if it exists. I assumed (probably stupidly) that it should skip over anything like My Music since it doesn't exist as a directory?
The problem is that the existing java.io.File API can't handle symbolic links (or what ever they call them in Windows). Directories like "My Music" aren't actually a File/directory in the traditional sense, but are a special marker pointing to another file/directory.
In order to overcome this, you'll need to take a look at the new Paths/Files API available in Java 7
For more details, try taking a look at Links, Symbolic or Otherwise
I found the answer. It was the same problem I was asking about in this thread, and was thinking the solution was something else: Java program to calculate directory size keeps throwing NPE
The problem is that file.listFiles() was null when run while the file path was C:\Users\user\Documents\My Music. To fix it I simply put in an if statement to check that file.listFiles() != null before the "for" loop at the bottom of the copyDirectory method:
if (file.listFiles() != null){
for (File f : file.listFiles()) {
copyDirectory(f, newDir);
}
}
I'm sorry for posting this here when apparently I already had the same problem that was answered in another thread. Hopefully this helps someone though. Thank you all for your suggestions, they are appreciated.
Related
edit: I'm not sure how to get the stacktrace. Here's the error I get:
Exception in Application start method
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:389)
at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:328)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at sun.launcher.LauncherHelper$FXHelper.main(Unknown Source)
Caused by: java.lang.RuntimeException: Exception in Application start method
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:917)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$1(LauncherImpl.java:182)
at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.IllegalArgumentException: Grid hgap=0.0, vgap=0.0, alignment=TOP_LEFTis already inside a scene-graph and cannot be set as root
at javafx.scene.Scene$9.invalidated(Scene.java:1100)
at javafx.beans.property.ObjectPropertyBase.markInvalid(ObjectPropertyBase.java:111)
at javafx.beans.property.ObjectPropertyBase.set(ObjectPropertyBase.java:146)
at javafx.scene.Scene.setRoot(Scene.java:1072)
at javafx.scene.Scene.<init>(Scene.java:347)
at javafx.scene.Scene.<init>(Scene.java:223)
at application.Main.start(Main.java:108)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$8(LauncherImpl.java:863)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$7(PlatformImpl.java:326)
at com.sun.javafx.application.PlatformImpl.lambda$null$5(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$6(PlatformImpl.java:294)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$4(WinApplication.java:186)
... 1 more
Exception running application application.Main
I have an assignment where I need to read in information and create a graph from it. It also needs to automatically resize a graph when the user drags the window. I've got the graph working but can't figure out how to get it resize.
I found a different thread that used something like this:
StackPane root = new StackPane(pane);
root.setAlignment(Pos.TOP_LEFT);
// use gridPane size to determine the factor to scale by
NumberBinding maxScale = Bindings.min(root.widthProperty().divide(350),
root.heightProperty().divide(100));
pane.scaleXProperty().bind(maxScale);
pane.scaleYProperty().bind(maxScale);
but that gave me a runtime error.
package application;
import javafx.scene.control.Label;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Scanner;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.NumberBinding;
import javafx.geometry.Pos;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws FileNotFoundException {
GridPane pane = new GridPane();
pane.setMinSize(400, 500);
pane.setMaxSize(350, 10000);
StackPane root = new StackPane(pane);
ArrayList <Team> aT = new ArrayList <Team>();
Scanner scannerIOInput = null;
FileInputStream fis = null;
BorderPane root2 = new BorderPane();
try{
fis = new FileInputStream(new File("mp3_hockey_stats.txt"));
scannerIOInput = new Scanner(fis);
// System.out.println("File is read in");
String c = null;
int indx;
//read in data
for (int i = 0; i < 7; i++){
c = scannerIOInput.nextLine();
indx = c.indexOf(",");
if (indx > 0)
{
String name = c.substring(0, indx);
String s1 = c.substring(indx + 1);
int stat = Integer.parseInt(s1);
aT.add(new Team (name, stat));
}
}
//print data
int recX, recY, recWidth, recHeight;
recX = 10;
recY = 10;
recWidth = 10;
recHeight = 10;
for (int i = 0; i < aT.size(); i++)
{
Label name = new Label (aT.get(i).teamName1);
Rectangle r = new Rectangle();
r.setX(recX);
r.setY(recY + (i * 100));
r.setWidth(aT.get(i).stats1);
r.setHeight(recHeight);
r.setFill(Color.BLUEVIOLET);
pane.add(name, 1, i);
pane.add(r, 2, i);
//pane.add(" ", 1, i+1);
}
Scene scene = new Scene(pane,350, 100);
primaryStage.setScene(scene);
primaryStage.setTitle("Hockey Statistics Chart");
primaryStage.show();
} catch (FileNotFoundException e) {
System.out.println("File not found.");
} catch (NullPointerException e){
System.out.println("NullPointerException.");
}catch (ArrayIndexOutOfBoundsException e){
System.out.println("ArrayIndexOutOfBoundsException.");
}catch (RuntimeException e){
System.out.println("Runtime exception.");
} finally {
scannerIOInput.close();
}
}
public static void main(String[] args) {
launch(args);
}
}
I need to display two connected combo boxes with directory names. There is a start path which contains multiple directories that are displayed in the first jcombobox, and when a directory is selected, the sub directories need to be displayed in the second jcombobox. The second jcombobox should be able to select one of those sub directories. Each of sub sub directories contains multiple .txt files. I managed to display the directories and sub directories on both jcomboboxes including the files.
package calc.my.pay;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;
import javax.swing.table.DefaultTableModel;
import javax.swing.JComboBox;
import java.awt.Color;
import javax.swing.JTable;
import javax.swing.JScrollPane;
public class CalcMyPay extends JFrame implements ActionListener {
private JPanel contentPane;
private JScrollPane scrollPane;
private JComboBox folderSelector, subFolderSelector;
private File[] directory, subDirectory;
private String subPath, finalSubPath, selectedSubDirectory, finalSubDirectory;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
CalcMyPay frame = new CalcMyPay();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
* #throws IOException
*/
public CalcMyPay()
{
setBackground(Color.LIGHT_GRAY);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(350, 10, 1000, 700);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
scrollPane = new JScrollPane();
scrollPane.setBounds(12, 120, 958, 300);
String startPath = "C:/Users/Zeus/Desktop/Content/";
// The starting path of the file
directory = new File(startPath).listFiles();
// Folders dropdown box
folderSelector = new JComboBox();
folderSelector.setBounds(60, 13, 200, 22);
folderSelector.insertItemAt("Choose directory", 0);
folderSelector.setSelectedIndex(0);
for(int i=0; i < directory.length; i++) {
System.out.println(directory[i]);
folderSelector.addItem(directory[i].getName());
}
contentPane.add(folderSelector);
// Sub folder dropdown box
subFolderSelector = new JComboBox();
subFolderSelector.setBounds(300, 13, 200, 22);
subFolderSelector.insertItemAt("Choose subdirectory", 0);
subFolderSelector.setSelectedIndex(0);
contentPane.add(subFolderSelector);
folderSelector.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// Get the folder dropdown selected item
selectedSubDirectory = folderSelector.getSelectedItem().toString();
//System.out.println("Folder selected: " + Arrays.asList(directory).toString().contains(selectedSubDirectory));
//System.out.println("Subfolders based on folder selected : " + Arrays.asList(directory) + " " + selectedSubDirectory);
//subFolderSelector.addItem(folderSelector.getSelectedItem());
// Check if the array from the main directory contains the selected directory
if(Arrays.asList(directory).toString().contains(selectedSubDirectory)) {
// Make a new file that list all the directories in the given path
subPath = startPath + selectedSubDirectory;
subDirectory = new File(subPath).listFiles();
// Sort the array directory in a descending order
Arrays.sort(subDirectory, Collections.reverseOrder());
// Delete the previous list items, if any
subFolderSelector.removeAllItems();
// Iterate through all the directories in the selected folder
for(int i=0; i < subDirectory.length; i++) {
// Pass only directories (files will be omitted)
// ### Should check if directory contains only 4 numbers here
if(subDirectory[i].isDirectory()) {
//subFolderSelector.addItem(folderSelector.getSelectedItem());
subFolderSelector.addItem(subDirectory[i].getName());
}
}
}
}
});
subFolderSelector.addActionListener(new ActionListener() {
int count = 0;
#Override
public void actionPerformed(ActionEvent e) {
count++;
if(count == 3) {
selectedSubSubDirectory = subFolderSelector.getSelectedItem().toString();
// Make an new file that list all the file in the selected sub folder
if(Arrays.asList(subDirectory).toString().contains(selectedSubDirectory)) {
//textFiles = new File(finalSubPath).listFiles();
subSubPath = startPath + selectedSubDirectory + "/" + selectedSubSubDirectory;
textFiles = new File(subSubPath).listFiles();
for(File file: textFiles) {
if(file.isFile() && file.toString().toLowerCase().endsWith("_110.txt")) {
System.out.println(file);
}
}
}
count = 0;
}
}
});
}
}
However as you can see in the second actionListener for the subDirectorySelector i have a counter. The code there executes three times (because the second jcombobox changes value). There is an error if you select the same path twice in the first jcombobox. There must be a better (and possibly) shorter way to do this. What would you change?
Thanks
I tried to make my own version but it's really similar, except I removed the actionListener before updating the subFolder selector and I added more checks.
Here is my code :
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.Arrays;
import java.util.Collections;
import javax.swing.JComboBox;
import javax.swing.JFrame;
public class ComboDemo extends JFrame implements ActionListener {
private String rootDir;
private JComboBox box1;
private JComboBox box2;
/**
* Create the frame.
*/
public ComboDemo () {
super("Demo");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
createGui();
this.rootDir = "/home";
setRootDir(new File(this.rootDir));
}
/**
* Create the gui components.
*/
private void createGui () {
this.box1 = new JComboBox();
this.box2 = new JComboBox();
this.box1.addActionListener(this);
this.box2.addActionListener(this);
this.box1.insertItemAt("Choose directory :", 0);
this.box1.setSelectedIndex(0);
this.box2.insertItemAt("Choose subdirectory :", 0);
this.box2.setSelectedIndex(0);
setLayout(new FlowLayout(FlowLayout.LEADING));
add(this.box1);
add(this.box2);
}
/**
* Show the gui.
*/
private void showGui () {
setSize(500, 250);
setLocationRelativeTo(null);
setVisible(true);
}
/**
* Update the first selector with the directories listed under the specified
* root directory.
*
* #param dir
* Root directory.
*/
private void setRootDir (File dir) {
for (File file : dir.listFiles()) {
if (file.isDirectory()) {
this.box1.addItem(file.getName());
}
}
}
#Override
public void actionPerformed (ActionEvent e) {
if (e.getSource() instanceof JComboBox) {
JComboBox box = (JComboBox) e.getSource();
// Box 1
if (this.box1.equals(box)) {
String dirName = box.getSelectedItem().toString();
// RootDir / Folder
File dir = new File(this.rootDir + File.separator + dirName);
System.out.println("# Folder : " + dir.getPath());
// Check if there is a least one file
if (dir.exists() && dir.listFiles().length > 0) {
Arrays.sort(dir.listFiles(), Collections.reverseOrder());
// Reset box2
this.box2.removeAllItems();
this.box2.insertItemAt("Choose subdirectory :", 0);
// Update Box2
this.box2.removeActionListener(this);
for (File file : dir.listFiles()) {
if (file.isDirectory()) {
this.box2.addItem(file.getName());
}
}
this.box2.addActionListener(this);
this.box2.setSelectedIndex(0);
}
}
// Box 2
else if (this.box2.equals(box)) {
// Check if box2 is empty
if (box.getItemCount() > 0) {
String dirName = box.getSelectedItem().toString();
// RootDir / Folder / SubFolder
File dir = new File(this.rootDir + File.separator + this.box1.getSelectedItem().toString()
+ File.separator + dirName);
System.out.println("# SubFolder : " + dir.getPath());
// Check if there is a least one file
if (dir.exists() && dir.listFiles().length > 0) {
Arrays.sort(dir.listFiles(), Collections.reverseOrder());
// Print .txt files
for (File file : dir.listFiles()) {
if (file.isFile() && file.getName().endsWith(".txt")) {
System.out.println("\t" + file.getName());
}
}
}
}
}
}
}
public static void main (String[] args) {
ComboDemo demo = new ComboDemo();
demo.showGui();
}
}
When executing my jar from terminal I am getting the following:
***WARNING: Display must be created on main thread due to Cocoa restrictions.
Exception in thread "main" org.eclipse.swt.SWTException: Invalid thread access
at org.eclipse.swt.SWT.error(Unknown Source)
at org.eclipse.swt.SWT.error(Unknown Source)
at org.eclipse.swt.SWT.error(Unknown Source)
at org.eclipse.swt.widgets.Display.error(Unknown Source)
at org.eclipse.swt.widgets.Display.createDisplay(Unknown Source)
at org.eclipse.swt.widgets.Display.create(Unknown Source)
at org.eclipse.swt.graphics.Device.<init>(Unknown Source)
at org.eclipse.swt.widgets.Display.<init>(Unknown Source)
at org.eclipse.swt.widgets.Display.<init>(Unknown Source)
at commonDenom.UserInterface.main(UserInterface.java:26)an error
I've searched for his error and found a few with the same execution output error, but nothing with a solution to my situation.
The following details the locations of files, manifest content, terminal steps taken and finally the code content of the two class files involved.
File Locations
SWT library
/Dropbox/workspace/org.eclipse.swt/swt.jar
Manifest
/Dropbox/workspace/commonDenom/bin/Manifest.txt
Classes
/Dropbox/workspace/commonDenom/bin/commonDenom/
commonDenom.class
UserInterface.class
UserInterface$1.class (I didn't create this)
UserInterface$2.class (I didn't create this)
CommonDenom.jar (see creation below):
/Dropbox/workspace/commonDenom/bin/CommonDenom.jar
Manifest.txt content:
Main-Class: commonDenom.UserInterface
Class-Path: /Users/skuredjian/Dropbox/workspace/org.eclipse.swt/swt.jar
Terminal actions
Directory change
cd Dropbox/workspace/comonDenom/bin/
.jar creation
jar cfm CommonDenom.jar ../Manifest.txt *
Manifest check
jar tf CommonDenom.jar
META-INF/
META-INF/MANIFEST.MF
commonDenom/
commonDenom/commonDenom.class
commonDenom/UserInterface$1.class
commonDenom/UserInterface$2.class
commonDenom/UserInterface.class
swt.jar
CommonDenom.jar execution
java -jar CommonDenom.jar
***WARNING: Display must be created on main thread due to Cocoa restrictions.
Exception in thread "main" org.eclipse.swt.SWTException: Invalid thread access
at org.eclipse.swt.SWT.error(Unknown Source)
at org.eclipse.swt.SWT.error(Unknown Source)
at org.eclipse.swt.SWT.error(Unknown Source)
at org.eclipse.swt.widgets.Display.error(Unknown Source)
at org.eclipse.swt.widgets.Display.createDisplay(Unknown Source)
at org.eclipse.swt.widgets.Display.create(Unknown Source)
at org.eclipse.swt.graphics.Device.<init>(Unknown Source)
at org.eclipse.swt.widgets.Display.<init>(Unknown Source)
at org.eclipse.swt.widgets.Display.<init>(Unknown Source)
at commonDenom.UserInterface.main(UserInterface.java:26)
Code
UserInterface.class content
package commonDenom;
import java.util.Arrays;
import java.util.Scanner;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
public class UserInterface {
Shell shell;
Button btnNext;
Button btnDone;
Text input;
Text output;
static int count;
static int[] finalNums;
int[] nums = new int[1000];
public static void main(String[] args){
Display display = new Display();
new UserInterface(display);
display.dispose();
}
public UserInterface(Display display){
shell = new Shell(display);
shell.setSize(220,350);
shell.open();
input = new Text(shell, SWT.SINGLE);
input.setBounds(10, 10, 100, 20);
btnNext = new Button(shell, SWT.PUSH);
btnNext.setBounds(10, 40, 100, 30);
btnNext.setText("Next");
nextPress();
btnDone = new Button(shell, SWT.PUSH);
btnDone.setBounds(10, 80, 100, 30);
btnDone.setText("Done");
donePress();
output = new Text(shell, SWT.SINGLE);
output.setBounds(10, 120, 200, 200);
while(!shell.isDisposed()){
if(!display.readAndDispatch()){
display.sleep();
}
}
}
public void nextPress(){
btnNext.addSelectionListener(new SelectionAdapter(){
int x = 0;
#Override
public void widgetSelected(SelectionEvent e) {
nums[x] = Integer.parseInt(input.getText());
System.out.println("nums[" + x + "]:" + nums[x]);
x++;
count++;
}
});
}
public void donePress(){
btnDone.addSelectionListener(new SelectionAdapter(){
#Override
public void widgetSelected(SelectionEvent e) {
finalNums = new int[count];
for(int i = 0; i < count; i++){
finalNums[i] = nums[i];
}
System.out.println("finalNums:" + Arrays.toString(finalNums));
commonDenom.compare();
if(commonDenom.getResult() == 0){
output.setText(Arrays.toString(finalNums) + "\nThese numbers do not have a \ncommon multiplier");
}
else{
output.setText(Arrays.toString(finalNums) + "\nResult:" + String.valueOf(commonDenom.getResult()));
}
}
});
}
public static int[] getNums(){
return finalNums;
}
}
commonDenom.class content:
package commonDenom;
import java.awt.Button;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
import org.eclipse.swt.widgets.*;
public class commonDenom{
static int result;
public static void main(String[] args){
}
public static String compare(){
result = 0;
int mult = 0;
int x = 1;
int[] nums = UserInterface.getNums();
// find highest in set
for(int i = 0; i < nums.length; i ++){
if (nums[i] > mult) mult = nums[i];
}
// finds lowest common multiple
for(int i = 0; i < nums.length;){
if((mult * x) % nums[i] == 0){
result = mult * x;
i++;
}
else{
result = 0;
x++;
i = 0;
}
}
}
public static int getResult(){
return result;
}
}
On a Mac you must specify the -XstartOnFirstThread command line option to get SWT to run correctly.
So I've recently started working with JavaFX to try and insert video and audio into my java programs. Audio has worked just fine, but for some reason every time I try and play a video file, it returns a MEDIA_UNSUPPORTED exception. I've read around and saw that the video file needed to be MP4 (which it is), so I tried converting it to a different type then re-converting it to MP4 (H.264 & AAC) with a few different converters and nothing changes.
Here's the code I'm working with:
import java.net.URL;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.embed.swing.JFXPanel;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaView;
import javafx.util.Duration;
public class CallVideo extends JFrame{
public static final String VID_URL = "file:/C:/Users/Public/Videos/Videos/testCon.mp4"; //http://static.clipcanvas.com/sample/clipcanvas_14348_H264_320x180.mp4
private JFXPanel panel;
public CallVideo(String url)
{
panel = new JFXPanel();
Platform.runLater(new Runnable()
{
public void run()
{
final Media clip = new Media(VID_URL);
final MediaPlayer player = new MediaPlayer(clip);
final MediaView viewer = new MediaView(player);
viewer.setFitHeight(200);
viewer.setFitWidth(200);
final Button button = new Button("Bing Zzzzt!");
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event)
{
viewer.getMediaPlayer().seek(Duration.ZERO);
viewer.getMediaPlayer().play();
}
});
setMediaEventHandlers(viewer);
VBox vid = new VBox();
vid.getChildren().addAll(viewer, button);
Scene aScene = new Scene(vid, 200, 200);
panel.setScene(aScene);
}
});
this.add(panel);
this.setSize(500, 500);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
}
private void setMediaEventHandlers(final MediaView view) {
final MediaPlayer player = view.getMediaPlayer();
System.out.println("Initial: " + player.getStatus());
player.statusProperty().addListener(new ChangeListener<MediaPlayer.Status>() {
#Override
public void changed(ObservableValue<? extends MediaPlayer.Status> observable, MediaPlayer.Status oldStatus, MediaPlayer.Status curStatus) {
System.out.println("Current: " + curStatus);
}
});
if (player.getError() != null) {
System.out.println("Initial Error: " + player.getError());
}
player.setOnError(new Runnable() {
#Override public void run() {
System.out.println("Current Error: " + player.getError());
}
});
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new CallVideo(VID_URL);
}
});
}
}
The error occurs on the line where the "Media" object is initialized (beginning of constructor).
I'm at a total loss to see what the problem is. I've seen questions about the audio playing but the video not showing up, but it doesn't even do that for me...
In case someone needs it:
Eclipse
JDK 7
JavaFX 2.0
Windows 7 Pro
EDIT:
First off, I noticed I'm actually using JavaFX 2.0... Might that be the problem?
I've tested both versions provided in the answer, and both return this error (called by the statusListener) when using the URL provided by that answer:
Current Error: MediaException: MEDIA_UNSUPPORTED : com.sun.media.jfxmedia.MediaException: "Error enter code herelocator unsupported media format" : com.sun.media.jfxmedia.MediaException: "Error locator unsupported media format"
When using my own file, the program returns this error immediately upon calling the Media constructor, as before:
Exception in thread "AWT-EventQueue-0" MediaException: MEDIA_UNSUPPORTED : Unrecognized file signature!
at javafx.scene.media.Media.<init>(Media.java:382)
at CallVideo.<init>(CallVideo.java:27)
at CallVideo$5.run(CallVideo.java:90)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$000(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
I've updated the code I'm using above.
SOLVED!
The reason is really I was using an inappropriate JavaFX (and possibly JDK) for the job. I'm not really in control of that stuff since these are school computers, but that messed me up something good... Thanks for the help! I updated it with my final code.
This worked for me after I modified your program a little bit to fix a couple of issues.
Some changes I applied:
A MediaView is necessary to view the video, so one needs to be created and added to an active JavaFX scene in order for the video to be seen.
Some JavaFX controls need to be created on the JavaFX application thread rather than the main thread, otherwise you get java.lang.IllegalStateException: Toolkit not initialized.
Monitoring media error events and adding some diagnostic logs helps troubleshoot media encoding issues.
A JavaFX only solution
Your program embeds JavaFX in a Swing application which is a bit more complex then just playing Media in a standard JavaFX application. Corresponding code for playback of an mp4 in a standard JavaFX application is supplied in my answer to: Can't play mp4 converted file - JavaFX 2.1. Using just JavaFX is recommended unless you have a specific need for Swing (such as embedding your JavaFX based media player inside an existing large Swing application).
Oracle provide a good tutorial for Incorporating Media Assets Into JavaFX Applications.
The JavaFX media package description documents the media playback encodings, containers and protocols which JavaFX supports.
Sample for playing back mp4 video from a Swing App using a JavaFX MediaPlayer
Note the sample only catches a subset of the possible media errors. For a code template which can catch and log all media errors see the JavaFX media error handling documentation.
import javax.swing.*;
import javafx.application.Platform;
import javafx.beans.value.*;
import javafx.embed.swing.JFXPanel;
import javafx.event.*;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.VBox;
import javafx.scene.media.*;
import javafx.util.Duration;
public class VideoPlayer extends JFrame {
public static final String VID_URL =
"http://static.clipcanvas.com/sample/clipcanvas_14348_H264_320x180.mp4";
private static final int VID_WIDTH = 320;
private static final int VID_HEIGHT = 180;
private static final int PLAYER_WIDTH = 320;
private static final int PLAYER_HEIGHT = 265;
private void play(final String url) {
final JFXPanel panel = new JFXPanel();
Platform.runLater(new Runnable() {
#Override public void run() {
initFX(panel, url);
}
});
this.add(panel);
this.setSize(PLAYER_WIDTH, PLAYER_HEIGHT);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
}
private void initFX(JFXPanel panel, String url) {
MediaView mediaView = createMediaView(url);
final Scene playerScene = new Scene(
createPlayerLayout(mediaView),
PLAYER_WIDTH,
PLAYER_HEIGHT
);
setMediaEventHandlers(
mediaView
);
panel.setScene(playerScene);
}
private MediaView createMediaView(String url) {
final Media clip = new Media(url);
final MediaPlayer player = new MediaPlayer(clip);
final MediaView view = new MediaView(player);
view.setFitWidth(VID_WIDTH);
view.setFitHeight(VID_HEIGHT);
return view;
}
private VBox createPlayerLayout(final MediaView view) {
final Button button = new Button("Play From Start");
button.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent event) {
view.getMediaPlayer().seek(Duration.ZERO);
view.getMediaPlayer().play();
}
});
final VBox layout = new VBox(8);
layout.setAlignment(Pos.CENTER);
layout.getChildren().addAll(
view,
button
);
layout.setStyle("-fx-background-color: linear-gradient(to bottom, derive(lightseagreen, -20%), lightseagreen);");
return layout;
}
private void setMediaEventHandlers(final MediaView view) {
final MediaPlayer player = view.getMediaPlayer();
System.out.println("Initial: " + player.getStatus());
player.statusProperty().addListener(new ChangeListener<MediaPlayer.Status>() {
#Override
public void changed(ObservableValue<? extends MediaPlayer.Status> observable, MediaPlayer.Status oldStatus, MediaPlayer.Status curStatus) {
System.out.println("Current: " + curStatus);
}
});
if (player.getError() != null) {
System.out.println("Initial Error: " + player.getError());
}
player.setOnError(new Runnable() {
#Override public void run() {
System.out.println("Current Error: " + player.getError());
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override public void run() {
VideoPlayer player = new VideoPlayer();
player.play(VID_URL);
}
});
}
}
SOLVED!
Nice to see that original poster was able to get video playback working and the final error was just using an old JavaFX version (2.0) which does not support mp4 playback. Updating to JavaFX 2.2+ (which does support mp4 playback) fixed the issue.
I am trying to pack my project into runable jar file , and i got this error:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at javax.swing.ImageIcon.<init>(Unknown Source)
at eBridge.LoginPage.initialize(LoginPage.java:66)
at eBridge.LoginPage.<init>(LoginPage.java:55)
at eBridge.LoginPage.<init>(LoginPage.java:49)
at eBridge.eBridgFrame.<init>(eBridgFrame.java:37)
at eBridge.eBridgFrame$1.run(eBridgFrame.java:24)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
My main method is on a class calss eBridgFrame , and itz running base on tabs... here is the eBridgFrame class:
package eBridge;
import javax.swing.SwingUtilities;
import java.awt.BorderLayout;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JFrame;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.WindowEvent;
import javax.swing.WindowConstants;
public class eBridgFrame extends JFrame {
private static final long serialVersionUID = 1L;
private JPanel jContentPane = null;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
eBridgFrame thisClass = new eBridgFrame();
thisClass.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
thisClass.setVisible(true);
}
});
}
/**
* This is the default constructor
*/
public eBridgFrame() {
super();
initialize();
JPanel panel = new LoginPage(this);
this.getContentPane().add(panel);
this.setVisible(true);
}
/**
* This method initializes this
*
* #return void
*/
private void initialize() {
this.setSize(950, 720);
this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
this.setName("EBRIDG");
this.setIconImage(Toolkit.getDefaultToolkit().getImage(getClass().getResource("/eBridge/images/eB.png")));
this.setResizable(false);
this.setMinimumSize(new Dimension(950, 720));
this.setPreferredSize(new Dimension(950, 720));
this.setContentPane(getJContentPane());
this.setTitle("EBRIDG");
}
//Pop up msg to confirm closing by overiding javax.swing.JFrame.processWindowEvent() method
protected void processWindowEvent(WindowEvent e) {
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
int exit = JOptionPane.showConfirmDialog(this, "Are you sure?");
if (exit == JOptionPane.YES_OPTION) {
System.exit(0);
}
}
}
/**
* This method initializes jContentPane
*
* #return javax.swing.JPanel
*/
private JPanel getJContentPane() {
if (jContentPane == null) {
jContentPane = new JPanel();
jContentPane.setLayout(new BorderLayout());
}
return jContentPane;
}
}
Can someone save me ??? Thanks a lot !
It would really have helped if you'd told us which is line 66, but my guess is that it's this:
this.setIconImage(Toolkit.getDefaultToolkit().getImage(
getClass().getResource("/eBridge/images/eB.png")));
It sounds like you just haven't included eB.png in your jar file, or you haven't included it in the right place.
You need to look at below line;
eBridge.LoginPage.initialize(LoginPage.java:66)