How to return variable from actionPerformed? - java

I'm not looking for direct answers. Just a general direction where I'm supposed to search or little hints, as this is an assignment for a class.
I am supposed to create a game, and in order for the user to start the game, they must enter their name through a JOPtionPane, at the moment, I have coded this:
JButton nameBtn = new JButton("NAME");
nameBtn.setBounds(25, 10, 250, 30);
nameBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String name;
do{
name = JOptionPane.showInputDialog(frame, "ENTER YOUR NAME", "", JOptionPane.QUESTION_MESSAGE);
if(name != null)
;
else
JOptionPane.showMessageDialog(frame, "No name entered");
}while(name == null);
}
});
What I want to do is then display that user entered name unto another panel. How would one go about doing that?

If I am understanding the question correctly, then you want to use the name result from the input dialog and display it in an existing label in the outer class. You can simply create a method in the outer class that takes the name as a String argument and that adds it to any of the components in that outer class. You can call this method from within the ActionListener. Without including the element where the name should end up in your question, I cannot go more specific than this.

Nvm, I found my own answer
// buttons
JButton nameBtn = new JButton("NAME");
nameBtn.setBounds(25, 10, 250, 30);
nameBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String name;
do{
name = JOptionPane.showInputDialog(frame, "ENTER YOUR NAME", "", JOptionPane.QUESTION_MESSAGE);
if(name != null)
;
else
JOptionPane.showMessageDialog(frame, "No name entered");
}while(name == null);
//take user input (name) and assign it into a JLabel, which will be added
to my desired Panel
JLabel userName = new JLabel(name);
botPan.add(userName);
userName.setBounds(400, 20, 55, 30);
}
});

Execution continues uninterrupted immediate on from the call to addActionListener. So the code following the listener registration is executed at the wrong time to receive such a returned value.
The action to be performed should be initiated within the actionPerformed method or methods that it calls. And that's about it. In an anonymous inner class, as used in the question, access is available to the enclosing scope.
As a note of style, listener implementations should usually be short, just removing the necessary information from the event (often only that it happened at all) and calling an uncluttered method that does the useful work.
For tasks that may block the AWT Event Dispatch Thread (EDT), work can be done on another thread. Any resultant manipulation to AWT/Swing object need then be performed with a java.awt.EventQueue.invokeLater call to run on the EDT.
Some methods dealing with modal dialogues, such as presumably showInputDialog, use a hack whereby EDT events are processed within the method call. You can see this in stack traces. Modal dialogues are generally considered poor UI.

Related

Java multiple message dialogs at the same time with focusLost event

The problem is that when i click on the surname field when the name field is empty both messages appear because the focus is lost even from surname when the message dialog appears. Is there anything i can do to make the program show the name message and the focus to stay on the name field?
I tried the .requestFocus() but it didn't work.
private void NameFieldFocusLost(java.awt.event.FocusEvent evt) {
if (NameField.getText().equals('smth')) {
JOptionPane.showMessageDialog(null, "Please put a name!","Error!", JOptionPane.INFORMATION_MESSAGE);
}
}
private void SurnameFieldFocusLost(java.awt.event.FocusEvent evt) {
if (SurnameField.getText().equals("smth")) {
JOptionPane.showMessageDialog(null, "Please put a surname!","Error!", JOptionPane.INFORMATION_MESSAGE);
}
}
First off, in the NameFieldFocusLost event: if (NameField.getText().equals('smth')) { doesn't fly. The equals() method requires a String: if (NameField.getText().equals("smth")) { or better yet...since you want to ensure a name is actually provided:
if (NameField.getText().trim().equals("")) {
There must be something we're not being shown. I don't understand why both MessageBoxes would be displaying when focus is taken away from the nameFieldFocusLost event. This shouldn't happen unless you have code somewhere moving focus around especially before your form is actually visible. The requestFocus() method should work as well and should be called directly after you display the MessageBox, for example:
private void nameFieldFocusLost(java.awt.event.FocusEvent evt) {
if (nameField.getText().trim().equals("")) {
JOptionPane.showMessageDialog(this, "Please put a name!","Error!", JOptionPane.INFORMATION_MESSAGE);
nameField.setText(""); // Clear the JTextField in case a white-space was placed there.
nameField.requestFocus(); // Force focus back onto the JTextField.
}
}
If you are moving focus to a JTextField before the parent container is visible (Form / JDialog) then you could possibly experience your particular problem.
EDIT:
Ahhh...I see the problem, thank you for the comment. Here are a few ways you can get around this dilemma:
Add a condition within the focusLost event for the next
JTextField to be in focus which will force an exit of that event
should the validation of the previously focused JTextField fail.
In your case you have a First Name text field and a Last Name text
field. In the focusLost event for the Last Name field you would have
the very first line of code being:
if (nameField.getText().trim().equals("")) { return; }
This way the remaining event code doesn't get run in the Surname
Lost Focus event unless validation for Name field is successful. The
entire Surname event code may look like this:
private void surnameFocusLost(java.awt.event.FocusEvent evt) {
if (nameField.getText().trim().equals("")) { return; }
if (surnameField.getText().trim().equals("")) {
JOptionPane.showMessageDialog(this, "Please put a last name!","Error!", JOptionPane.INFORMATION_MESSAGE);
surnameField.setText(""); // Clear the JTextField in case a white-space was placed there.
surnameField.requestFocus(); // Force focus back onto the JTextField.
}
}
An other way would be to utilize the InputVerifier
Class.
There is good example of its use in this SO
post.
Don't use the JTextField's Focus Events at all. If there is a button
that will be selected to further processing with the inputted data
then check the validation for all your JTextFields there (in the button's actionPerformed event) and force a
focus upon the field that fails (nameField.requestFocus();) for proper input.

Java showInputDialog select custom text

I have rename dialog for rename file
String renameTo = JOptionPane.showInputDialog(gui, "New Name", currentFile.getName());
it works this way, but I have a problem.
the problem is that I set the default value with the extension of the file
but I just want the file name to be selected.
sample : my file name = yusuf.png
I want select only yusuf like;
There is a lot going on inside JOptionPane, it's one of the things that makes it so powerful, it also makes it a little inflexible to.
Two immediate problems are apparent...
You can't gain direct access to the JTextField been used to get input from the user
The JOptionPane wants to control which components have focus when the dialog is first shown.
Setting up the JTextField is actually straight forward...
String text = "yusuf.png";
int endIndex = text.lastIndexOf(".");
JTextField field = new JTextField(text, 20);
if (endIndex > 0) {
field.setSelectionStart(0);
field.setSelectionEnd(endIndex);
} else {
field.selectAll();
}
This will basically select all the text from the start of the String up to the last . or all the text if no . can be found.
The difficult part now is taking back focus control from the JOptionPane
// Make a basic JOptionPane instance
JOptionPane pane = new JOptionPane(field,
JOptionPane.PLAIN_MESSAGE,
JOptionPane.OK_CANCEL_OPTION,
null);
// Use it's own dialog creation process, it's simpler this way
JDialog dialog = pane.createDialog("Rename");
// When the window is displayed, we want to "steal"
// focus from what the `JOptionPane` has set
// and apply it to our text field
dialog.addWindowListener(new WindowAdapter() {
#Override
public void windowActivated(WindowEvent e) {
// Set a small "delayed" action
// to occur at some point in the future...
// This way we can circumvent the JOptionPane's
// focus control
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
field.requestFocusInWindow();
}
});
}
});
// Put it on the screen...
dialog.setVisible(true);
dialog.dispose();
// Get the resulting action (what button was activated)
Object value = pane.getValue();
if (value instanceof Integer) {
int result = (int)value;
// OK was actioned, get the new name
if (result == JOptionPane.OK_OPTION) {
String newName = field.getText();
System.out.println("newName = " + newName);
}
}
And, crossing our fingers, we end up with something looking like...
Personally, I'd wrap this up in a nice reusable class/method call which returned the new text or null based on the action of the user, but that's me
Isn't there an easier way?
Of course, I just like showing you the most difficult solution possible ... 😳 (sarcasm) ... it's kind of why I suggested wrapping it up in it's own utility class, so you can re-use it later 😉

Java GUI Input Dialogs are showing up twice

I have an assignment for class, and I made a simple accounting program in Java with a GUI. This is my first time working with a GUI in Java, and i'm not that good a programmer.
When the program runs, the user can select five JButtons which when clicked takes them to a new JFrame with some input dialogs, which are saved as Strings and Doubles.
My variables are set to something like
variable = JOptionPane.showInputDialog("TEXTGOESHERE");
My Problem is that after entering values into the dialogs, they will pop up a second time, like in a loop. The user has to enter an input into every dialog twice.
Code for one of the buttons:
pcButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
JFrame pcframe = new JFrame("Choosing a File Menu");
pcframe.setSize(760,500);
pcframe.add( new JPanel()
{
public void paintComponent( Graphics g )
{
super.paintComponent(g);
//ACTION BEGIN-----------------------------------------
The input dialogs which are showing up twice:
compName = JOptionPane.showInputDialog("What is the name of your business?");
firstName = JOptionPane.showInputDialog("What is your first name?");
lastName = JOptionPane.showInputDialog("What is your last name?");
day = JOptionPane.showInputDialog("What is the day?");
month = JOptionPane.showInputDialog("What is the month?");
year = JOptionPane.showInputDialog("What is the year?");
String filename = JOptionPane.showInputDialog("Would you like file 1, 2, or 3? (Type in 1, 2, or 3");
filename = (filename + ".txt");
//Storing File into array
//Calculations
g.drawString("" + compName, 330, 15);
//More drawStrings
//ACTION END-------------------------------------------
}
});
pcframe.setVisible( true );
}
});
modePanel.add(pcButton);
When the pcButton is pressed, the user is supposed to enter their name, file, etc. However, every dialog input shows up twice. I want the inputs to show up just once.
Any help would be greatly appreciated, thanks.
Sorry, but that's all wrong. You should never call JOptionPanes or do anything other than painting from within a paintComponent method. You never have full control over when or even if that method gets called, and your program's perceived responsiveness is partly dependent on how fast that method completes its jobs. So my main recommendation -- get all non-painting code out of that method and into a method that you can fully control.
Myself, rather than throw a bunch of JOptionPanes at the user, I'd create a JPanel that has all the fields that I want the user to fill out, and then show one single JOptionPane that holds this JPanel, and get all the input all at once.
Next, your secondary dialog window should be a true dialog, and for Swing that means a JDialog (or JOptionPane which is a type of modal JDialog) and not a JFrame.

FocusListener callback method doesn't work for separately instantiated objects from same variable?

I'm currently working on the GUI part of our group's first semester exam project, and I ran into a curious issue regarding callbacks and event handling.
A bit off topic: I have googled this SO hard, but have really failed to find any concrete examples of using callbacks in Java, so from what i've gathered... By definition... What i'm doing here is actually a callback (Would be awesome if you could explain why, or point me to a page that explains it thoroughly)
Here's the code:
private FocusListener callback = new FocusListener(){
#Override public void focusGained(FocusEvent e){
if(hasBeenSet){}else{tfield.setText("");hasBeenSet=true;}
} #Override public void focusLost(FocusEvent e){}};
...
tfield = new JTextField("Insert CPR number", 8);
constraint.gridx = 0;
constraint.gridy = 1;
constraint.gridwidth = 2;
panel.add(tfield, constraint);
tfield.addFocusListener(callback);
tfield = new JTextField("Type new password", 8);
constraint.gridx = 0;
constraint.gridy = 2;
panel.add(tfield, constraint);
tfield.addFocusListener(callback);
tfield = new JTextField("Retype new password", 8);
constraint.gridx = 0;
constraint.gridy = 3;
panel.add(tfield, constraint);
tfield.addFocusListener(callback);
When I start up the GUI, it has these three (3) textfields, and the idea is to remove the text when the user focuses on the textfield. This should work for all three textfields, but apparently, whatever textfield you click on, only the last textfield gets set to an empty string. I'm most curious about this since each object is instantiated individually.
The obvious workaround here, is to just rename tfield to like "tfield[1-3]", but would be great if you could humor me with this :)
Also: Please note that all the GUI code is actually inside the constructor. Yes, I know this is completely ridiculous, but our design suggests that all logic and data handling will happen after the constructor has completed... So there shouldn't be any threats here per say, but I don't know if this would somehow conflict the callback method for FocusListener.
Thank you. :)
P.S. For the "Re/type new password" fields, I do acknowledge the JComponent JPasswordField, and that will be changed after this problem is fixed. So no need for the security warning :)
The tfield variable holds the reference to the last instance of JTextField. The way to do what you want is this:
private FocusListener callback = new FocusListener() {
#Override public void focusGained(FocusEvent e){
JTextField jtf = (JTextField) e.getSource();
if(hasBeenSet){}else{jtf.setText("");hasBeenSet=true;}
}
...
Note: as your code reads at the moment, hasBeenSet will be shared across all 3 text fields.
Update:
Java has no support for closures, so when the focusGained runs, it sees the last value of tfield, not the value tfield had when the listerner was installed.
It looks like hasBeenSet is defined as a member of the outer class and as such focusGained is checking the same variable for all 3 textfields. Here is a way of handling what I think you're trying to do:
tfield = new JTextField("Insert CPR number", 8);
tfield.putClientProperty("originalText", tfield.getText());
Then in the focusGained:
#Override public void focusGained(FocusEvent e){
JTextField jtf = (JTextField) e.getSource();
if(jtf.getClientProperty("originalText").equals(jtf.getText())){
jtf.setText("");
}
}
The putClientProperty/getClientProperty methods are defined in JComponent class and so these are available in every Swing GUI component that inherits from JComponent. They store/retrieve an Object given a string. In this case the string "originalText" holds the value originally used to initialize the JTextField. Upon gaining focus, if the field still contains that value, it is set to blank. Likewise, you can perform a similar operation in focusLost where if the field is blank you set it to the value retrieved for "originalText".

Java. How to wait?

I call a class that creates a jframe and waits from user to input some values.
The problem that I experience is that I need to wait these values before to continue.
So the code is something simple like this
Jframe frame= new jframe(); //here I want the program to show the frame and then wait till it will be disposed
// I want a pause here
System.out.println(frame.getvalue);
Till now the only I could do is to froze the frame before can even appear totally.
Any help?
Please keep it simple since I am new to Java.
THANK YOU!
I think you should use JDialog instead of JFrame. Please follow this example
What you're probably looking for is JOptionPane. This is a blocking routine that returns only after the user has entered some value, like so:
public class test
{
public static void main ( String args[] )
{
String input = JOptionPane.showInputDialog(null, "Thing: ",
"Enter Stuff", JOptionPane.OK_CANCEL_OPTION);
System.out.println ( "won't reach until got input");
System.out.println ( "My value: " + input );
}
}
The great thing about it is you can add Components to it, so you aren't limited to a single input field, but it is still blocking. The following would add two JTextField's to the frame:
public class test
{
public static void main ( String args[] )
{
JTextField input_box = new JTextField(7);
JTextField input_box2 = new JTextField(7);
JComponent[] inputs = new JComponent[] {
new JLabel("Thing 1:"),
input_box,
new JLabel("Thing 2:"),
input_box2 };
int rval = JOptionPane.showConfirmDialog(null, inputs,
"Enter Stuff", JOptionPane.OK_CANCEL_OPTION);
if ( rval == 0)
{
System.out.printf ("%s and %s!", input_box.getText(),
input_box2.getText());
}
}
}
Instead of using a JFrame, consider using a JDialog with modality set to true.
When it comes time to add an 'OK' button or something like that, check out JRootPane.setDefaultButton()
well as you know swing components are not thread safe though you can use SwingWorker to make the waiting in background,
It uses the thread way but it creates a new thread for the waiting ,long term operations in general,
instead of pausing the event dispatch thread so the user can interact with the rest of the application or the rest of the application can continue to work while the waiting goes on.
ofcourse you have to define a way for it to stop the waiting.
check out its documentation here http://docs.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html
This will cause the current thread to wait 5 seconds:
try {
Thread.currentThread().wait(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}

Categories

Resources