So I am trying to run a code, open a GUI window, choose between two buttons, which set a value and then with this value continue the rest of the code.
I have seen similar questions or Tutorials, but I do not find the suitable solution for my problem.
As I have already seen, JFrame, ActionListener and ActionEvent have to be used in order to make a GUI with a button.
An Object which extends JFrame and implements ActionListener is writen in the main method.
The Problem is, that the code writen in the main method opens the GUI window and continues to run. I just want that the code waits till the user clicks a button and then continue.
A sub-solution is, to write the code that I want in the actionPerformed method but:
The GUI window remains open, after the selection of a button
It makes no sense to me to write the rest of the code in the actionPerformed method.
Or to write a while loop until a button is clicked. A more sensible solution has to exist that I am not aware of or I do not understand the way this should work.
Here is a part of the code.
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == testStringA) {
setVariableTo = "testString_a";
try {
runMethodWithNewVariable(setVariableTo);
} catch (IOException e1) {
e1.printStackTrace();
}
System.exit(0);
} else {
setVariableTo = "project";
try {
runMethodWithNewVariable(setVariableTo);
} catch (IOException e1) {
e1.printStackTrace();
}
System.exit(0);
}
}
Instead of a JFrame, why don't you use a JOptionPane (showOptionDialog) with two buttons, "string A" and "project" instead of "Yes" and "No", for example?
JOptionPanes like "show Option Dialog" are intrinsically blocking. If you put one in your main() method, execution will "wait" for the user to select something in the dialog and the dialog will return an indicator to what was selected before execution in main() continues.
At the begining of your program, show a modal JDialog to the user! You can do this using JOptionPane.show() methods, like this:
String[] buttonTexts = {"first","second"}; //create the button texts here
//display a modal dialog with your buttons (stops program until user selects a button)
int userDecision = JOptionPane.showOptionDialog(null,"title","Select a button!",JOptionPane.DEFAULT_OPTION,JOptionPane.PLAIN_MESSAGE,null,buttonTexts,buttonTexts[0]);
//check what button the user selected: stored in the userDecision
// if its the first (left to right) its 0, if its the second then the value is 1 and so on
if(userDecision == 0){
//first button was clicked, do something
} else if(userDecision == 1) {
//second button was clicked, do something
} else {
//user canceled the dialog
}
//display your main JFrame now, according to user input!
You basically have two threads running - the main thread and the GUI thread. You don't explicitly create the GUI thread but it is there.
You can use a number of techniques to synchronise these two threads. The most basic is the good old synchronized, wait and notify. Something a Semaphore can also be used. In the main thread you would create the GUI and wait until a condition is met. In the GUI thread (i.e. actionPerformed) you would notify.
Related
I'm writting a console interface for a small program I'm doing. I display something like this on the console:
Please select:
1)Add user
2)Delete user
3)Edit user
The method it self should listen for a button push, and if that button push is one of the digits 1,2 or 3 it should call some other method and clear all the text from the console. Something like this:
display the above info
if(button is not pushed)
do nothing
else if ( button == 1)
call method addUser and clear everything on the console, so that addUser
can display it's info
I know the question does not contain any code, but I have no idea how to do this. I know there should be some kind of button listener, but have no idea what to use and how. Any help is welcomed :)
You'll have to add an event listener to the button(s), and when that specific button is clicked, you call the required methods.
If you're not familiar with event listeners, I strongly suggest you check out https://docs.oracle.com/javase/tutorial/uiswing/events/intro.html and related pages on the official documentation portal.
Hope this helps.
This code can guide you to your solution. Use BufferedReader to read from console and check codes for buttons which was pressed, and depending on them, call the appropiate methods.
public static void main (String[] args) throws IOException {
BufferedReader bufferRead = new BufferedReader(new InputStreamReader(System.in));
System.out.println("Hit 1, 2 or 3");
int buttonCode = bufferRead.read();
System.out.println("Code of button hit is: "+buttonCode);
//Button Codes for 1, 2 and 3 keys are 49, 50 and 51 respectively
if (buttonCode==49) {
//DO insert user
} else if(buttonCode==50) {
//Do delete
} else if (buttonCode==51) {
//Do Edit
} else {
System.out.println("Wrong button pressed");
}
}
Okay, so our assignment is to create a Guessing Game where the user inputs a number and the text foreground is supposed to change to either red if it is too high, blue if it is too low, or green if it is exact.
Our teacher has posted code that does that, and it is quite simple and I can understand it. Problem is, when I try to reformat it for what I need I get the JFrame, I get the text field where I can input it, but when I click submit it just like freezes. I suppose it has to do with how the action listener is written, but I am not sure.
Any help would be appreciate.
Here's my code, edited so just that specific part is shown"
button.addActionListener(
new ActionListener()
{
#Override
public void actionPerformed(ActionEvent arg0)
{
userInput = keyboard.next();
if(Integer.parseInt(userInput) > randomNumber)
{
tf.setForeground(Color.red);;
}
else if(Integer.parseInt(userInput) < randomNumber)
{
tf.setForeground(Color.blue);
}
else if(Integer.parseInt(userInput) == randomNumber)
{
tf.setForeground(Color.green);
}
}
}
);
}
while(true)
That's the problem. Don't block the EDT (Event Dispatch Thread). The GUI will 'freeze' when that happens. See Concurrency in Swing for details and the fix.
so I have this part of my code (I cannot post everything because it's just too long and so far this is the only problem with it). Our professor assigned us to make our own Assembler just like MARIE and we are having a trouble with these lines of code:
else if(get.charAt(0)=='B')//input
{
inputfield.setEditable(true);
//INSERT LISTENER HERE!
AC.setText(inputfield.getText());
System.out.println(""+col);
//insert action here - HALP
}
The entire thing gets a value from a table sort of like an Instruction in Hex and if the Intruction starts with B like B000 then it will toggle the input textbox which is named inputfield. It works fine but we need to add a key listener in the part where it says //INSERT LISTENER HERE! for when the user will press enter the AC.setText(inputfield.getText()); will be executed. How should we do it? I mean we tried actionListener but it sort of stops the loop unless another button is clicked. We need another way that when the user presses enter it automatically resumes the execution.
Thank you.
Add action listener to textfield. ActionEvent will occur when you press Enter while editing in textfield.
JTextField field = new JTextField();
field.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// action to perform when one hits "Enter"
}
});
public void actionPerformed(ActionEvent e) {
String sp1="Player 1's turn. ";
String sp2="Player 2's turn. ";
System.out.println("Mouse entered for rating " + index); //helps me track the cards
ori=new ImageIcon(getClass().getResource(index+1+".png")); //set the image to the card
ori.setDescription("ori"); //It's weird that I cannot directly flip the card, so I used this method to flip the cards.
tail.setDescription("tail");//http://stackoverflow.com/questions/13557561/the-method-about-imageicons-does-not-work
if (((ImageIcon) bt[index].getIcon()).getDescription()=="ori")
bt[index].setIcon(tail);
else
bt[index].setIcon(ori);
count++;
System.out.printf("Action Performed %d times \n",count);
if(count==1){ //if the card is clicked for once, the card should not flip and the index is stored in record.
record=index;
countS++;
}
String turnS=Integer.toString(countS);//parse the int and printout the turn
// text3.setText(sp1+"This is turn "+turnS);
if(count==2){
int match1=record/4; //Since every four cards have the same rank, I used this to get the rank very easily
int match2=index/4;
if(match1==match2&&record!=index){ //compare the two cards clicked
p1++;
score1=Integer.toString(p1);
text1.setText("Player 1: "+score1); //display the score
text3.setText(sp2+"This is turn "+turnS);
bt[index].setEnabled(false);//remove the cards that match
bt[record].setEnabled(false);
}
if(record==index){
text3.setText(sp2+"This is turn "+turnS);//designed for the situation that the user clicks the same card
}
if(match1!=match2){//designed for the situation that the two cards do not match
//time.schedule(taskFlip1,500);//delay the flip so that the user can see the cards
//time.schedule(taskFlip2,500);
try{ **//This part is problematic!**
Thread.currentThread().sleep(4000);
flip(index);
flip(record);
}
catch(Exception ie){
}
}
text3.setText(sp2+"This is turn "+turnS);
}
When I click on the button, the button is supposed to change the ImageIcon. It works fine without the sleep. But after I add sleep, when I click on the button, the program pauses without changing the ImageIcon! Can you tell me why? Thank you!
The actionPerformed() method runs in the event dispatching thread. So does the repaint system. If you sleep, you are deferring painting, and everything else. You should never sleep in this thread. If you want a deferred paint, use SwingWorker or javax.swing.Timer to start a deferred task.
The action is executed by the very thread which also does handle the drawing. You block this thread. You see nothing. Game over.
This is the reason why YOU SHALL NOT BLOCK NOR DELAY THE EVENT-DISPATCHER THREAD.
Searching for the term "Event Dispatcher Thread" and "blocking" you find plenty of stuff explaining the gory details.
ActionPerformed is run in the event-dispatcher thread. Sleeping in there will stop the UI from updating.
You can use a Swing Timer instead to delay an action.
I have an application which opens multiple JIFs, But I only want to create a single instance of the JIF, so I use these function to check that, and I use dispose to close the JIF after a key is pressed(JDesktopPane.getSelectedFrame().dispose()). However after 2-3 successive disposes, it doesn't create a new JIF? Am I doing anything wrong over here?
public static void setInternalFrame(final JInternalFrame internalFrame) {
log.debug("CurActiveInternalFrame " + ShoppyPOSApp.getCurrentActiveInternalFrame(), null);
log.debug("Incoming internalFrame " + internalFrame, null);
boolean isFrameFound = false;
try {
// Have a check whether the DesktopPane contains the internal Frame
// If yes bring it to front and set the focus
for (int i = 0; i < ShoppyPOSApp.frame.mainDesktopPane.getAllFrames().length; i++) {
if (ShoppyPOSApp.frame.mainDesktopPane.getAllFrames()[i].getClass() == internalFrame.getClass()) {
isFrameFound = true;
}
}
if (!isFrameFound) {
internalFrame.setVisible(true);
internalFrame.setLocation(
ShoppyPOSApp.frame.mainDesktopPane.getWidth()/ 2 - internalFrame.getWidth() / 2,
ShoppyPOSApp.frame.mainDesktopPane.getHeight() / 2 - internalFrame.getHeight() / 2
);
ShoppyPOSApp.frame.mainDesktopPane.add(internalFrame);
}
internalFrame.setSelected(true);
} catch (Exception e) {
log.debug(e.toString(), null);
}
}
You are comparing the classes of your input parameter and your desktops internal frames in your for loop. This will always be true as your parameter is an instance of JInternalFrame and the getAllFrames method returns an array of JInternalFrames. Why not just do a regular comparison? :
ShoppyPOSApp.frame.mainDesktopPane.getAllFrames()[i] == internalFrame
I would recommend using HIDE_ON_CLOSE as your default close operation on the frames and using setVisible(false) in your key listener instead of dispose(). When frames are disposed they are closed and you should not try and reuse a frame after is has been closed. If you just hide the frame it will still be a child of the desktop pane so you shoud add a call to setVisible(true) when you find a frame in your setInternalFrame method.
It sounds like you're getting inconsistent behaviour (you say it fails after two or three disposes). This suggests to me that you have an event thread problem. Is your setInternalFrame being called on the event thread? Are you familiar with the Event Dispatch Thread and are you using it correctly?
I don't think dispose is doing what you mean for it to do. dispose gets rid of the operating system "peer" of your frame. But if you intend to show that frame again, then you shouldn't throw away its underpinnings!
I'd go with setVisible(false) on the JIF to hide it. Then you can re-activate it with setVisible(true).