I´ve been working on a GUI and I´ve run into some problems with a JMenu. The GUI is in a separate class that takes all the actions of the program from the rest of the classes. My problem with using the menu is that I want it to do 2 things: first, to show the correct panels based upon a user choice and second, wait for user input to complete the chosen task.
I´ve arranged it into 13 different if.. else clauses depending on the user choice, this part works correctly with the nescessary input options (panels) shown that the user need to input data.
Part two when the user sees the right panels and wants to input information (int and Strings) is where things don´t go as intended. Instead of waiting for user input and then take actions based on those data the program rushes forward and continues. Since no data is entered, needless to say, the output is not the intended one.
I´ll provide part of the class as it´s quite large.
class Employee implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
if(e.getActionCommand().equals("1"))
{
panelB.setVisible(false);
panelC.setVisible(false);
panelD.setVisible(false);
display.setText(bank.infoBank()); }
else if(e.getActionCommand().equals("2"))
{
panelB.setVisible(true); //Show all panels
panelC.setVisible(true);
panelD.setVisible(true);
label2.setText("Accountnumber: ");
text2.setText("");
display.setText("");
}
...
else if(e.getActionCommand().equals("5"))
{
panelB.setVisible(true);
panelC.setVisible(false);
panelD.setVisible(true);
display.setText("");
if(e.getActionCommand().equals("Ok") && !pNrText.getText().isEmpty()) //This is a JButton that when pressed should send the data to the method
{
if(checkInput(pNrText) == true) //Method to validate input
{
pNr = Long.parseLong(pNrText.getText()); //pNr is an input field
bank.addSavingsAccount(pNr); //this is a method from another class
}
else
{
JOptionPane.showMessageDialog(null, "Only digits permitted!");
}
}
This last part (actioncommand equals 5) is one of the places where the program doesn´t wait for the user to input anything before it continues and thus receives no input at all to process.
This is part of an ATM-program built around different JMenus, in another place where an JRadioButton is used it works as intended but I can´t get it to work using the JMenu and I don´t want to use a JRadioButton with so many choices(13).
Any input greatly appreciated!
/Johan
"This last part (actioncommand equals 5) is one of the places where the program doesn´t wait for the user to input anything before it continues and thus receives no input at all to process."
else if(e.getActionCommand().equals("5")) {
panelB.setVisible(true);
panelC.setVisible(false);
panelD.setVisible(true);
display.setText("");
if(e.getActionCommand().equals("Ok") {
I don't know why you would expect this behavior. This is not a console program where a scanner waits for input. Event driven programming doesn't work like that. One event get's one response. There's no waiting. Everything in the actionPerformed happens exactly once. That means when you press 5, the corresponding if will perform. The OK-if will never be performed because no event will ever reach it because it's trapped in the 5-if. Quickes fix, would be to give the OK-block it's own else-if on the same level as the 5-if
Like I said in my comment. Avoid all these if statement. Add an anonymous listener to each menu item.
okItem.addActionListener(new ActionListener(){
public void actionPerforemd(ActionEvent e) {
}
});
But you can even excel beyond this and use Action. Personally I prefer to go this route for menu items, for a number of reasons.
Also as an aside, you should be using a CardLayout to switch between panels.
Related
This question already has an answer here:
Integrating Swing in a simple text adventure game
(1 answer)
Closed 6 years ago.
I am trying to make a text adventure after a choice is submitted i want it to move to the next method and allow you to press submit again. How would I do this?
private void submitActionPerformed(java.awt.event.ActionEvent evt) {
if (option1.isSelected()) {
one();
} else if (option2.isSelected()) {
two();
} else {
}
}
private void one() {
//Button action here
}
You need to re-align your thinking. It's not the next method that you want to call but rather the next state -- you want to change the state of your model (the logical portion of your program) depending on where the user is and what responses he makes, and change the behavior of the program to the user's responses based on this state. What you don't want to do is to to hard-wire your code as you're currently doing as this will lead to rigid programs, programs that cannot adapt to changes in user selection or changes to the logic of the program itself.
Again, the best solution to your general problem is to gear your program to use the state design pattern where the response of the program to input depends on the state of the model (the object that controls what happens).
If I understand correctly, the same button will be used in the progression of your adventure. If that's the case, you could start by registering a first ActionListener whose actionPerformed() corresponds to one. at the end of that method, you can deregister the listener and register a new one whose actionPerformed implementation is two()
I tried this different ways and none worked. First the explanation:
Picture of the table(gridview):
I have a Table aka (GridView to be specific) which i fill with TextFields.
The right upper triangle can be edited, the bottom one can't.
If the user inputs 1-9 the mirrored field get's the value of 1/(1-9)
The user also has the ability to write 1/(1-9) and the mirrored field get's the value 1-9 (Doesn't matter if the input is 1/9 or the actual number, 0.1111)
The third point is easy, I just used changeListener got both textfields and changed the values. (simple regex: ^[1-9]). This is already done.
I've tried with making if statements with regex checking if it starts with 1 and then 1/ and then 1/(2-9), but it got alot of errors (error that looks something like that =>, I dont' remember the description), it's overly complicated and causes problems later. I also tried that the user can input decimals 0.1111=9 also the same problems.
Is there a listener that I can use that starts when user finished (input is whole). Or how would you tackle the problem?
This should work:
field.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
// what happens after Enter is pressed
}
});
Two common ( but not exclusive ) solutions are to:
1) Have the user press enter/return when done editing the field. You can then run your verification function based on that keypress. ( see here )
2) Have the verification run when the field loses focus. ( see here )
I'm working on a large application with a lot of different windows/frames/panes/tabs, many of which may be open at any time. Requirements call for some hotkeys that give focus to a certain tab in a certain window. I would like to avoid registering a KeyListener with every single window/component that might have focus; as such, I tried the following
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(new KeyEventDispatcher(){
#Override
public boolean dispatchKeyEvent(KeyEvent e) {
if (e.getKeyChar() == '-'){
doTheThing();
return false;
}
return false;
}
});
That first "return false" allows that character to go through to other possible consumers, such as text entry fields. The problem is that the code still fires, and will jerk the user back to the tab in question (potentially pulling them away from what they were doing, if it was another tab in the same window.)
Is there a way to have this code fired globally, EXCEPT if it would otherwise enter into a text panel? (Maybe a way to add a handler that would get it "last" rather than "first" - so it only fires if nothing else is consuming the event?)
I'm pretty new to UI design, so apologies if this is a dumb question, and thanks in advance for the help.
Try using KeyboardFocusManager#getFocusOwner and determine if it's a JTextComponent or not...
if (!(KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() instanceof JTextComponent)) {
//...
}
or some such
I'm trying to build a text based D&D type game, and I'm stuck on how to let the user call a method at any time during the game.
The game will run its course, and if the user decides at any time they want to take a peak at his/her stats, the user will type "character sheet" and all his stats etc. will show.
My only idea to go about my problem is to to use:
if( variable.equals("character sheet"))
callMethod();
but this only works once.
Now even if I put it in a loop, yes, it would let me do it as many times as I want, but it won't execute the rest of the program...
Without the loop it will let me do it once, and execute the rest of the program but will never let the user type Character Sheet and open the method ever again.
/////////////////
import java.util.Scanner;
public class MainGame
{
public static void main(String[] args)
{
Scanner input = new Scanner(System.in);
String characterSheet;
CharacterCreation create = new CharacterCreation();
System.out.println("Choose a race:");
System.out.println("Race List:\nDwarf\nDark Elf\nHalfling\nHuman");
create.stats();
System.out.println("If you want to see your character sheet in the future type 'character sheet'");
characterSheet = input.nextLine();
characterSheet.toLowerCase();
if(characterSheet.equals("Character Sheet"))
create.getStats();
}
}
Well, the big question is: is your game running whatever the user does, or does it run in step with each user action? In the second case, you need a simple loop:
while (isRunning){
getUserInput();
updateGameWorld();
}
If the game runs independently of the user's action, you'll need 2 threads: one that will update the world regularly, and one that will listen to the user inputs and adapt the world to them.
I'd suggest you read about "game loops", but be warned that they usually about drawing graphics in frame, which may dilute their general purpose. But basically you have one game loop that renders the world, and another thread that handles user actions.
My title is somewhat cryptic but I couldn't come up with a clear one.
First, two code snippets to establish a point of reference (hopefully I have no typos):
Input with Scanner
'''
Scanner sc = new Scanner(System.in);
for (int i=0; i<10; ++ i) {
System.out.print("Please input a value:");
String answer = sc.next();
// do something with this string
}
...
Input with JOptionPane:
...
for (int i=0; i<10; ++ i) {
String answer = JOptionPane.showInputDialog("Please input a value");
// do something with this string
{
So, in the above samples we're asking a user to enter a value a fixed number of times. How can I implement the same kind of functionality in a Swing application?
I have no problem creating a JFrame with JPanel (as its content pane) and adding JLabel (with prompt) and JTextField to this panel. I can also create ActionListener for the text field which ActionPerformed method to retrieve the value and process it. String processing is not a long-running task so I do not believe I will need a separate worker thread.
Since we can't really force user to do anything, I plan to use javax.swing.Timer to ensure a timely response.
What I do not understand is how to implement the loop or any other form of control to ensure that a user enters (and the program retrieves) the value the exact number of times. How do I inject such logic into an event-driven system?
Once I set-up the GUI part and submit its instance to be invoked on EDT I seem to be relinquishing all control.
Do I initially submit my text field with setEditable set to false and then create a loop that will invokeAndWait a Runnable to enable the edit (and disable it back in the ActionPerformed)?
Please point me into the right direction.
Well it depends on how you want to achieve it...
You could...
Provide the required number of fields (10 in your example) and a JButton, so that until all the fields are filled out, clicking the button will simply provide the user with a message and re-focus the invalid field...
You could...
Provide the user with a single field (and label) and button. Until they fill out the field, pressing the button prompts them and re-focuses the field.
When the user fills out the required information and clicks the button, you increment a counter, reset the field and carry on until your counter reaches it's limit...
You could...
Use a JTable which has only one column and five rows...this is simplified (depending on your perspective) solution to the first solution...