Passing input from one frame to another(JAVA) - java

Here's the thing...
I have 2 GUI programs.
A Menu Program,which is basically a frame with buttons of food items,the buttons when clicked
opens this other program,an Input Quantity Program,which is a frame with a text field,buttons for numbers,buttons for Cancel and Confirm. The quantity that is confirmed by the user will be accessed by the menu program from the Input Quantity Program to be stored in a vector so that every time a user wants to order other food items he will just click another button and repeat the process.
Now I've coded the most part and got everything working except one thing,the value returned by the Input Quantity Program has this delay thing.
This is what I do step by step:
1)Click a food item in Menu,it opens the Input Quantity window.
2)I input the number I want,it displayed in the text box correctly.
3)I pressed confirm which will do 3 things,first it stores the value of the text field to a variable,second it will call the dispose() method and third a print statement showing the value of the variable(for testing purposes).
4)The menu program then checks if the user has already pressed the Confirm button in the Input program,if true it shall call a method in the Input program called getQuantity() which returns the value of the variable 'quantity' and store it in the vector.
5)After which executes another print statement to check if the passed value is correct and then calls the method print() to show the ordered item name and it's recorded quantity.
Here are the screenshots of the GUI and the code will be below it.
ActionPerformed method of the CONFIRM BUTTON in the Input Quantity Program:
private void ConfirmButtonActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
confirmed = true;
q= textField.getText().toString();
quantity =Integer.parseInt(q) ;
System.out.println("getQTY method inside Input Quantity Interface:" +getQuantity());
System.out.println("Quantity from confirmButton in Input Quantity Interface actionPerformed: "+quantity);
//getQuantity();
}
ACTION LISTENER CLASS of the MENU ITEM BUTTONS in MENU PROGRAM which does step 2 above:
class f implements ActionListener {
#Override
public void actionPerformed(ActionEvent e)
{
inputGUI.setVisible(true);
int q =0;
q=inputGUI.getQuantity(); //call method to get value from Input Program
System.out.println("Quantity inside Menu actionperformed from AskQuantity interface: "+q);
orderedQuantity.add(q); //int vector
textArea.append("\n"+e.getActionCommand()+"\t"+ q);
orderedItems.add(e.getActionCommand()); //String vector
print();
/*
System.out.println("Enter QTY: ");
int qty = in.nextInt();
orderedQuantity.add(qty);
print();*/
}
Here are screenshots of the print statements in the console:
Here I first ordered Pumpkin Soup,I entered a quantity of 1
Here I ordered seafood marinara and entered a quantity of 2
Here I ordered the last item,pan fried salmon and entered a quantity of 3
As you can see the first recorded quantity is 0 for the first item I ordered then when I added another item,the quantity of the first item gets recorded but the 2nd item's quantity is not recorded..same goes after the third item... and the quantity of the 3rd item is not recorded even if the program terminates :(
How can I solve this problem?

I think I see your problem, and in fact it stems directly from you're not using a modal dialog to get your input. You are querying the inputGUI before the user has had a chance to interact with it. Hang on while I show you a small example of what I mean...
Edit
Here's my example code that has a modal JDialog and a JFrame, both acting as a dialog to a main JFrame, and both using the very same JPanel for input. The difference being the modal JDialog will freeze the code of the main JFrame at the point that it has been made visible and won't resume until it has been made invisible -- thus the code will wait for the user to deal with the dialog before it progresses, and therein holds all the difference.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class DialogExample {
private static void createAndShowGui() {
JFrame frame = new JFrame("Dialog Example");
MainPanel mainPanel = new MainPanel(frame);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class MainPanel extends JPanel {
private InputPanel inputPanel = new InputPanel();
private JTextField responseField = new JTextField(10);
private JDialog inputDialog;
private JFrame inputFrame;
public MainPanel(final JFrame mainJFrame) {
responseField.setEditable(false);
responseField.setFocusable(false);
add(responseField);
add(new JButton(new AbstractAction("Open Input Modal Dialog") {
#Override
public void actionPerformed(ActionEvent e) {
if (inputDialog == null) {
inputDialog = new JDialog(mainJFrame, "Input Dialog", true);
}
inputDialog.getContentPane().add(inputPanel);
inputDialog.pack();
inputDialog.setLocationRelativeTo(mainJFrame);
inputDialog.setVisible(true);
// all code is now suspended at this point until the dialog has been
// made invisible
if (inputPanel.isConfirmed()) {
responseField.setText(inputPanel.getInputFieldText());
inputPanel.setConfirmed(false);
}
}
}));
add(new JButton(new AbstractAction("Open Input JFrame") {
#Override
public void actionPerformed(ActionEvent e) {
if (inputFrame == null) {
inputFrame = new JFrame("Input Frame");
}
inputFrame.getContentPane().add(inputPanel);
inputFrame.pack();
inputFrame.setLocationRelativeTo(mainJFrame);
inputFrame.setVisible(true);
// all code continues whether or not the inputFrame has been
// dealt with or not.
if (inputPanel.isConfirmed()) {
responseField.setText(inputPanel.getInputFieldText());
inputPanel.setConfirmed(false);
}
}
}));
}
}
class InputPanel extends JPanel {
private JTextField inputField = new JTextField(10);
private JButton confirmBtn = new JButton("Confirm");
private JButton cancelBtn = new JButton("Cancel");
private boolean confirmed = false;
public InputPanel() {
add(inputField);
add(confirmBtn);
add(cancelBtn);
confirmBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
confirmed = true;
Window win = SwingUtilities.getWindowAncestor(InputPanel.this);
win.setVisible(false);
}
});
cancelBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
confirmed = false;
Window win = SwingUtilities.getWindowAncestor(InputPanel.this);
win.setVisible(false);
}
});
}
public boolean isConfirmed() {
return confirmed;
}
public void setConfirmed(boolean confirmed) {
this.confirmed = confirmed;
}
public String getInputFieldText() {
return inputField.getText();
}
}
So solution: use a modal JDialog.

Suppose i am having two GUI frames f1 and f2. Now by clicking a button on f1 i want to invoke frame f2 and also sending some data from f1(frame class) to f2(frame class).
One possible way is to declare a constructor in f2 which takes the same data as parameters which i wanted to send to it from f1.Now in frame f1's coding just include these statements:
f1.setVisible(false);//f1 gets invisible
f2 newFrame=new f2(uname,pass);//uname and pass have been takenfrom f1's text fields
f2.setVisible(true);
I think this will clear up your problem.

Related

How to update values of a JFrame main after using a JDialog of Java Swing?

I have a main window called MainFrame which is a jForm to which I update the data depending on a timer, but the problem is that I cannot update the data in the same MainFrame after using the jdialog, since I end up creating another duplicate window, but with the data changed, one with the original timer and the other with the new timer, I know that I can close the first window with dispose() and then keep the second, but I would like to avoid changing windows so much
the code with which I create another window when pressing the jDialog button is the following
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
// TODO add your handling code here:
String textoFieldTimer = jTextField1.getText();
int timeUserConfig = Integer.parseInt(textoFieldTimer);
Timer timeDefault = new Timer(timeUserConfig, null);
TokenAccess token = new TokenAccess();
token.access_code = code;
MainFrame mainFrame = new MainFrame(token);
mainFrame.setVisible(true);
mainFrame.timeDefault.stop();
mainFrame.timeDefault = timeDefault;
mainFrame.setUpdateTime(timeUserConfig);
this.dispose();
}//GEN-LAST:event_jButton1ActionPerformed
Is there any alternative to update the window? something like mainFrame.update(); or maybe send the value of the jTextField from the jDialog to mainFrame? since the previous code creates another MainFrame for me.
Method main setLabel and Timer.start/stop
public void setUpdateTime(int timeUserConfig) {
this.timeUserConfig = timeUserConfig;
if (timeUserConfig == 0) {
timeDefault.start();
timeDefault.addActionListener(new java.awt.event.ActionListener() {
#Override
public void actionPerformed(java.awt.event.ActionEvent evt) {
setLabelText();
String timeUserConfigStr = Integer.toString(timeDefaultInt);
tiempoActualizado.setText("Tiempo de Actualizado: " + timeUserConfigStr+"ms");
}
});
} else {
timeDefault.stop();
timeDefault = new Timer(timeUserConfig, null);
timeDefault.start();
timeDefault.addActionListener(new java.awt.event.ActionListener() {
#Override
public void actionPerformed(java.awt.event.ActionEvent evt) {
setLabelText();
String timeUserConfigStr = Integer.toString(timeUserConfig);
tiempoActualizado.setText("Tiempo de Actualizado: " + timeUserConfigStr+"ms");
}
});
}
}
setLabelText is a method set of label
public void setLabelText() {
String humedadStr = String.valueOf(humedad);
String temperaturaStr = String.valueOf(temperatura);
String presionStr = String.valueOf(co2);
temporalHum.setText(humedadStr);
temporalTemperatura.setText(temperaturaStr);
temporalPresion.setText(presionStr);
}
Any help would be appreciated.
Thanks for the update, and I found another solution without using an OptionPane from this question: programmatically close a JPanel which is displayed in JDialog.
I cannot replicate your codings
Start with the MainFrame, assuming you opened the JDialog by clicking on a button and wants to setText() to label lbSomething:
private void btInputActionPerformed(java.awt.event.ActionEvent evt) {
// Open new JDialog when button is clicked
NewJDialog dialog = new NewJDialog(new javax.swing.JFrame, true);
dialog.setVisible(true);
// Get user input from JDialog
String temp = dialog.getInput();
if (temp != null) {
/*
* Perform jButton1ActionPerformed() content here
* Including timeUserConfig, timeDefault and setUpdateTime() here
* so that you don't have to access mainFrame in the JDialog.
*/
lbSomething.setText(temp);
}
}
Then about the JDialog (with simple input detection):
public class NewJDialog extends javax.swing.JDialog {
// Set the variable as class variable
private String textTOFieldTimer;
public NewJDialog(java.awt.Frame parent, boolean modal) {
// default contents
}
#SupressWarinings("unchecked")
private void initComponents() {
// default contents
}
private void btSaveAction Performed(java.awt.event.ActionEvent evt) {
// Check if input correct and whether to disable JDialog
if (tfInput.getText.length() != 0) {
input = tfInput.getText();
// Connect to the whole JDialog by getWindowAncestor()
Window window = SwingUtilities.getWindowAncestor(NewJDialog.this);
// Just setVisible(false) instead of dispose()
window.setVisible(false);
} else {
JOptionPane.showMessageDialog(this, "Wrong Input");
}
}
public String getInput() {
return textToFieldTimer;
}
// default variables declarations
}
Hope this answer helps you well.
Would be better if you displayed the source code, but a simple solution to update values to an existing JFrame is by using setText() and getText().
For example:
String input = JOptionPane.showInputDialog(this, "Nuevo valor");
lbPresionActual.setText(input);
If you created a self-defined JDialog, it is about to transfer the input value when closing the JDialog, and that could be a different question.

Why is my boolean value preemptively being returned?

I am working on a login validator and have a class that checks username and password validity. After checking, a boolean variable (isValidLoginCredentials) is updated in the LoginProxy class, which can be fetched by a get method and used for another purpose. However, the value that is returned by the get method is always the default value that I assigned to isValidLoginCredentials when the class was created. I think the issue is that I am calling the getter method in main() before I have a chance to update isValidLoginCredentials, but I don't understand what changes I should make to stop this. Here is the relevant part of the class and main program.
public class LoginProxy implements ActionListener
{
private JLabel usernameLabel;
private JTextField usernameText;
private JLabel passwordLabel;
private JPasswordField passwordText;
private JButton loginButton;
private boolean isValidLoginCredentials = false;
public void createLogin()
{
/*Here was code irrelevant to the problem I removed*/
loginButton.addActionListener(new LoginProxy());
loginButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
String user = usernameText.getText();//get the username
String pass = passwordText.getText();//get the password
String credentials = user +":"+pass;//creates the string I compare to other valid
//credentials
ConcreteLoginValidator validator = new ConcreteLoginValidator(credentials);
try
{
isValidLoginCredentials = validator.checkLogin();
System.out.println("The credentials are "+isValidLoginCredentials);
}
catch (FileNotFoundException e1)
{
e1.printStackTrace();
}
}
});
}
public void actionPerformed(ActionEvent e)
{
// TODO Auto-generated method stub
}
public boolean getValidity()
{
return isValidLoginCredentials;
}
And here is the main method
public static void main(String[] args)
{
boolean isValidLogin = false;
LoginProxy proxy = new LoginProxy();
proxy.createLogin();
isValidLogin = proxy.getValidity();
if(isValidLogin == true)
{
JFrame frame = MainUI.getInstance();
frame.setSize(900, 600);
frame.pack();
frame.setVisible(true);
}
}
What should I add so that isValidLogin=proxy.getValidity(); returns a value only after I have already entered and checked whether the login credentials are correct?
Going straight to the point, a quick fix is to put the code below:
if(isValidLoginCredentials) {
JFrame frame = MainUI.getInstance();
frame.setSize(900, 600);
frame.pack();
frame.setVisible(true);
}
After this part:
System.out.println("The credentials are "+isValidLoginCredentials);
The code you call on createLogin() just sets the action listener to the button in the UI, hence the code will be executed just when you click on the button.
On the top of that, when you open a window, it starts a separated thread. I don't know the rest of the code, but assuming that when you instantiate the LoginProxy, it opens the login window. But the way you wrote, it will open the window and check the isValidLogin straight away (it doesn't wait you to click the button).
If you want to prove that, you can simply put a System.out.println before and after the proxy.createLogin(). You will realise that both lines will be reached while the UI is rendered.
Using a modal dialog that blocks until it is closed.
Very simplified example:
public class Dialog { // LoginProxy in questions code
private String value = null;
public void show(Window owner) {
var dialog = new JDialog(owner, JDialog.DEFAULT_MODALITY_TYPE);
var field = new JTextField(40);
var okButton = new JButton("OK");
okButton.addActionListener(ev -> {
value = field.getText();
dialog.dispose();
});
var panel = new JPanel();
panel.add(field);
panel.add(okButton);
dialog.add(panel);
dialog.pack();
dialog.setLocationRelativeTo(owner);
dialog.setVisible(true); // this will be blocked until JDialog is closed
}
public String getValue() {
return value;
}
}
called like
public static void main(String[] args) {
var dialog = new Dialog();
dialog.show(null);
System.out.println(dialog.getValue()); // check if valid and open JFrame in questions code
}
Advantage of this solution IMHO: the dialog class (LoginProxy) does not need to know about the main class and main JFrame. It has a clear single function: ask for user input.
the dialog creation is even easier using JOptionPane
In order to guarantee reading a value written in another thread, you must make the field volatile:
private volatile boolean isValidLoginCredentials;
You must also wait until the other completes before reading it. That aspect I leave to the reader.

Java Button Click Counter

I wanted to make a button that every time it is clicked it would increase the variable int score by 1. So far I have added the button and everytime I click it does add one but instead of replacing the old score it writes a new line for each click.
public class ButtonClicker extends JFrame implements ActionListener
{
static int score = 0;
public static void main (String[] args)
{
ButtonClicker run = new ButtonClicker();
run.cole();
} // main method
public ButtonClicker ()
{
JFrame j = new JFrame("Window title");
JButton click = new JButton("button");
j.getContentPane().add(click);
click.addActionListener(this);
j.setSize(450,450);
j.setVisible(true);
}
public void actionPerformed(ActionEvent e)
{
System.out.println("Score: " + score);
score++;
}
public void cole ()
{
}
} // ButtonClicker class
So everytime I click instead of replacing Score:0 to Score: 1 and so on, it adds a new line. Example
Score:0
Score:1
Score:2
etc.
You are printing the result in the terminal itself, you cannot clear the previous line like this, instead use a text box in the frame itself that displays the result.

How can I clear content for an old window and add new info to it?

The question is poorly worded, but I'll try to explain. I've created a vending machine where a window pops up and asks user to enter money. They then move to the main machine window and it displays the number they entered as the amount of money they have. I have a button, 'Add Money' that is supposed to add money to that current amount, but i'm not sure how to do that.
For example, a user enters that they have 2 dollars, then hits the enter key which takes them to the main machine interface that states they have 2 dollars.. The user hits the 'add money' button and types 3, denoting that they have 3 more dollars. That should mean they have 5 dollars, and will be denoted on the main interface that they have 5 dollars.
Code for the money input...
public void actionPerformed(ActionEvent arg0) {
double moneyInput;
String text = mInput.getText();
moneyInput = Double.parseDouble (text);
VendingMachineInterface frame;
try {
frame = new VendingMachineInterface(vendingMachineName, moneyInput);
frame.setVisible(true);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
This is one way to do what you want, but since you did not provide an MCVE this might not be what you were looking for.
public class VendingMachine extends JFrame {
static int amount = 0;
VendingMachine() {
JButton add = new JButton("Add amount");
JTextField moneyInput = new JTextField(8);
JLabel currentAmount = new JLabel("Current amount:");
JLabel amountLabel = new JLabel(String.valueOf(amount));
setLayout(new FlowLayout());
add(currentAmount);
add(amountLabel);
add(moneyInput);
add(add);
add.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String addAmountString = moneyInput.getText();
int addAmount = 0;
try {
addAmount = Integer.parseInt(addAmountString);
} catch (NumberFormatException exp) {
System.out.println("Not a number, amount to add will be 0.");
}
amount += addAmount;
moneyInput.setText("");
amountLabel.setText(String.valueOf(amount));
}
});
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack();
setVisible(true);
}
public static void main(String[] args) {
String initialString = JOptionPane.showInputDialog("Enter initial $");
try {
amount = Integer.parseInt(initialString);
} catch (NumberFormatException e) {
System.out.println("Not a number, initial amount will be 0.");
}
new VendingMachine();
}
}
Notes:
You can use an InputVerifier for the text fields instead of checking the value after it is entered.
You can use the input dialog that I used at the beginning each time the button is pressed instead of having the text field in the main window.
I don't know if this is the best way to accomplish your task, but I've used it before in a similar type of application.
Basically, inside the JFrame I had a JPanel which existed only to switch between other panels using the add() and remove() methods.
I created a ManagerPanel class, which has the following method:
public void switchPanel(JPanel removePanel, JPanel addPanel) {
this.remove(removePanel);
this.add(addPanel);
validate();
repaint();
}
To switch panels, I used the following inside an action event:
((ManagerPanel)this.getParent()).switchPanel(currentPanel.this, newPanel);
Like I said, there might be a fancier solution out there, but this was easy and worked for me.

How to "ignore/discard" Swing UI events when doing data validations on UI?

There's a text field and when lost focus it will validate the inputs, if not passed, print out the error message (to be simple here just has an empty check). And there's a button next to the text field, it will print out the text once click on it.
As I tried, when input some text and then click the button it will trigger both the focus lost event of text field and the event of button. In a other word, it will do the validation first and then print out the input text.
Here comes my question, what is the good approach to prevent printing out the text if the validation not passed? Or is there a way to "ignore" the click event on button if validation not passed?
I tried to use a boolean flag which indicate the validation result and check the flag when perform the action for button, but I do not think it is a good approach. As I know there's an event dispatcher thread in Swing which deal with the events, is it possible I can cancel the events from here?
Below is a piece of code which explain the question:
public class SimpleDemo
{
public static void main(String[] args)
{
JFrame frame = new JFrame("Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel content = new JPanel(new FlowLayout());
frame.setContentPane(content);
final JTextField textField = new JTextField(10);
textField.addFocusListener(new FocusAdapter()
{
#Override
public void focusLost(FocusEvent e)
{
String text = textField.getText();
// do some validation here, if not validated
// do not trigger the event on button.
if ("".equals(text))
{
System.out.print("please input a text!");
}
}
});
content.add(textField);
JButton button = new JButton("Print Text");
button.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
// action performed for button
String text = textField.getText();
System.out.println(text);
}
});
content.add(button);
frame.setVisible(true);
frame.pack();
}
}
I faces similar issue while working on an application. I solved it like below
I created a abstract class ApplicationFrame which every frame in the application extends
public abstract class ApplicationFrame extends JFrame implements ActionListener {
#Override
final public void actionPerformed(ActionEvent event) {
if(validateInput()){
performAction(event);
}
}
/*
* Sub class should override this method to receive any action
*/
protected void performAction(ActionEvent event) {};
/*
* Sub class should override this method to perform validation
*/
abstract protected boolean validateInput();
}
All Frames will now extend this base frame, as below:
public class Frame1 extends ApplicationFrame{
#Override
protected void performAction(ActionEvent event) {
// perform action
}
#Override
protected boolean validateInput() {
// return true or false depending upon the validation results
}
// if you want to add Action Listener, you need to add like this:
btnSomeButton.addActionListener(this);
}
If you need to handle Focus events, you can make ApplicationFrame or the base frame implement FocusListener.
This is my custom implementation to solve the problem, hope this helps.
Make the button disabled on start-up
Upon lost focus, validate the text & enable button only when the input passes validation.
Upon start of text change, disable the button
It's always makes sense to make ui to communicate with user. So you can show "please input a text" as the default text of the textField when nothing is entered by user.
Here is the code for such custom textField:
public class TextFieldWithDefaultText extends JTextField implements FocusListener{
private final String hint;
public TextFieldWithDefaultText (String $text)
{
super($text);
this.hint = $text;
addFocusListener(this);
}
#Override
public void focusGained (FocusEvent $e)
{
if (this.getText().isEmpty())
{
super.setText("");
}
}
#Override
public void focusLost (FocusEvent $e)
{
if (this.getText().isEmpty())
{
super.setText(hint);
}
}
#Override
public String getText ()
{
String typed = super.getText();
return typed.equals(hint) ? "" : typed;
}
}
Write the acttionListerner for your button like this:
JButton button = new JButton("Print Text");
button.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
if(!textField.getText().isEmpty())
System.out.println(textField.getText());
}
});
And ur textField implementation should be :
final TextFieldWithDefaultText textField = new TextFieldWithDefaultText ("please input a text");
Hope this helps :)

Categories