Changing a variable in another class without a static variable? - java

in the program that I am writing at the moment, I have 2 JFrames (each in a different class, each has a different purpose, however you could consider the widget frame to be a slave of some sort), one is a main window, and the other is a 'widget' that pops up upon hitting a button in the main window.
I only want one copy of the widget open at one time. I am currently doing this through boolean variables under an actionPerformed action listener. Below is the action listener for the main window.
public void actionPerformed(ActionEvent e) {
if(getOpenWidget() == false){
System.out.println(getOpenWidget()); //test line
widget.initialize(); // please note that the instance "widget" is declared just after "public class MainWindow{" :)
widget.frame.setVisible(true);
setOpenWidget(true);
System.out.println(getOpenWidget() ); // test line
}else{
System.out.println(getOpenWidget());
JOptionPane.showMessageDialog(frame, "There is already an instance of the Booking Widget open.");
}
}
Now the booking widget is open, on the booking widget there is a cancel button. Below here is the action listener for the widget's 'cancel' button.
btnCancel.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
MainWindow ui = new MainWindow();
frame.dispose();
ui.setOpenWidget(false);
}
}
Now, upon hitting my button in the main window again, in theory, the openWidget bool should be false, and allow me to open another window, however in the cancel button action listener, my variable isnt changed. So, am I going about my problem in the right way without making openWidget a static variable?(I should be using getters and setters right?)
What am I doing wrong and what don't I understand about instantiating a new instance of the main window every time I click that button?
Also, my getters and setters are stock standard as follows.
void setOpenWidget(boolean val){
this.openWidget = val;
}
boolean getOpenWidget(){
return this.openWidget;
}

Just pass the reference of MainWindow to the Widget class so that it can update its flag on cancel button.

You are calling setOpenWidget(false) on some other new instance you have created using this line MainWindow ui = new MainWindow();
You should call setOpenWidget(false) using same instance from which you have initialised widget. Pass the reference of MainWindow to widget while creating widget and invoke setOpenWidget(false) using that reference

When you are creating the object of widget within MainWindow you can call it like this:
widget = new Widget(this);
And change the Widget Window Constructor as follows:
MainWindow ui;
public Widget(MainWindow mw)
{
this.ui = mw;
//...initialize btnCancel...
btnCancel.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
frame.dispose();
ui.setOpenWidget(false);
}
});
//..do all other stuffs here...
}

Related

Adapter pattern with Buttons, adaptor class has to know which button was pressed

This is an actionPerformed in a Swing panel with custom buttons from a framework which scrambles their classes so all methods are a():String or b():void and there is no way to make out what it actually is.
I got a compiler error becaus when I inherit this button class the compiler find a():void an a():String which is not allowed in Java. My solution was to use the adapter pattern like this:
public abstract class FactoryButton {
private CustomButton button;
public FactoryButton(int width, int height) {
button = new DynButton();
button.setSize(width, height);
}
public DynButton getButton() {
return button;
}
}
So my FactoryButton has the CustomButton class as a private member. The FactoryButton is the parent of another Button class named FactorySelectionButton
which has an action performed where I used to be able to get the source of the event:
#Override
public void actionPerformed(ActionEvent arg0) {
if (arg0.getSource() instanceof FactorySelectionButton) {
// User selected a factory
selectedItem = ((FactorySelectionButton) arg0.getSource()).getFactory();
// Close the screen, so control returns back to the parent window
cancel();
} else {
// other buttons implementation
}
}
But now since I solved one problem with the adapter pattern I have another the arg0.getSource() no longer gives me the FactorySelectionButton but it now gives a CustomButton which gives me no way to know which custom button is pressed.
The reason for not throwing away the custom button is that I am bound to the framework, I have to use it and the amount of factories can grow so I don't want hardcoded buttons.
So anyone have an idea on how I can fix this?
I found a way around it by looping over all my components and checking whether they have the button I need and they double checking whether it's really an instance of the class I want.
#Override
public void actionPerformed(ActionEvent arg0) {
for (FactoryButton component : components) {
if(component.getButton().equals(arg0.getSource()) && component instanceof FactorySelectionButton)
selectedItem = ((FactorySelectionButton) component).getFactory();
return;
}
//other buttons implementation
}

Make button available after certain time?

So I have a method to create a button. I'd like that button to be activated every 120 (2 min) seconds. Once the button is clicked, the timer is reset.
addButton( new RedButton(TXT_SATURNUP) {
#Override
public void onClick() {
Game.instance.showAd();
Game.instance.wasAnswerCorrect();
}
});
If possible, I'd also like to be able to have a log message. Say...
if ( timerFinished ) {
// log message to screen informing user
} else {
// Button cannot be clicked at this time
}
You can use a Timer. You will have to set it up with an ActionListener that enables your button, and you button click will have to reset your timer.
Given the interconnections I would make a new button class using the template below:
class TimedButton extends JButton implements ActionListener {
private Timer T;
// Override constructors to set up timer
// and disable button (if/as desired)
public void onClick(){
super.onClick();
setEnabled(false);
T.restart();
}
public void actionPerformed(ActionEvent e){
setEnabled(true);
}
}
Then you need a method to start the timer externally, or a way to start the timer internally. You might want to avoid doing this in your constructor, as the timer may run out before you make the button is visible. It all just depends on when the button is first available.
As for the logging you can add it in the above methods or use isEnabled().

Activities in button

where can i insert the class calling here in my code?
what i would like to happen is that when i click the button, the maze.java(the class that i would like to call) would run? ,thanks!
public class Main extends Applet {
Button mazebutton;
Button hexbutton;
public void init() {
mazebutton = new Button("Create a maxe");
hexbutton = new Button ("Create a hexagonal Maze");
mazebutton.setBounds(20,20,100,30);
hexbutton.setBounds(20,70,100,40);
add(mazebutton);
add(hexbutton);
}
}
you need to just makethe code like
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
//here you need to call a function that you need to make
//on "maze.java" that returns the values of each variable
//or starts by launching other function in the same class
//(maze.java) that activates the game
}
});

Seeing if JButton is clicked from parent class

I am working on a project in that I am managing multiple windows in the main class. As you can tell from the title, I have a problem with JButtons in the windows.
The main method will wait for one specific button to be pressed:
public static void main(String[] args){
ButtonWindow bw = new ButtonWindow();
while(bw.buttonClicked() == false);
System.out.println("ok cool");
}
Meanwhile, the button's ActionListener will trigger the boolean d (the one the method buttonClicked() returns) to be set true.
public boolean d = false;
public ButtonWindow(){
JPanel cp;
JButton b;
setContentPane(cp = new JPanel());
cp.add(b = new JButton("Click me"));
b.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
d = true;
}
});
setSize(200, 200);
setVisible(true);
}
public boolean buttonClicked() {
return d;
}
Now, it seems as if the main method is stuck in the while loop. How is this possible, since "d" had been changed (I checked it in with an extra "System.out.println("" + d);" in the button's ActionListener)?
Thanks in advance
Oh, and also, is there any smarter way of doing this? I don't think continuously calling this method is the most practical thing to do, really.
I am managing multiple windows in the main class.
AN application should only have a single JFrame and the main window for the application.
For secondary windows you would generally use a modal JDialog. Execution will not continue until the dialog is closed.
In many cases you can use a JOptionPane to manage the dialog for you. Read the section from the Swing tutorial on How to Make Dialogs for more information.
You should be doing this:
public static void main(String[] args){
ButtonWindow bw = new ButtonWindow();
}
And
public void actionPerformed(ActionEvent e) {
if(e.getSource().getText().equals("Click me"))
System.out.println("ok cool");
}
Second Approach:-
Make your flag variable static, create new thread class, and loop using the thread which continuously checks class flag variable value. You can also make your flag variable an instance variable but in that case, your object ref will have to be shared across threads.

Programmatically Generating Actionevent in Java

I'm making an App. in java , in which there is a Button to which I have added an actionlistener. The ActionEvent it(the button) generates executes some code. Now I want this piece of code to run whenever the app. starts and without pressing the button. I mean, I want to generate the Actionevent (without pressing the button) so that the piece of code the ActionPerformed contains gets executed as the app. start. After that, it may run whenever I press the button.
You can create ActionEvents like any other Java Object by just using the constructor. And then you can send them directly to the component with Component.processEvent(..)
However, in this case I think you are better making your code into a separate function which is called both:
By the ActionListener when the button is pressed
Directly by your application startup code (possibility using SwingUtilities.invokeLater() or SwingUtilities.invokeAndWait() if you need it to happen on the event-handling thread)
This way you don't mix up presentation logic with the business logic of whatever the code does....
Yes it can be done, but it doesn't really make sense, since your goal isn't to press a button or to call an ActionListener's code, but rather to have a common behavior on button press and on program start up. To me the best way to achieve this is to have a method that is called by both the actionPerformed method of the ActionListener and by the class at start up.
Here's a simple example. In the code below, a method disables a button, turns the JPanel green, and starts a Timer that in 2 seconds enables the button and resets the JPanel's background color to its default. The method that causes this behavior is called both in the main class's constructor and in the JButton's ActionListener's actionPerformed method:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ActionOnStartUp extends JPanel {
private static final int PANEL_W = 400;
private static final int PANEL_H = 300;
private static final int TIMER_DELAY = 2000;
private JButton turnGreenBtn = new JButton("Turn Panel Green for 2 seconds");;
public ActionOnStartUp() {
turnPanelGreen();
turnGreenBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
turnPanelGreen();
}
});
add(turnGreenBtn);
}
public void turnPanelGreen() {
setBackground(Color.green);
turnGreenBtn.setEnabled(false);
new Timer(TIMER_DELAY, new ActionListener() {
public void actionPerformed(ActionEvent ae) {
setBackground(null);
turnGreenBtn.setEnabled(true);
((Timer) ae.getSource()).stop(); // stop the Timer
}
}).start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PANEL_W, PANEL_H);
}
public static void createAndShowGui() {
JFrame frame = new JFrame("Foo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new ActionOnStartUp());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Usually, the button action event responds to an external event, to notify the application that the user (or rather something or someone) interacted with the application. If your button executes some code that you want to also execute at application start, why not just place everything at it's proper place?
Example:
public class SomeSharedObject {
public void executeSomeCode() { /*....*/ }
}
Set the button with something like
public void setButtonAction(final SOmeSharedObject obj) {
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
obj.executeSomeCode();
}
});
}
And run at application start with something like
public void initApplication(SomeSharedObject obj) {
obj.executeSomeCode();
}
And, if the code you need to execute takes a while to complete, you might want to use a separate thread inside your actionPerformed button event so your application UI does not freeze up.
Just Call JButton.doClick() it should fire the ActionEvent associated with the JButton.

Categories

Resources