I have a TabbedPane in a class called App and i want to run a method in this class. I added two tabs with a JPanel from the class Login and an empty one. Here is the class:
public class App {
private static JTabbedPane tabbedPane;
public JPanel mainPanel;
public App(){
tabbedPane.addTab("Login", new Login().mainPanel);
tabbedPane.addTab("test", new JPanel());
changeFocus(0);
}
public void changeFocus(int i){
//CODE HERE
}
}
Now i want to run a method called changeFocus() from an outer class. A added an actionListener to the Login class with a constructor like this:
public Login() {
logInButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
App.changeFocus(1);
}
});
}
Now i ask why this doesn´t work and changeFocus() must be static. And if i change it to static why the JTabbedPane cannot be static and throws out an error.
Simply pass App as an argument to Login's constructor:
tabbedPane.addTab("Login", new Login(this).mainPanel);
and then:
public Login(App app) {
logInButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
app.changeFocus(1);
}
});
}
Related
I have two frames in NetBeans 9.0 as frame1.java, frame2.javaand the main class as main.java.
If I declare a public variable in frame1.java as
public String stringName;
and a function fn() which gives the value of stringName in frame1as say "abcd".
When I write this in frame2,
frame1 fm = new frame1();
String str = frame1.stringName;
System.out.print(str);
I get the output as null. But what I require is "abcd".
What am I doing wrong, and what should it be?
Thanks for help!
Edit:
I have linked frame1 and frame2 such that the GUI from frame1 leads to frame2, and so does the value.
Edit 2
The process goes like this:
GUI of frame1 is visible >> based on user's input, function fn() stores the value, say "abcd" in stringName >> a button click in frame1 leads to frame2>> variable str gets the value from stringName >> System.out.print(str) outputs the value as null .
CODE
frame1:
public class frame1 extends javax.swing.JFrame {
public String stringName;
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt){
stringName = jTextField1.getText(); // gets a not null value
}
}}
frame2:
public class frame2 extends javax.swing.JFrame {
frame1 fm = new frame1();
String str = frame1.stringName;
System.out.print(str); //outputs a null value
}
The point ist that you are crating a new Instance (frame1, fm) in your class frame2. So the value from the string in this new Instance is null. You need a reference to your old Instance which you maybe have initialised in your main method?
Something like that:
String str = myOldInstance.stringName;
But you should create getter an setter and make your var private.
But to help you exactly we need more Code.
in this case the best is Listener pattern.
Create interface of listener, which will inform about change text. In class - target of this information - create instance of this listener and return that. In class - source of information - set listener and put on field.
When you want inform of change text, you fire method of listener, and on seconde frame will execute implementation of method.
Below example - I fire on button click.
Any way, field should be private, and add getter and setter. Public fields are bad.
Main class
public class App {
public static void main(String[] args) {
Frame1 f1=new Frame1();
Frame2 f2=new Frame2();
TextListener textListener = f2.getListener();
f1.setListener(textListener);
}
}
Listener
public interface TextListener {
public void onTextPropagate(String text);
}
Frame classes
public class Frame1 extends JFrame{
private TextListener listener;
JButton button;
public Frame1() {
super("Frame1");
setBounds(200, 200, 400, 600);
button=new JButton("Action");
button.setBounds(100, 200, 200, 100);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(listener!=null) {
String text = UUID.randomUUID().toString();
System.out.println("On Frame1:\t"+text);
listener.onTextPropagate(text);
}
}
});
this.add(button);
setVisible(true);
}
public void setListener(TextListener listener) {
this.listener=listener;
}
}
public class Frame2 extends JFrame{
public Frame2() {
super("Frame2");
setBounds(100, 100, 200, 400);
setVisible(true);
}
public TextListener getListener() {
return new TextListener() {
#Override
public void onTextPropagate(String text) {
reactOnChangeText(text);
}
};
}
private void reactOnChangeText(String text) {
System.out.println("On Frame2:\t"+text);
}
}
So what I am trying to accomplish is to add ActionListener to a button which is defined in another class, without breaking encapsulation of this button.
My GUI class:
public class GUI extends JFrame {
private JButton button;
public GUI () {
this.button = new JButton ();
}
public void setText (Text text) {
this.button.setText (text);
}
public JButton getButton () {
return this.button;
}
}
My Game class:
public class Game {
private GUI gui;
public Game () {
this.gui = new GUI ();
this.gui.getButton ().addActionListener (new ActionListener () {
public void actionPerformed (ActionEvent evt) {
play ();
}
});
}
public void play () {
this.gui.setText ("Play");
}
}
Then I call a new Game instance in the Main class.
I would like to get rid of the getter in GUI class, otherwise there is no point in using text setter or setters similar to that.
When I add ActionListener to GUI constructor, I have no access to Game methods than. Is there a solution that I don't see?
Normally when I do this, I add an interface that describes the View (GUI), and then have the view implement that interface.
public interface MyView {
void addActionListener( ActionListener l );
}
And the view:
public class GameGui implements MyView {
// lots o' stuff
public void addActionListener( ActionListener l ) {
button.addActionListener( l );
}
}
Then your main code is free from dependencies on what kind of view you actually implement.
public class Main {
public static void main( String... args ) {
SwingUtils.invokeLater( Main::startGui );
}
public static void startGui() {
MyView gui = new GameGui();
gui.addActionListener( ... );
}
}
Don't forget that Swing is not thread safe and must be invoked on the EDT.
Let the GUI add the action listener to the button, let the Game create the action listener:
public class GUI extends JFrame {
public void addActionListenerToButton(ActionListener listener) {
button.addActionListener(listener);
}
....
}
public class Game {
private GUI gui;
public Game () {
this.gui = new GUI ();
this.gui.addActionListenerToButton (new ActionListener () {
public void actionPerformed (ActionEvent evt) {
play ();
}
});
}
...
}
Alternatively just pass in a functional interface instead of a fully built ActionListener.
I'm trying to separate my Swing GUI from my actual code. In short, I want the user to kick off a process (based on the user's selections); in this case, the JFrame will no longer be needed.
What I couldn't figure out is how to share the user's selection from the GUI.class with the Main.class.
Do you have any advice for me?
Here's my code:
public class Main {
public static void main(String[] args) {
// Show GUI
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
GUI gui = new GUI(templates);
gui.setVisible(true);
}
});
// Kick off a process based on the user's selection
}
}
public class GUI extends JFrame {
private static final long serialVersionUID = 1L;
public GUI(Object[] objects) {
setTitle("GUI");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 350, 100);
setLocationRelativeTo(null);
JPanel cp = new JPanel();
cp.setBorder(new EmptyBorder(10, 10, 10, 10));
setContentPane(cp);
JLabel lbl = new JLabel("Selection:");
cp.add(lbl);
final JComboBox<String> comboBox = new JComboBox<String>(new String[] { "One", "Two", "Three" });
comboBox.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
setVisible(false);
dispose();
// Share the selected item with Main.class
}
});
cp.add(comboBox);
}
}
You could create an object to store the selection result and pass it in to the constructor of the GUI class. Set the selection result in that object before closing the UI and then your Main class could access the value:
public class SelectionResult {
private String selectionResult;
public void setSelectionResult(final String selectionResult) {
this.selectionResult = selectionResult;
}
public String getSelectionResult() {
return this.selectionResult;
}
}
Then, you could modify the GUI constructor like this:
private final SelectionResult selectionResult;
public GUI(Object[] objects, SelectionResult selectionResult) {
this.selectionResult = selectionResult;
...
Create a SelectionResult object in your Main class, and pass it to the constructor of the GUI class. In you GUI class ActionListener, you can then call the setSelectionResult() method with the selected value and that value will be available from the Main class.
You would need to add code to make your main method wait while you are waiting for the value to be set in the UI and then proceed with your logic based on the selection.
A Good way of doing this is use Callback mechanism.
Steps to follow:
create a callback interface
interface Callback {
void execute(Object result);
}
GUI class will implement Callback interface but without providing any implementation
Make GUI class abstract
abstract class GUI extends JFrame implements Callback
Now create an object of GUI class providing actual implementation of Callback interface
Here you can use Anonymous class
GUI gui = new GUI() {
#Override
public void execute(Object result) {
System.out.println("You have selected " + result);
}
};
You can pass any thing in execute() method of Callback.
comboBox.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
setVisible(false);
dispose();
// Share the selected item with Main.class
// Callback
execute(comboBox.getSelectedItem());
}
});
Here Main class is responsible for capturing the response of Callback that is directed by GUI class.
Here is the code:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
public class Main {
public static void main(String[] args) {
// Show GUI
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
GUI gui = new GUI() {
#Override
public void execute(Object result) {
System.out.println("You have selected " + result);
}
};
gui.setVisible(true);
}
});
// Kick off a process based on the user's selection
}
}
interface Callback {
void execute(Object result);
}
abstract class GUI extends JFrame implements Callback {
private static final long serialVersionUID = 1L;
public GUI() {
setTitle("GUI");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 350, 100);
setLocationRelativeTo(null);
JPanel cp = new JPanel();
cp.setBorder(new EmptyBorder(10, 10, 10, 10));
setContentPane(cp);
JLabel lbl = new JLabel("Selection:");
cp.add(lbl);
final JComboBox comboBox = new JComboBox(new String[] { "One", "Two", "Three" });
comboBox.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
setVisible(false);
dispose();
// Share the selected item with Main.class
execute(comboBox.getSelectedItem());
}
});
cp.add(comboBox);
}
}
So I have a class that extends a JPanel and within the constructor I add my JButtons and whatever else I need to add. I also have a MainFrame class that is the container (JFrame) and this class will take an argument from a class called FrameSwitcher (Controller) which will assess what buttons were clicked, and pass the information to the MainFrame
I'm having troubles doing this, I can't find a proper way to do this. I do also wish to maintain the JButtons private and non static.
JPanel example:
public class MainMenu() {
private JButton btnSinglePlayer, btnMultiPlayer;
public MainMenu() {
setLayout(null);
btnSinglePlayer = new JButton("singlePlayer");
btnSinglePlayer.setBounds(320, 25, 275, 130);
add(btnSinglePlayer);
btnMultiPlayer = new JButton("MultiPlayer");
btnMultiPlayer.setBounds(320, 170 , 275, 130);
add(btnMultiPlayer);
}
}
FrameSwitcher:
public class FrameSwitcher implements panelListener { // panelListener is an interface defined else where.
public FrameSwitcher(MainFrame frame) {
// This is irrelevant to the question.
}
#Override
public void gamePanel() {
System.out.println("GamePanel Event: Recieved");
}
#Override
public void mainMenu() {
System.out.println("mainMenu Event: Recieved");
}
#Override
public void scoreBoardPanel() {
System.out.println("scoreBoardPanel Event: Recieved");
}
}
Then my MainFrame:
public class MainFrame extends JFrame implements ActionListener {
private PanelListener panelListener;
private JFrame mainContainer = new JFrame("Game");
private JPanel mainMenu = new MainMenu();
public void start() {
mainContainer(mainMenu);
}
public MainFrame(JPanel frame) {
mainContainer.getContentPane().add(frame);
mainContainer.pack();
// Other methods to initialize the frame
return mainContainer;
}
public void switchFrames(PanelListener panelListener) {
this.panelListener = panelListener; // PanelListener is an interface.
}
public void actionPerformed(ActionEvent e) {
JButton source = (JButton)e.getsource();
if(source == MainMenu.btnSinglePlayer) {
if(panelListener != null) {
System.out.println("Recieved the event approriately.");
}
}
}
}
In this example, it does compile, but doesn't do what it is supposed to. Another thing is I currently have the JButtons as public and static, I don't want that.
In your MainMenu class, you need to add some kind of listener that interested parties can register with, so when some event occurs, they can be notified.
The simplest solution would be to provide a addActionListener method which delegated to each of the buttons. This, however, has may expose portions of the application you don't exposed (a listener now has direct access to the JButton and can do all kinds of nasty things to it).
A better solution would be to create something like a MainMenuListener which had methods like startSinglePlayer and startMultiPlayer
You would then provide a add/removeMainMenuListener method within in your MainMenu class.
Each button would then register there own actionListener and fire the appropriate menu listener event
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.EventListener;
import javax.swing.JButton;
import javax.swing.JPanel;
public class MainMenu extends JPanel {
private JButton btnSinglePlayer, btnMultiPlayer;
public MainMenu() {
setLayout(null);
btnSinglePlayer = new JButton("singlePlayer");
btnSinglePlayer.setBounds(320, 25, 275, 130);
add(btnSinglePlayer);
btnSinglePlayer.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
fireStartSinglePlayer();
}
});
btnMultiPlayer = new JButton("MultiPlayer");
btnMultiPlayer.setBounds(320, 170, 275, 130);
add(btnMultiPlayer);
btnMultiPlayer.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
fireStartMultiPlayer();
}
});
}
public void addMainMenuListener(MainMenuListener listener) {
listenerList.add(MainMenuListener.class, listener);
}
public void removeMainMenuListener(MainMenuListener listener) {
listenerList.remove(MainMenuListener.class, listener);
}
public void fireStartSinglePlayer() {
MainMenuListener[] listeners = listenerList.getListeners(MainMenuListener.class);
if (listeners != null && listeners.length > 0) {
for (MainMenuListener listener : listeners) {
listener.startSinglePlayer();
}
}
}
public void fireStartMultiPlayer() {
MainMenuListener[] listeners = listenerList.getListeners(MainMenuListener.class);
if (listeners != null && listeners.length > 0) {
for (MainMenuListener listener : listeners) {
listener.startMultiPlayer();
}
}
}
public interface MainMenuListener extends EventListener {
public void startSinglePlayer();
public void startMultiPlayer();
}
}
First you have to create an ActionListener like this
class MyActionListener implements ActionListener{
public void actionPerformed(ActionEvent ae){
//do your stuff
}
}
Then call,
yourButton.addActionListener(new MyActionListener());
I am really struggling with making a program that has buttons on it and when a button is clicked, it calls a class to work. I have only been using Java for about 10 weeks now and I get the basics but I have not found any place that gives me an understanding of what I want to do here.
I have tried
public void mouseEntered(MouseEvent e) {
if (e.getButton()== MouseEvent.BUTTON3){
Object triangle;
Frame.class.getClass();
}
}
I have also tried
panel.addMouseListener(new MouseAdapter() {
if (e.getButton()== MouseEvent.BUTTON1) {
Frame.class.getClass(circle); }
Either way I have tried it I usually get an error unable to find object or The method getClass() in the type Objectis not applicable for the arguments (JButton).
Can anyone please help me try to figure out what I am doing wrong?
Thank you.
public class MainFrame extends JFrame {
private JButton button = new JButton("Run AnotherClass");
MainFrame() {
super();
this.setTitle("Demo App");
this.setSize(200,200);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLayout(new FlowLayout());
this.add(button);
button.addActionListener(new ButtonHandler());
}
public class ButtonHandler implements ActionListener {
public void actionPerformed(ActionEvent e) {
new AnotherClass();
}
}
public static void main(String[] args) {
new MainFrame().setVisible(true);
}
}
public class AnotherClass {
public AnotherClass() {
JOptionPane.showMessageDialog(null, "AnotherClass is in operation");
}
}