I am trying to write a Java GUI that takes a file containing song information, allows the user to edit it, then outputs the new file with the same name. The file pathway is supplied by a run-time parameter, so the user would run the program like:
java myProgram myFile
This is how I am initializing the file in the main method (I am assuming since the file pathway is input as a run-time parameter, it must be assigned to a variable in the main method. I am not sure if I am correct):
public class SongDatabase extends JFrame
{
public SongDatabase(File file) throws IOException
{
setSize(700, 500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new Panel(file);
this.add(panel);
}
public static void main (String [] args) throws IOException
{
File file = null;
if (args.length == 1)
{
file = new File(args[0]);
}
else
{
System.out.print("No source file entered. Create source file (1 for yes 2 for no)?");
Scanner input = new Scanner(System.in);
int choice = input.nextInt();
if (choice ==2)
{
System.exit(0);
}
else
{
file.createNewFile();
}
}
JFrame frame = new SongDatabase(file);
frame.setVisible(true);
}
}
Upon selecting an "exit" button in the GUI, the program should take the stored data and output it using the same file pathway (basically overwriting the old file). Whatever I try, I can't seem to pass 'file' to the actionPerformed method, where this should be taking place. Based on responses from other questions about passing arguments to the actionPerformed this is what I tried in an attempt to get this to work:
public class Panel extends JPanel implements ActionListener{
...
File myFile;
public Panel(File file) throws IOException {
myFile = file;
...
}
public void actionPerformed(ActionEvent e) {
...
if (source == exitButton) {
try (PrintWriter outFile = new PrintWriter(myFile))
{
for (int i = 0; i < songBox.getItemCount(); i++)
{
Song songOut = songList.get(i);
outFile.println(songOut.getSongName()+ "\t" + songOut.getSongCode()+ "\t" + songOut.getSongArtist()+ "\t"+ songOut.getSongAlbum()+ "\t" + songOut.getSongPrice());
}
}
System.exit(0);
}
}
but that doesn't seem to work. For whatever reason, I get a FileNotFoundException. Are there any better alternatives to passing 'file' to actionPerformed?
Edit: I know it's not the path name or file that is the problem because when the offending code is removed the program imports the file correctly and runs as expected. When debugging the code, myFile does have the correct path so I would think that it should work fine, but it doesn't.
Related
I'm coding a small audio player and need help here; the method fopen() is called by a button press in another class (not the issue here); the problem is that I cannot get the file's path as a string without calling the method.
The playsound() method needs the filepath variable from fopen(), and if I use the String 'path' (initialized after fopen()) it calls the method again.
I ONLY need the 'filepath' variable, but I cannot access it outside of fopen(), or at least not that I know of. Assistance on how I can access filepath without invoking fopen()?
EDIT: Fixed fopen() being set up to return a 'File' instead of a string. Also made some changes to the code; the issue of having fopen() called when it's not supposed to be is fixed, but now it gives me a java.io.FileNotFoundException: when I call playsound() (which, from what I understand, means that the file's path and/or name wasn't even recorded). What else is going on here?
Edit 2: I'm just going to ask another question, seeing as the problem at hand seems to have been answered, and I have an entirely different one on my hands.
package mediaz;
import javazoom.jl.player.*;
import javax.swing.filechooser.*;
import java.io.*;
import javax.swing.JFileChooser;
public class audio {
private String lastfilepath = "";
public String fopen(){
JFileChooser fc= new JFileChooser();
FileNameExtensionFilter filtermp3 = new FileNameExtensionFilter("MPEG-2
Audio Layer III", "mp3");
fc.setFileFilter(filtermp3);
int ret = fc.showOpenDialog(null);
if (ret == JFileChooser.APPROVE_OPTION)
{
File file = fc.getSelectedFile();
String filepath = file.getAbsolutePath();
this.lastfilepath = filepath;
return filepath;
}
else
return null;
}
String path = fopen();
void playsound(){
System.out.println("You pressed play.");
try{
FileInputStream fis = new FileInputStream(this.lastfilepath);
Player playMP3 = new Player(fis);
playMP3.play();
}
catch(Exception e){
System.out.println("Error: '" + e +"'");
}
}
// IGNORE WHAT'S BELOW HERE //
void rewsound(){
System.out.println("You pressed rewind.");
}
void pausesound(){
System.out.println("You pressed pause.");
}
/* void forwardsound(){
System.out.println("You pressed fast forward.");
}
*/
}
Create a String instance variable in audio, and then when you call fopen() store the currently selected file's path in that string.
See code below. Untested, but the idea is here. Also, the formatting of this code is pretty bad, it's hard to read. This is what it should look like (ish).
Edit: Added some comments in the code on general improvements/coding style
Edit: For more info on the try I updated in the code, see: https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html
package mediaz;
import javazoom.jl.player.*;
import javax.swing.filechooser.*;
import java.io.*;
import javax.swing.JFileChooser;
public class audio {
private String filePath = "";
public File fopen() {
JFileChooser fc = new JFileChooser();
FileNameExtensionFilter filtermp3 = new FileNameExtensionFilter("MPEG-2
Audio Layer III ", "
mp3 ");
fc.setFileFilter(filtermp3); int ret = fc.showOpenDialog(null);
if (ret == JFileChooser.APPROVE_OPTION) {
File file = fc.getSelectedFile();
this.filePath = file.getAbsolutePath()
return filepath; // should be file
} else // give me braces please!
return null;
}
// try to stick to camelCase, it is the 'Java' way
void playsound() {
System.out.println("You pressed play.");
// streams implement AutoCloseable, use it
// also, you were not closing fis as it was
try (FileInputStream fis = new FileInputStream(this.filePath)) {
Player playMP3 = new Player(fis);
playMP3.play();
} catch (Exception e) {
System.out.println("Error: '" + e + "'");
}
}
}
Your fopen() method is declared to return a File, yet in the method you return a String. If you returned the file that the user selected, and then stored this reference somewhere, you could ask that file for its path any time you wanted.
Create another method that returns the last filepath determined in fopen(), eg:
private String lastFilepath;
public String fopen() {
// logic for determining filepath
lastFilepath = filepath;
return filepath;
}
public String getLastFilepath() {
return lastFilepath;
}
First of all you should read about scopes in java programming.
What you currently have is a local scope for your variable "filepath". To make it accessible outside its method block you can either return it as the method result or asign it to a instance variable.
In addition please note that your fopen() method currently won't compile cause it is declared to return a File but inside tries to return a String type.
I would recommend the following:
public class foo {
private String filePath;
private void readFile() {
filePath = doReadingHere();
}
private void useFilePath() {
System.out.println(filePath);
// do what ever you like to do with the instance variable filePath
}
}
statsButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
//Return the string "stats" to gameLoop() as cmd
}
});
public void gameLoop(){
Scanner lineScanner = new Scanner(System.in);
cmd = "";
System.out.print(getBoard().printBoard(false));
while (!cmd.equals("quit")) {
System.out.print(">");
Scanner wordScanner = new Scanner(lineScanner.nextLine());
if (wordScanner.hasNext()) {
cmd = wordScanner.next();
if (cmd.equals("board")) {
System.out.print(getBoard().printBoard(false));
} else if (cmd.equals("ships")) {
System.out.print(getBoard().printBoard(true));
} else if (cmd.equals("help")) {
printHelp();
} else if (cmd.equals("stats")) {
printStats();
} else if (cmd.equals("fire")) {
if(fire(wordScanner)) {
printStats();
cmd = "quit";
}
} else if (cmd.equals("quit")) {
} else if (!cmd.equals("")) {
System.out.println(ILLEGAL_COMMAND);
}
}
}
}
What I'm trying to do is that when the user clicks the statsButton, the String cmd in the gameLoop would be changed to "stats". The statsButton and the gameLoop() are located in two different classes. Anyone can give me an idea how to do it? (I've attempted pipedreader/pipedwriter) and I just can't seem to get it right.
*I'm basically trying to make my console application into a GUI application without changing the original console application.
Edit: What I've tried
Class textBased
PipedInputStream in = new PipedInputStream()
public void gameLoop(){
try{
in.connect(GUIclass.out);
Scanner lineScanner = new Scanner(in);`
Class GUIclass
PipedOutputStream out = new PipedOutputStream();
PrintWriter writer;
public GUIclass(){
final PrintWriter writer = new PrintWriter(out);
statsButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
writer.println("stats");
}
});
that's what I tried writing but it doesn't seem to work.
Regarding
I'm basically trying to make my console application into a GUI application without changing the original console application..."
My advice is simple: "don't do it".
The two applications have completely different structure, one being linear, the other being event-driven, and are not directly translatable to each other. Better to make a new GUI program from the ground up. Now if your non-GUI application contains some well-structured and behaved object-oriented classes, then by all means use those classes in your GUI's "model" or logic section, but don't try to directly translate the program flow of one type of application to the other.
Edit
Based on your posted requirements:
"You should be able to play your Battleship game through your GUI interface. In addition, the text-based front-end you wrote for project 1 should still "work" and be playable."
Correct me if I'm wrong, but I'm betting that you have several classes involved here, and only one of them is the "text-based front-end". If so, then use the non front-end classes as the model of your GUI as I suggested above, but do not use the text-based front-end for anything GUI related, and do not try to emulate it in your GUI.
Have the console application instantiate the button ActionListener and pass it to the UI. When the action event is fired, the listener will tell the console app that it happened. The method in the ActionListener will tell it what to do.
I agree with Hovercrafts comment (changed to a reply).
But in general for problems like this I would change the method signature of your gameLoop(). I would use:
public void gameLoop(Reader reader)
Then you can pass different types of readers to the loop depending on the requirement.
For a console you might do something like:
gameloop( new InputStreamReader( System.in ) );
For a GUI you could do something like:
gameLoop ( new StringReader("some text") );
Edit:
Without changing the method signature you can redirect System.in to come from the String retrieved by the ActionListener:
public class Test
{
public static void main(String args[]) throws Exception
{
String text = "some text";
System.setIn( new ByteArrayInputStream( text.getBytes() ) );
// gameloop();
Scanner lineScanner = new Scanner(System.in);
System.out.println( lineScanner.nextLine() );
}
}
If you have something like this :
class B {
public void gameLoop(){
..
}
}
and
class A{
statsButton.addActionListener(new ActionListener() {
...
});
}
You can declare reference to B in A with final . In that case it's will be visible in inner class ActionListener.
class A{
final B b = ...; //final variable is visible in inner class
statsButton.addActionListener(new ActionListener() {
b.gameLoop();
...
});
}
I'm making a program that adds and formats files. I actually have many classes, but for the purpose of this question let's say I have two, guidialog and guimain.
In guidialog I have a JTextField and an actionlistener for it. Here is the actionlistner:
public void actionPerformed(ActionEvent event) {
blockName=textFieldBlockName.getText();
System.out.println("Made new block: "+blockName);
canClose=true;
guimain blockAddWrite = new guimain();
blockAddWrite.addNewBlockFile();
}
});
public String blockName;
Now in guimain I have a formatter which writes a file based on the name given in the text field:
public void addNewBlockFile() {
blockdialog blockName = new blockdialog();
try {
newBlock = new Formatter("Block" + blockName.blockName + ".java");
System.out.println("Created File: Block" + blockName.blockName);
} catch (Exception e) {
System.out.println("ERROR: Could Not Output Block File");
}
}
I do edit and close the file, but it wasn't necessary. But when I try this, all of the stuff in guimain that refers to blockName outputs as "null". I can't figure it out.
That's because in guimain, you're not using the blockName field of the dialog where the user entered something: you're using the blockName field of another, newly constructed dialog:
public void addNewBlockFile() {
blockdialog blockName = new blockdialog();
^--- the dialog is not the one where the user entered something. It's a new one.
You should pass the blockName from the dialog to the guimain:
public void actionPerformed(ActionEvent event) {
blockName=textFieldBlockName.getText();
System.out.println("Made new block: "+blockName);
canClose=true;
guimain blockAddWrite = new guimain(blockName); // we construct a guimain instance with the entered text
blockAddWrite.addNewBlockFile();
}
});
Side notes:
you should not use public fields. Use getter methods.
classes should be start with an upper-case and be spelt in CamelCase: GuiMain.
I have made one preference page whose programming is:
public class SAML
extends FieldEditorPreferencePage
implements IWorkbenchPreferencePage {
public SAML() {
super(GRID);
setPreferenceStore(RmpPlugin.getDefault().getPreferenceStore());
setDescription("Browse Appropriate files");
}
public FileFieldEditor f;
public FileFieldEditor f1;
public void createFieldEditors() {
f=new FileFieldEditor(PreferenceConstants.P_PATH,
"&Prism.bat File:", getFieldEditorParent());
addField(f);
f1=new FileFieldEditor(PreferenceConstants.P_PATH1,
"&NuSMV Application File:", getFieldEditorParent());
addField(f1);
}
I want to get path of FileFieldEditor f and want this path to run on a button which is embedded on workbench (but programming of that button is in different project on the same workspace).
The button programming which has hard coded path of "prism.bat" file is:
try {
//to clear the console on every click of button
IViewPart view = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().findView(IConsoleConstants.ID_CONSOLE_VIEW);
if (view != null) {
(myConsole).clearConsole();
}
ProcessBuilder pb=new ProcessBuilder("C:\\Program Files\\prism-4.0\\bin\\prism.bat");
pb.directory(new File("C:\\Program Files\\prism-4.0\\bin"));
Process p=pb.start();
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
String in;
while((in = input.readLine()) != null) {
out.println(in);
}
int exitVal=p.waitFor();
if(exitVal==0)
{
out.println("Process Successful");
out.println("Printing on console with Exitvalue =0");
}
else
{out.println("Process failed");
out.println("Exitvalue = 1");
}
}
catch (Exception e)
{
out.println(e.toString());
e.printStackTrace();
}
But I want to fetch file from my preference page FileFieldEditor f and want this path to embed in button programming so that when button is pressed, result is shown.
You need two parts:
Code that initialize the default for the preference
Code that use the current value
To set the default, you use the following code in the Activator:
public class Activator extends AbstractUIPlugin {
#Override
public void start(BundleContext context) throws Exception {
super.start(context);
IPreferenceStore ps = getPreferenceStore();
ps.setDefault(SHOW_IMAGE, true);
}
public static final String SHOW_IMAGE = "showImage";
}
Alternatively, you can use the org.eclipse.core.runtime.preferences extension point...
Note that the code above assume that the type of the preference is Boolean - there are other methods for numbers, strings, etc... A file name is a string.
To use the current value, just use
if (Activator.getDefault().getPreferenceStore().getBoolean(Activator.SHOW_IMAGE)) {
…
}
The following slides contains a little more information...
i write a method to create a form(3 buttons and a textBox), then i call it in main.
but when i run program, before i enter information in the form (method form6 ),
Other commands that are executed! "s4 and ontname chenged in the form".
this is a part of my code:::::::::::
//////////////////////////////////////////////////////////////////////////
public static void main(String[] args) {
System.out.println("*begin main*"); // call form method
String s4= form6(); // s4 is returned by method.
System.out.println("s3333*"+s4);
System.out.println("ont:"+ontname);//it's global }
//////////////////////////////////////////////////////////////////////////
i have 2 questions:::
1--- While the form is running, other commands are executed!
What is their order execution?
2. --- i want to define a button to when i click it,it closes the form.
thanks all.
If I get your code correctly, ontname is either (1) a class member (declared outside a method) or (2) a local variable, which is declared in the method that contains this code snippet.
In both cases there is no need to "return" ontname just because it is not declared inside the anonymous ActionListener instance.
The following example illustrates a typical pattern for this problem:
public void someMethod() {
// ...
button2.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
String filename = File.separator+"c:";
JFileChooser fc = new JFileChooser(new File(filename));
fc.showOpenDialog(null);
File selFile = fc.getSelectedFile();
setOntName(selFile.getPath()); // <-- here we call another method
}
});
// ...
}
void setOntName(String ontName) {
// do something with ontName
}
Alternativly: declare ontName as a static class member (only):
private static String ontName = ""; // <-- accessible from main method
public static void main(String[] args) {
// ...
}
// more methods.
You can't return a value in this Method because the ActionListenerInterface does not allow this. But you can call another method from within the actionPerformed() method and pass the ontname to it.
You can also close the third button in the new method. Or define the third button as final and use it in the actionPerformed() method.
E.g.
button2.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
String filename = File.separator+"c:";
JFileChooser fc = new JFileChooser(new File(filename));
fc.showOpenDialog(null);
File selFile = fc.getSelectedFile();
ontname=selFile.getPath();
System.out.println("filepath: "+ontname); //it works correctly.
anotherMethod(ontname);
}
});
private void anotherMethod(String path) {
//doSomething with the path
//close third button here
}
You could probably define your variable ontname as global, outside of your function:
var ontname = null;
button2.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
// ...
ontname=selFile.getPath();
}
});
// ...
System.out.println("filepath: "+ontname);
If you want to remember the values, then they should be class level variables.
But, generally, you would want to pass these to some other method to do some processing on them (or, say, persist them in a file). You can pass these as parameters to the other method.
(The second one is better in most cases, I don't know much about your app, so I am unable to give one answer)
There are other problems with your code:
You need to check whether the use has clicked the "Ok" or "Cancel" button in the open dialog to decide whether to get the file or not.
String filename = File.separator+"c:"; does not really make sense. Perhaps you meant String filename = "c:"+File.separator; But even this is not very useful. File.separator is for getting the platform specific file separator char (\ in Windows, / on linux) but since you are hard coding c:, you are anyway constrainting your app to Windows. You might want to have a better platform independent way (start at the "default" path, new JFileChooser() without arguments, and then remember the path the user last used, and proceed from there)
If the argument to the showOpenDialog method is your parent frame, then the dialog would be centered on the parent frame, and would, in most cases, look nicer.
You might also want to relook your variable names.
button2.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
String filename = File.separator+"c:";
JFileChooser fc = new JFileChooser(new File(filename));
int option = fc.showOpenDialog(null);
if(option = JFileChooser.APROVE_OPTION)
{
File selFile = fc.getSelectedFile();
String ontname=selFile.getPath();
System.out.println("filepath: "+ontname); //it works correctly.
doSomeOperation(ontname); //Or, declare ontname as a class level variable.
}
}
});