Today I have another project that involves the program I have written for work and been working on for well over 6 months. There is a lot of code and classes so I'm going to try to explain the best that I can so you can (hopefully) help me.
Currently my program works by reading a file and allowing a user to make some modifications to that file, then a new file is written. This entire process involves a GUI that is better explained as a series of JOptionPanes, some with imbedded panels.
Here is my goal: Each file uploaded comes with a given number of "batches". My program loops through once for each batch. During a loop each of the relevant JOptionPane GUI's is displayed. When all batches are read the program ends and the file is complete.
I have been asked to add a feature where the entire "project" is inside of a JFrame with a new "upload" button. This would allow the user to run the program multiple times without having to open the JAR over and over again. If they select "Upload" they essentially start the program over.
Here is my main class:
package nachamultifive;
import java.util.ArrayList;
import javax.swing.JFileChooser;
import nachamultifive.Buffered_Reader_Writer.BatchCounter;
import nachamultifive.Buffered_Reader_Writer.FileValidation;
import nachamultifive.Buffered_Reader_Writer.MainWriter;
import nachamultifive.GUIs.FileHandling;
import nachamultifive.GUIs.ReturnBuilderGUI;
public class NachaMain
{
public static JFileChooser saveFile;//The output file save location.
public static JFileChooser uploadFile;//The uploaded NACHA file.
public static int batchTotal;//The total number of batches in the file.
public static ArrayList<String> batchHeaders;//An array of all batch headers.
public static int batchCounter;//The counter that displays the current batch number in sequence.
public static String location;
public static void main(String args[]){
FileHandling fHandling = new FileHandling();//The class that handles upload/save of files.
fHandling.getFile();//Allows the user to upload a file.
fHandling.setDirectory();//Allows the user to choose the save location.
saveFile=fHandling.saveFile;//Sets the file save location as static with the main class.
uploadFile=fHandling.uploadFile;//Sets the uploaded file as static with the main class.
BatchCounter bCounter = new BatchCounter();//The class that handles counting the batches.
bCounter.getBatches();//Counts the total number of batches.
batchTotal=BatchCounter.BatchTotal;//Sets the total number of batches as static with the main class.
batchHeaders=bCounter.batchHeaders;//Sets the batch header array as static with the main class.
MainWriter mWriter = new MainWriter();//The class that handles all writing functions for the new file.
mWriter.writeNacha();//Writes the output file.
location = MainWriter.location;
System.out.println("NachaMain Location=" + location);
FileValidation fValidation = new FileValidation();//The class that handles validating the output ACH file.
fValidation.validateNacha();//Method to validate the ACH file.
ReturnBuilderGUI gui = new ReturnBuilderGUI();//Class used for GUI's.
gui.displayFileOption();//Method used to display the ACH output and error report name.
gui.showSavedErrors();//Method to display the error report.
}
}
Essentially each of the classes calls modifies the input file. Inside of the mWriter class you will see this bit of code:
ReturnBuilderGUI gui = new ReturnBuilderGUI();//The GUI class.
ReturnBuilderGUI.displayGUI();//Calls the GUI to display the initial double list GUI.
Calling that class calls the entire GUI for that loop. (The mWriter class loops for each batch). When the ReturnBuilder class is called this is the basic code layout:
public static void displayGUI(){//Method to display the GUI.
final JButton createReturnButton = new JButton("Create Return");
createReturnButton.addActionListener(new ActionListener(){
public void actionPerformed(final ActionEvent ae){
if(verifyBatch==true){
initialScreenDecisions="NONE";//The user did not choose to add any entry details to the output list.
MainWriter.finishedCounter=true;//The boolean counter to trigger that the return is finished goes to true.
while(MainWriter.entryDetails.size()>0){//Removes all entry details from the input list.
MainWriter.entryDetails.remove(0);
}
while(output.size()>0){//Removes all entry details from the output list..
output.remove(0);
}
JOptionPane.getRootFrame().dispose();
}else {
JOptionPane.showMessageDialog(null, "No batches have been completed!");
}
}
});
final Object[] createR = new Object[] { "Confirm",createReturnButton };
int result = JOptionPane.showOptionDialog(null, getPanel(),"Return Builder", JOptionPane.OK_CANCEL_OPTION,
JOptionPane.PLAIN_MESSAGE, null, createR, "default");
System.out.println(verifyBatch);
//Creates a JOptionPane for the first GUI featuring 7 buttons and 2 lists..
}
The getPanel() method inside of that JOptionsPane calls the panel that has some buttons and lists. Depending on what the user chooses some more JOptionPane's will appear that give the user more options. When they are finished the initial mWriter class will loop again (assuming there are more batches in the input file) and the ReturnBuilder class will be called again restarting the process.
Now, I can't for the life of me figure out a way to make all this happen inside of a JFrame that remains before and after all these other things happen without having to restructure my code.
I don't know if I've given you guys enough information to work with. My only idea right now is that I feel like I need to create a JFrame in the ReturnBuilder class and add the JOptionsPane to it, but then when the ReturnBuilder class is called again later I'm sure the JFrame would just open again and be duplicate.
Any ideas?
It really looks to me that you need to use Cardlayout and flip to the next card at each step. When you are done, reset by flipping to the first card. CardLayout is cyclic, so it will flip to the first card automatically.
public class CardExample extends JFrame {
CardExample() {
JPanel main = new JPanel(new BorderLayout());
CardLayout cl = new CardLayout();
main.setLayout(cl);
for (int i = 0; i < 4; i++)
main.add(new StepPanel(i));
JButton next = new JButton("Next");
next.addActionListener(e -> cl.next(main));
add(main);
add(next, BorderLayout.PAGE_END);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setVisible(true);
}
class StepPanel extends JPanel {
StepPanel(int i){
add(new JLabel("Step " + i));
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new CardExample());
}
}
All of this is instead of JOptionPanes, which is usually more comfortable for a step-by-step user interaction (see, for example, installers). Just customize each of what I called StepPanels and at the end you can use a "load and reset" button instead of "next".
Related
To start with -- I'm not sure, that I have properly formulated the question (I'm new in Java and in making programs with GUI).
It is the following thing, I'm trying to do. I have a window with several similar parameters (numbers are just for distinction between lines and it ist just very simplified example, of what should my GUI be):
Initial Window
Then, by clicking on the "+"-button I would like to add an new line, like here:
Line 35 is added
It should be also possible to delete lines, like here: Line 30 was deleted, by pressing "-"-Button.
As I wrote at the beginning, it is possible, that there was such a question, but I couldn't find anything (probably, because I do not now the keywords or I was looking with a wrong ones).
How such window can be done? The only idea I have is to draw a new window after every +/-.
Addition: Code (not working in the part of changing the number of rows).
import javax.swing.*;
import java.awt.event.*;
public class Test extends JFrame {
public Test() {
setSize(200, 600);
JButton plusButton[] = new JButton[100];
JButton minusButton[] = new JButton[100];
JTextField fields[] = new JTextField[100];
JPanel panel1 = new JPanel();
for (int i=0; i<plusButton.length; i++) {
plusButton[i]=new JButton("+");
minusButton[i]=new JButton("-");
fields[i] = new JTextField("Text "+ i);
}
for (int i=1; i<4; i++) {
panel1.add(plusButton[i*10]);
plusButton[i*10].setActionCommand("add after " +String.valueOf(i));
panel1.add(minusButton[i*10]);
minusButton[i*10].setActionCommand("remove " +String.valueOf(i));
panel1.add(fields[i*10]);
}
panel1.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
this.getContentPane().add(panel1);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public void actionPerformed(ActionEvent e) {
for (int i=0; i<100; i++) {
String stand1 = "add after "+String.valueOf(i);
String stand2 = "remove "+String.valueOf(i);
if (stand1.equals(e.getActionCommand())) {
//add "row" of elements
panel1.add(plusButton[i]);
plusButton[i+1].setActionCommand("add");
panel1.add(minusButton[i+1]);
minusButton[i+1].setActionCommand("remove");
panel1.add(fields[i+1]);
} else if (stand2.equals(e.getActionCommand())) {
//delete "row" of elements
}
}
}
public static void main(String[] args) {
Test a = new Test();
}
}
The Problem, that is obvious -- when I want to add 2 rows (i think it is proper definition) of buttons after button 20, there will be an doubling of numbers. As a solution I see here a creation of a new panel for each new row. But it is sounds wrong for me.
P.S. Unfortunately I do not have time to end this topic or to post a working example. I actually found some kind of solution, beginning from the Question here, on Stack Overflow:
Adding JButton to JTable as cell.
So, in case somebody will be looking for such topic, it should sounds like "jButton in jTable".
There are multiple GUI frameworks for Java. First decide which one you wanna use.
As for your particular query
Add functionality to the + and - such that it will create an instance of a field object (that line with parameters as you call them) or destroy that particular instance of the object.
+ is clicked -> Create new object on consecutive line and increase the pointer-count(?) of the following fields.
- is clicked -> Call destructor for the particular object and decrease the pointer-count of the following fields.
I have a basic text based Java app. I want the user to be able to enter sensitive info (password) in a text editing session that only exists for that purpose.
A bit like with git you get a temporary session/file in vi (or another set editor) to edit comment and save/quit - then the git process resumes and consumes that file. The file is (probably) deleted or at least forgotten about.
Do not need any advanced editor capabilities, just basic typing, backspace etc.
I want the user to be able to see what they're typing BUT once they have typed a password, it must be erased from screen. So plain STDIN won't work as the input remains on the screen.
How can I do it in Java or for that matter in another language?
I have looked at Scanner (basically STDIN) and Console.readPassword (user cannot see what they type).
Perhaps a solution that involves STDIN and immediate erasure of the typed line could be acceptable. But emulating git/vi interplay is more attractive because it's arguably a bit more standard.
EDIT: I have implemented something close - create temp file and run notepad.exe on that, let user save and close notepad, read from temp file, delete it. Simple but it relies on an external tool, needs to be adjusted to run on linux as well.. I would like something more seamless where the behaviour is emulated within the java app itself
Swing is pretty consistently available, here is an example of a method that opens a window, waits until the window is closed, and returns the text.
import javax.swing.*;
import java.util.concurrent.LinkedBlockingQueue;
import java.awt.EventQueue;
import java.awt.event.*;
public class EditMe{
LinkedBlockingQueue<String> queue = new LinkedBlockingQueue<String>(1);
public void showEditor(){
JFrame frame = new JFrame("edit text");
JEditorPane pane = new JEditorPane("txt", "");
frame.add(pane);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.addWindowListener( new WindowAdapter(){
#Override
public void windowClosed(WindowEvent evt){
try{
queue.put(pane.getText());
} catch(InterruptedException e){
//not really possible, but just incase.
throw new RuntimeException(e);
}
}
} );
frame.setSize( 640, 480 );
frame.setVisible(true);
}
public static String getText() throws InterruptedException{
EditMe me = new EditMe();
EventQueue.invokeLater( ()-> me.showEditor() );
return me.queue.take();
}
public static void main(String[] args) throws Exception{
System.out.println("waiting for response");
String s = getText();
System.out.println("response received: \n" + s);
}
}
This would be about equivalent to a notepad solution, but it uses swing that comes with standard jdk's. (There are headless jdk's that don't include swing.)
I have a simple GUI that has a jTextField that waits for the user to put in something. After a button is clicked, the program:
reads the input, saves it in a String variable;
opens a new GUI (that is in a separate class file), which contains an empty jLabel, and passes the String variable to it, changing the jLabel text to it.
The problem is that no matter how hard I try to reconfigure the code, adding things like repaint(), revalidate(), etc., the jLabel in the second GUI stays empty. Using a System.out.println(jLabel.getText()) reveals that the text value is indeed changed, but not displayed. How do I "refresh" this jLabel, so it'd show what I want it to? I'm aware I could add an event, though I don't want the user to click anything to refresh the GUI, the values should be there as it's initiated. I've read trough several similar posts, but found that the solutions don't work for me.
The code of first GUI's button click event:
private void sbuttonActionPerformed(java.awt.event.ActionEvent evt) {
errortext.setText("");
Search = sfield.getText();
Transl = hashes.find(Search);
if (Transl.equals("0")) errortext.setText("Word not found in database.");
else {
ws.run(Search, Transl); // <- this opens the second GUI, with two String parameters I want to display in the second GUI;
}
}
The code of the second GUI (activeword and translation are the jLabels that are giving me trouble.):
public void run(String Search, String Transl) {
WordScreen init = new WordScreen(); //initialise the second GUI;
init.setVisible(true);
activeword.setText(Search);
translation.setText(Transl);
}
Any reply is very welcome! Please ask me for more information about the code if necessary, I will make sure to reply as soon as possible!
Best solution: change WordScreen's constructor to accept the two Strings of interest:
From this:
public void run(String Search, String Transl) {
WordScreen init = new WordScreen(); //initialise the second GUI;
init.setVisible(true);
activeword.setText(Search);
translation.setText(Transl);
}
to this:
public void run(String search, String transl) {
WordScreen init = new WordScreen(search, transl);
init.setVisible(true);
}
Then in the WordScreen constructor use those Strings where needed:
public WordScreen(String search, String transl) {
JLabel someLabel = new JLabel(search);
JLabel otherLabel = new JLabel(transl);
// put them where needed
}
Note that I cannot create a comprehensive answer without your posting a decent MRE
As an aside, you will want to learn and use Java naming conventions. Variable names should all begin with a lower letter while class names with an upper case letter. Learning this and following this will allow us to better understand your code, and would allow you to better understand the code of others.
I tried to figure this out myself but I can't. I'm stuck at a strange problem.
I have a Java Program with multiple classes and forms (I use Intellij and the build in GUI-Creator). When I switch from one Screen to another I just call frame.setVisible(false); at the leafing window and frame.setVisible(true); at the window I want to show next.
On a Button Click I make this:
In Class 1:
if (e.getSource() == umschaltenButton) {
this.mainW.goToMainWindow();
logger.log(Level.INFO, "Switched Back to MainMenu");
frame.setVisible(false);
}
And here is the weird part.
In Class 2:
public void goToMainWindow() {
frame = tvElectronics.drawMainWindow(); // I get a new Frame with new Images and so on
frame.addMouseListener(al);
frame.add(BotomPanel); // in here is the JComboBox
frame.setSize(LENGTH, HEIGHT);
comboBox1.removeAllItems(); // Here it tryes to refere to the old frame before i made frame = tvElectronics.drawMainWindow();
Vector<String[]> content = tvElectronics.getContent();
for (int i = 0; i < tvElectronics.getAnz(); ++i) {
comboBox1.addItem((i + 1) + ". " + content.get(i)[3]);
}
comboBox1.setSelectedIndex(chanel);
frame.setVisible(true);
}
And so it tries to update the old frame from class2 which no longer exists because of the new one I just created. And so I have 2 frames open: one as I want it and one strange old frame form class2.
My problem is that I want bind my JComboBox to a new Frame and update it but it is still connected to the old one and that causes weird problems like jumping back in the function. I mean it is at the last line of goToMainWindow() and then it starts again at the first line.
First off you should avoid swapping JFrames as your program does since this is a very annoying GUI design. Please read The Use of Multiple JFrames, Good/Bad Practice? for more on this.
Next, it's impossible for us to tell what GUI view your JComboBox is associated with.
But having said that, it really shouldn't matter. Instead of doing what you're doing, I would give the display class that holds a JCombBox a public method that you call on the containing display class that clears the contained JComboBox's model or that places items in the model. This way, there will be no ambiguity as to which JComboBox you're referring to, and this way you avoid directly exposing a view's inner components.
As an aside, I try to gear my display or view classes towards creating JPanels, not JFrames as this will give my code much greater flexibility.
For example
// my display class
class Display1 {
private DefaultComboBoxModel<String> myModel = new DefaultComboBoxModel<>();
private JComboBox<String> myCombo = new JComboBox<>(myModel);
public void removeAllComboElements() {
myModel.removeAllElements();
}
public void addElement(String ele) {
myModel.addElement(ele);
}
}
Same for your Display2 class. Then you can call the correct method on the JComboBox that is held by the correct view/display.
This way, when you swap displays, perhaps by using a CardLayout, you can clear the JComboBox in the display that is being shown by calling its own method to clear its own combobox's model.
So I'm working on a little project and I'm looking for the base code for how to do this in JOptionPane. I'm still really new to this side of Java. I'm not looking for a whole lot, I just didn't know where to start.
The program should populate the screen with a JOptionPane window. I need it to be modeled like the picture below. The bottom row is a text input from the user and when they hit the enter key, the text should "refresh/clear" and then the middle string area should populate with both the user input and then just below it the result of an if statement according the the code.
for example: The user enters in: "Hello".
Then the text input should refresh and the grey box should do this: "User: Hello."
"Computer: Hello user".
I would really appreciate any and all help on this.
You don't System.out.println() into a gui component. Doesn't work like this. You can write a console program and use JOptionPanes to get user input, but the output would be used in the console program. You would need to create a gui program mimic a console.
Here's a basic layout to start you off
public class Game extends JFrame {
JTextArea jta = new JTextArea(10, 30);
JTextField jtf = new JTextField(30);
public Game(){
add(jtf, BorderLayout.SOUTH);
add(jta, BorderLayour.CENTER);
jta.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
}
});
}
public static void main(String[] args){
SwingUtilities.invokeLater(new Runnable(){
public void run(){
JFrame frame = new Game();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
});
}
}
What I would suggest is since this is a very basic program, I would use an array of String commands and iterate through them.
For example:
String[] question = {"Do you want to go to school?",
"Do you want to drive or walk?"};
jta.setText(questions[0]);
Then in your actionPerformed get the answer from the text field. Use an if statement like
if (jtf.getText().equals("yes") {
jta.append(questions[1]);
}
And so on. If you have no idea what I'm talking about, I would really consider using the Swing tutorials I mentioned. There's a lot of info in those tutorials.