Is it possible to access an object created in main class? or there is a way of get the owner/reference class?
For example, in the code below, how can I call the method setMenu, that is on the myMainClass, from one of the Menu class objects (firstMenu, secondMenu)
I can make the Menu objects static but doesn't seems like the right approach...
Main Class
public class myMainClass extends JFrame {
JPanel container;
Menu firstMenu;
Menu secondMenu;
myMainClass() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400, 400);
firstMenu = new Menu();
secondMenu = new Menu();
container = new JPanel(new CardLayout());
container.add(firstMenu, "firstMenu");
container.add(secondMenu, "secondMenu");
add(container);
}
public void setMenu(String s) {
CardLayout cl = (CardLayout) (container.getLayout());
cl.show(container, s);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
myMainClass myMainClassObject = new myMainClass();
myMainClassObject.setVisible(true);
}
});
}
}
Menu Class
public class Menu extends JFrame {
Menu() {
//How can I call myMainClass setMenu method from here?
//myMainClass.setMenu("secondMenu");
//myMainClassObject.setMenu("secondMenu");
}
}
Thanks
You've answered your own question. Make the setMenu method static.
public void setMenu(String s) {
CardLayout cl = (CardLayout) (container.getLayout());
cl.show(container, s);
}
And invoke it using the class name MyMainClass.setMenu in the Menu class.
Otherwise, you'll have to pass the instance of MyMainClass to the Menu class by overloading its constructor.
firstMenu = new Menu(this);
secondMenu = new Menu(this);
And in the other class,
public class Menu extends JFrame {
Menu() {
//How can I call myMainClass setMenu method from here?
//myMainClass.setMenu("secondMenu");
//myMainClassObject.setMenu("secondMenu");
}
Menu(MyMainClass main) {
main.setMenu("secondMenu");
}
}
setMenu() is an instance method if you want to call it you would need to instantiate myMainClass, which btw should be called MyMainClass, so you need to do:
MyMainClass mainClass = new MyMainClass();
mainClass.setMenu("secondMenu");
If you want the method to be accessed via the class then you would need to create the method static, so it is a class method and not an instance method, so you can call it like:
MyMainClass.setMenu("secondMenu");
Related
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);
}
});
}
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.
Suppose you have class A and class B. Class A is the main class which builds a frame with a GUI. It contains all the GUI variables (such as buttons, labels, strings) along with whatever methods that you'll be using. Class A also creates a class B object:
ClassB name = new ClassB();
Inside class B you will find a for loop. Now, once the for loop is finished looping, I want to call a method located in class A. Whenever I try calling a method located in class A, Eclipse suggests making that method static. I'm trying to avoid making static methods. Is there a way of calling class A's methods from class B without making anything static?
Class A:
public class Game extends JFrame implements ActionListener {
// init variables
private JPanel contentPane;
private JPanel panel_actions;
private JButton btn_strike;
private JProgressBar progBar_loading;
private Load load;
// create the frame
public dsgsd() {
load = new Load();
// frame initializing
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setBounds(100, 100, 890, 480);
setTitle("BeyondInfinity - Group Project for CS1100");
getContentPane().setLayout(null);
setVisible(true);
// create a root panel
contentPane = new JPanel();
contentPane.setLayout(null);
contentPane.setBounds(0, 0, 884, 451);
contentPane.setVisible(true);
getContentPane().add(contentPane);
// create actions panel for displaying attack buttons
panel_actions = new JPanel();
panel_actions.setBorder(new EmptyBorder(10, 10, 10, 10));
panel_actions.setBounds(10, 306, 854, 68);
panel_actions.setBackground(new Color(100, 149, 237));
panel_actions.setLayout(new GridLayout(0, 6, 10, 0));
panel_actions.setVisible(true);
contentPane.add(panel_actions);
// create attack button #1
btn_strike = new JButton("Strike");
btn_strike.setFocusable(false);
btn_strike.setVisible(true);
btn_strike.addActionListener(this);
panel_actions.add(btn_strike);
}
// create action listener
public void actionPerformed(ActionEvent evt) {
if (evt.getSource().equals(btn_strike)) {
load.start();
}
}
public void executeTasks() {
//TODO do something
}
// set value for the loading bar
public void setProgBar_loading(int val) {
progBar_loading.setValue(val);
progBar_loading.repaint();
}
}
Class B:
public class Load {
private Timer timer;
private int i;
public void start() {
// reset loading bar
Game.setProgBar_loading(0);
i = 0;
ActionListener listener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (i > 100) {
timer.stop();
Game..executeTasks();
} else
Game.setProgBar_loading(i++);
}
};
// timer which triggers the actionlistener every 15ms
timer = new Timer(15, listener);
timer.start();
}
}
You're going to need a reference to an instance of ClassA inside of ClassB to avoid static methods.
First, ClassB will need a field and constructor similar to the following:
private ClassA parent = null;
public ClassB(ClassA parent) {
this.parent = parent;
}
Then, when you instantiate ClassB, you'll pass a reference to the current instance like so: ClassB name = new ClassB(this)
Finally, when you want to use your method inside ClassB (let's assume that method is called doSomething(), you can call it with parent.doSomething()
The "proper" OOP approach to do this would be with an interface.
public interface Loadable {
void reset();
void setProgress(int progress);
void onLoaded();
}
You implement this in your Game class
public class Game extends JFrame implements ActionListener, Loadable {
private JButton load_button;
private JProgressBar progressBar;
public Game() {
// initialize
}
public void executeTasks() {
//TODO do something
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource().equals(load_button)) {
new Loader().load(this);
}
}
#Override
public void onLoaded() {
executeTasks();
}
#Override
public void reset() {
progressBar.setValue(0);
}
#Override
public void setProgress(int progress) {
progressBar.setValue(progress);
}
}
And pass it into the Loader. This way, the Loader doesn't care the you are giving it a Game object. You could have any implementation of Loadable that this Loader can load.
public class Loader {
private Timer timer;
private int i;
public void load(final Loadable l) {
// reset loading bar
l.reset();
i = 0;
ActionListener listener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
l.setProgress(++i);
if (i >= 100) {
timer.stop();
l.onLoaded();
}
}
};
// timer which triggers the actionlistener every 15ms
timer = new Timer(15, listener);
timer.start();
}
}
You can call non-static methods of an object, but you can only call static methods on a class. See this for more information on the difference between the two. To be able to call a method on an object of type ClassA, you'd have to do something like this:
public class ClassA {
public method myNonStaticMethod() { ... }
}
public class ClassB {
private ClassA a;
public ClassB(ClassA a) {
this.a = a; //This makes sure this *object* has a *reference* to an object of *type* ClassA.
}
public void looping() {
//some looping code
this.a.myNonStaticMethod(); //Actually call the nonstatic method
}
}
Note that any class that imports another class will have reference to that class and can call static methods on that class, or instantiate a new object of that class type. If you want a particular object to call a non-static method of another object, it either needs to instantiate the object itself, or it needs a reference to that other object.
In the example above, the constructor of ClassB gets a reference to a specific object of type ClassA, whose reference name is a. This is saved to a private member field, which can be called by any non-static method in an object of type ClassB.
To call any non-static method of A, you need a class instance of A. Do you have one inside class B? If you don't then you can't call a non-static method. A static method can be called without the instance (as long as it is accessible) like this A.method1();
Looking at other answers, i have followed exactly what they say, but i just keep getting the nullPointerException error. I have 4 classes, the 2 below, a GUI class and main menu class. Main manages the card layout and i would like a button in the Insert class to change the "Active" card to main menu class.
Main:
public class Main extends JPanel implements ChooserListener{
MainMenu mm;
Insert InsertCustomer;
public JPanel mPanel;
CardLayout cl;
private String c;
public Main(){
super();
//add mPanel, set to CardLayout and add the Main
mPanel = new JPanel();
this.add(mPanel);
cl = new CardLayout();
mPanel.setLayout(cl);
//add classes
mm = new MainMenu(this);
InsertCustomer = new Insert();
//add classes to mPanel
mPanel.add(mm, "mm");
mPanel.add(InsertCustomer, "InsertCustomer");
}
public void tell(Object o) {
c = o.toString();
cl.show(mPanel, c);
}
public void swapView(String key) {
CardLayout cl = (CardLayout)(mPanel.getLayout());
cl.show(mPanel, key);
}
}
Insert:
public class Insert extends JPanel{
private JButton logoutbutton;
private LogoutListener lListener;
public Insert() {
super();
//BUTTONS
//logout button
JButton logoutbutton = new JButton("Main Menu");
this.add(logoutbutton);
lListener = new LogoutListener(null);
logoutbutton.addActionListener(lListener);
}
private class LogoutListener implements ActionListener{
private Main main;
public LogoutListener(Main main){
this.main = main;
}
public void actionPerformed(ActionEvent e) {
main.swapView("mm");
}
}
}
lListener = new LogoutListener(null);
Your LogoutListener takes your Main-class, but you give him null. Of course you will get a NullPointerException (at least on your logoutButton-click).
Your problem in next lines :
lListener = new LogoutListener(null);
main.swapView("mm");
You need to put reference to your Main class, not null as you done. Because of your main in LogoutListener is null and you catch NPE.
Simple solution is to transfer reference of your Main to Insert with help of constructor and then transfer that to LogoutListener.
I'm programming in Java, trying to use a cardholder in order to switch between 2 JPanels which are each an extension of their own class. I think I understand the basic concepts but I am having errors in my current revision, when calling the classes. I'm getting a null pointer exception and I think it's a structural problem but I'm not sure how or why.
The main method points to this class
public class Skeleton implements ActionListener{
JPanel cardHolder;
CardLayout cards;
String cardA = "A";
String cardB = "B";
JPanel Jboard;
JPanel Jmenu;
JFrame frame2;
Board board;
Menu menu;
boolean menuSet;
boolean boardSet;
Timer timer;
public class Switcher implements ActionListener{
String card;
Switcher(String card){
this.card = card;
}
#Override
public void actionPerformed(ActionEvent e) {
cards.show(cardHolder, card);
}
}
public Skeleton(JFrame frame){
JPanel menu = new Menu();
JPanel board = new Board();
JFrame frame2 = frame;
timer = new Timer(5, this);
timer.start();
cardHolder = new JPanel();
cards = new CardLayout();
cardHolder.setLayout(cards);
cardHolder.add(menu, cardA);
cardHolder.add(board, cardB);
frame2.add(cardHolder);
frame2.revalidate();
frame2.setVisible(true);
}
public JFrame getSkeleton(){
return frame2;
}
public JPanel getCardHolder(){
return cardHolder;
}
public void checkStatus(){
if (menuSet == true){
new Switcher(cardB);
boardSet = false;
}
if (boardSet == true){
new Switcher(cardA);
menuSet = false;
}
}
#Override
public void actionPerformed(ActionEvent e) {
menuSet = menu.getMenuset();
boardSet = board.getBoardset();
checkStatus();
}
}
This is the board class, one of the JPanels I'm trying to switch between
public class Board extends JPanel{
boolean boardset;
Menu menu = new Menu();
public Board(){
setBackground(Color.WHITE);
}
public JPanel getPanel(){
return this;
}
public void setBoardset(boolean x){
boardset = x;
}
public boolean getBoardset(){
return boardset;
}
}
Here is the other JPanel class, which contains a button used to switch to the other JPanel class. This is also the original starting JPanel used.
public class Menu extends JPanel implements ActionListener{
boolean menuset;
public Menu(){
setBackground(Color.BLACK);
JButton button = new JButton("hello");
button.addActionListener(this);
this.add(button);
}
public JPanel getPanel(){
return this;
}
#Override
public void actionPerformed(ActionEvent e) {
menuset = true;
}
public void setMenuset(boolean x){
menuset = x;
}
public boolean getMenuset(){
return menuset;
}
}
Like I said, I'm getting a null pointer exception. It is occuring on this line of the Skeleton() class
menuSet = menu.getMenuset();
The line above is right after the actionPerformed event above (from the timer), and I have tested the timer a little, it works doing basic print statements but whenever I try to use the 'menu' or 'board' instance inside the actionPerformed, I get this null pointer exception.
I would appreciate any advice. I get the idea that the way I'm doing this may be a little convoluted. If anyone has any suggestions on a better way to do this it would also be helpful. My main goal is to be able to call 2 separate classes from one main class containing a cardholder. That way I can separate the code in order to keep everything isolated and in order.
Your Skeleton class has a "menu" member but it isn't set anywhere that I can see. The constructor declares its own "menu" local variable, which is local to the constructor and hides the member. Setting "menu" inside the constructor won't set the member. I don't see anywhere else where the "menu" member is set, unless I've missed something or unless another class in the same package is setting it.