Java button display code not working - java

I'm new to Java and I'm learning it for my computing coursework in college.
I have a button which is initially set to off(btn_state = false) while it displays the "off.png",
when the button is pressed I want the boolean var "btn_state" to set to true and display "on.png" and that if I press the button while it's set to true I want it to to set to false and display the "off.png"
If you didn't get what I said basically:
While boolean var button state = off display "off.png"
While state = on display "on.png"
When button is pressed,
if state = true then display "off.png" and set state = false
if state = false then display "on.png" and set state = true
I've tried making the button do as described above but failed D:, it seems pretty simple but I'm somehow incapable of coding it, maybe I'm just being stupid and going the complete wrong way about it lol, sorry if my explanation is still unclear :P
Here is the actual code:
JButton Gravity_btn = new JButton("");
boolean Gravity_btn_state = false;
while (Gravity_btn_state = false) {
Gravity_btn.setIcon(new ImageIcon("off.png"));
}
while (Gravity_btn_state = true) {
Gravity_btn.setIcon(new ImageIcon("on.png"));
}
Gravity_btn.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("Button has been pressed");
// I want it so that if "on.jpg" is showing and button is pressed then display "off.jpg" & vice versa
}
});

You are going about this in completely the wrong way.
Swing uses an Event Dispatching Thread (EDT), which calls methods to handle any generated events (including user button presses). When (and only when) those methods have returned control to the EDT will "painting" occur, which will redraw the user interface, including the any new icons on buttons.
while (Gravity_btn_state == false) {
Gravity_btn.setIcon(new ImageIcon("off.png"));
}
This loop will never end, locking up the user interface, and causing the application to never draw anything ever again. Nor will it respond to any user inputs. The button state cannot be changed, because control never returns to the EDT to accept new input from the user. And the UI will never be drawn because control never returns to the EDT.
What you want is to install an ActionListener on the button. When the button is clicked, the ActionListener will be invoked. In that listener, you would toggle gravity.
Since you've talking about gravity, you probably want things moving on the screen, being pulled "down". This means you want animation. Which, with Swing, means you want a Swing Timer. Again, the Timer would have an ActionListener which will be called when the timer expires (again, only if control always returns to the EDT). That timer should move things (i.e., change x,y variables), and call repaint() on the appropriate surface ... and return control to the EDT. The EDT will see that something needs repainting, and (if the event queue has nothing else in it) send the paint message to that thing, so it can draw itself.
There are plenty of tutorials on the Web for "Swing Animation". Do a search on that to find the tutorials, and try to redesign your application. If you get stuck, you can always return here for additional help.

Related

How to see if a button has been pressed from another class

I have a dilema. This might sound stupid but i have no idea how to do this.
I have a password class and a main screen. My main screen has a button that when pressed pops up the password class. Here is the call to the passwordClass from an actionlistener on my main class.
public PasswordClass login(){
pressMe.setVisible(true);
String player="?";
final String playerT = player;
boolean nameCorrect = false;
final PasswordClass hold = new PasswordClass(null);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
//Turn off metal's use of bold fonts
UIManager.put("swing.boldMetal", Boolean.FALSE);
PasswordClass.createAndShowGUI();
}
});
return hold;
}
the return statement isn't anything related to this I never used it but I had it their for testing purposes. In my password class i have a boolean that tells me if the user input matches the correct login info. i call it worked i run the password class and i had the problem that while the window is popping up my code to check if it worked is running simultaneously. This is a problem because i only want to check if it worked after the user has pressed ok. Here is the code
public void actionPerformed(ActionEvent ae)
{
else if(ae.getActionCommand().equals("Login")){
login();
}
else if(ae.getActionCommand().equals("Press Me To Continue")){
if(PasswordClass.worked){
//worked is a static variable from the PasswordClass class
}
pressMe.setVisible(false);
}
}
So whenever OK is pressed on The PasswordClass JFrame a little button pops up and asks a SECOND time for it to save. I want it to save from the first OK button. The reason i make another button is because i don't know how to stop and wait for the OK button to be pressed. My if loop to check if it worked already returns false automatically before the user presses OK. That is my problem and I am really confused on how to solve it.
Any help? If any more code is needed I will provide it but i think this is enough.
The reason i make another button is because i don't know how to stop and wait for the OK button to be pressed
Use a modal dialog of some kind, see How to Make Dialogs for more details
Conceptually, you want to display a modal dialog, which prompts the user for some information, while blocking at the point in your code that the dialog was made visible. When the dialog is dismissed (for what ever reason), you'll want to check the results from the dialog and take appropriate actions based on what the user did
There needs to be some form of synchronization between the objects (not necessarily related to the statement of that name).
If the code that wants to check the result wants to block until the result is set, you could use a CountDownLatch: the actionPerformed method calls CountDownLatch.countDown() while the other code calls CountDownLatch.await().
On the other hand, if the code checking the result does not want to block, then a simple two-boolean approach would work well. Have one boolean indicate whether the button press complete and the other to tell whether OK was the button pressed.

Why is my Swing application minimizing when I create a dialog?

I have a simple Swing application which runs in full screen mode. My application instantiates a JFrame, which in turn instantiates a JPanel, where all of the drawing is done in the paintComponent method. I also have a MouseListener watching for certain events.
One of those events (clicking on a certain area of the screen) triggers a prompt. Here is my code to show the prompt (keep in mind this comes from within my class that is extending JPanel).
int choice = JOptionPane.showConfirmDialog(this, "Are you sure you want to quit?", "Quit?", JOptionPane.YES_NO_OPTION);
if ( choice == JOptionPane.OK_OPTION ) {
dialogOpen = false;
System.exit(0);
} else {
dialogOpen = false;
repaint();
}
The only trouble is... as soon as this code runs, the entire window disappears. More specifically, it looks like it minimizes itself, because I can click on the Java icon in the taskbar and it pops right back up. But how do I stop it from minimizing itself? All I want to do is display a simple prompt!
I figured it out. Thanks to everyone for their helpful comments (what is it with people and commenting here, by the way? how come people write everything that could go in an answer in the comments instead?)
Rather than calling .showConfirmDialog(this, ...) (where this is my JPanel subclass), I needed to call .showConfirmDialog(parent, ...) (where parent is my JFrame subclass). Then, I added a WindowStateListener on the JFrame to detect state changes and reset the window state.

Toggle "enabled" state of a large number of components in a Java Swing applicaiton

I'm making a level editor for my java game using Java swing.
One of the features is that there is a a togglable button to turn the game on and off to test the level out. The game runs inside a jpanel, then you click the button again to untoggle it, and it turns the game off.
I only want the user to be able to change stuff or push buttons in the swing application when the game is NOT running, when it is running I set the focus to the game component. The only button in the swing application that they should be able push is the toggle button to turn the game back off.
The problem is, I can't think of a good way to do this. Using a recursive function I could easily loop through and find all components and do setEnabled(false), but when the game is turned back off it has no way to know what the previous enabled state was (along other issues, like other components responding to setEnabled being called on other components)
What I think I really need is just some kind of way to just outright "kill" user input into the swing application when the game is running.. But preferablly with a way to click the toggle button again to return the application's state, and the game which is running inside a Jpanel needs to be able to have focus...
Is there any way to do this sort of thing at all without massive amounts of "organizational" code to manage the components in the swing application?
You can place everything in a map, like this.
class ComponentState {
private JComponent component;
private bool on;
// Getters & Setters
}
private Map<String, ComponentState> components = new HashMap<>();
in order to add a new component to your game:
components.add("startbutton", new ComponentState(new JButton, true));
then to add all components to your screen:
for(String key : components.KeySet()) {
ComponentState comp = components.get(key);
if(comp.isOn()) { this.add(comp.getComponent()) };
}
and to disable/activate a component:
components.get("myActivatedComponent").disable(); // disable is a self defined method
You want a disableAll() method that sets every component to a disabled state, and a resetAll() method that will reset every component state back to its previous state. You need to save the status of every component when you disable it, in order to be able to restore it after. That will take O(n) space.
private final Map<JComponent, Boolean> components = new HashMap<JComponent, Boolean>();
public void disableAll(JComponent root) {
components.put(root, root.isEnabled());
root.setEnabled(false);
for (int i=0, n=root.getComponentCount(); i<n; i++) {
JComponent child = (JComponent) root.getComponentAt(i);
disableAll(child);
}
}
public void resetAll(JComponent root) {
boolean status = components.get(root);
root.setEnabled(status);
for (int i=0, n=root.getComponentCount(); i<n; i++) {
JComponent child = (JComponent) root.getComponentAt(i);
resetAll(child);
}
}
Another option is to use a GlassPane and "grey out" an area of components. You would also have to capture and ignore clicks in the pane for the area you don't want a users clicking.
See more with an example in the Java Tutorial here: http://docs.oracle.com/javase/tutorial/uiswing/components/rootpane.html
This write up could also be helpful:
https://weblogs.java.net/blog/alexfromsun/archive/2006/09/a_wellbehaved_g.html

Requesting user input from outside the GUI code, do I need Events or Action to communicate with the GUI in this case?

I'm writing a 2D polygon and physics editor, one functionality is to set a rotation limit for joints.
To use this functionality, the user clicks and drags a line between the joint points which need to receive the limit.
The logic of determining if the pick is valid happens outside of the GUI code.
If a pick is found, I wanted to pop up a JOptionPane.showInputDialog where the user can input the limit.
Thing is, if I do it directly, the program becomes unresponsive, I figure it's because of threading.
I's there a way to define an event listener the GUI can use that doesn't require an actual GUI component?
I want to send an event that also contains a reference to the target object to that component, then telling it that a valid pick has been made and user input is required, and then send the value back via a method of the target object.
I am very inexperienced with Swing.
My hunch is that I might be able to add an ActionListener to the main window, but I don't know how I could address that listener specifically.
As in, how would I need to define an Action that only gets processed by that particular listener?
If that is actually possible, of course.
So far I have only used listeners to let the GUI talk to the logic, not the other way around...
Edit:
The program becomes unresponsive the movement I call
result = JOptionPane.showInputDialog(this,"Enter Limit.");
That just breaks it. Can't even enter anything into the textbox, nor close it, etc.
I figure it's because it spawns a modal dialog that pauses some thread, and calling it from somewhere in the bowels of non GUI code is just not the thing I should do, but I'm too inexperienced to know another way...
Edit2:
I should add that I can use JOptionPane.showInputDialog without any problems if I spawn it, for example, after clicking a button or choosing a popup menu option.
In fact that's how I rename the items I am working with.
But I assume at that point, the dialog is being spawned inside the GUI thread, or this Event Dispatcher queue thing.
The problem with this though is, that this takes visible, interactive GUI components that fire that event.
What I'd like, however, is some sort of component that would spawn JOptionPane.showInputDialog just like a clicked button or context menu would, but without having to be interacted with by the user, but instead by the code.
I guess I could use invisible buttons and emulate mouseclick events, but that's pretty hacky...
Also, I tried spawning Threads and Runnables which spawned the JOptionPane.showInputDialog, but that didn't help either.
Unless I spawn the JOptionPane from a GUI source, everything stalls, and the dialog won't work.
The publisher will have a public add/remove listener, where the subscriber will add itself or be added via another channel to the EventListenerList in the publisher.
You can create your own listener interface that extends EventListener and a function to shoot an event. Below is an example:
import java.util.EventListener;
public interface MyEventListener extends EventListener {
public void myEventOccurred(MyEvent event);
}
You can then create your custom event class, "MyEvent" in the example above like:
import java.util.EventObject;
public class MyEvent extends EventObject {
// customer fields and methods here
public MyEvent(Object source) //more possible args here {
super(source);
//other things here to do what you want
}
}
Now you can have your subscriber implement MyEventListener and override the myEventOccurred(..) method.
Another approach would be to use the SwingWorker class to execute the logic of determining the pick in a dedicated thread without blocking the GUI dispatch thread, and use its callback method to execute the GUI action (open the input dialog).
See : http://docs.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html
(This page has a better explanation of concept than I could write.)
It should be possible for your background thread to spawn a dialog with invokeAndWait():
final double[] result = new double[1];
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
try {
result[0] = Double.parseDouble(
JOptionPane.showInputDialog("Enter value:"));
} catch(NumberFormatException e) {
result[0] = -1;
}
}
}
// ... do something with result[0]
Here I made the result an array just so that it can be final (accessible to the anonymous class) and also mutable.

How to have program wait for a button press in Java

Now, I'm not sure if this is possible or even the best way to accomplish what I'm trying to do, but basically I'm creating a very simple simulation program with a very simple Swing GUI.
After each round of the simulation, some buttons on the interface are enabled for the user to make changes and then the user can press the "continue" button to start the simulation again. The simulation itself is basically a while loop that needs to wait for the user action before continuing. My question is how can I have the program stop and wait until the user presses the "continue" button? Please let me know if there are any more details I can provide if this is unclear!
Edit:
I'm going to add some simplified code here so maybe this will make more sense. The program is in two parts, the simulation class and the view. So the button to be pressed is in the view class while the simulation is happening in its class.
Simulation class:
SimulationView view = new SimulationView(); // extends JFrame
while (!some_condition) {
// code
// need user action via button press here before continuing!
}
Most likely the best way to go is enclose one round of the simulation in a method, that would then be executed from the action listener attached to the button you want.
After edit:
Somebody needs to control the simulation in the first place, so you could do the following:
SimluationClass
{
public int startSim()
{
...
}
}
class SimulationView
{
SimulationClass sim = new SimulationClass();
private void init()
{
JButton button = new JButton("Start");
button.addActionListener(new ActionListener() {
void actionPerformed(...)
{
sim.startSim()
}
});
}
}
Keep in mind though that this will freeze your gui as the sim method will be executed from the event thread.

Categories