I am trying to call two methods from another class which is linked to the current class i am working in.

basically if it is a left-button click from the mouse, i want to call the addCounter method (of the myAbacus object). If it is a right button click, i need to call the removeCounter method (of the myAbacus object).

In both cases, i think i need the method parameter as thisCol (a variable which stores the column that the mouse was clicked in)

class AbacusPanel extends JPanel implements MouseListener
{
    int numCols;
    int numRows;
    int buttonClick;

    AbacusModel myAbacus;


    public static void main(String[] args)
    {
        AbacusFrame w = new AbacusFrame();
        w.setVisible(true);
    }


    public AbacusPanel(int nc, int nr)
    {
        numCols = nc;
        numRows = nr;
        addMouseListener(this);

        myAbacus = new AbacusModel(numCols,numRows);
    }
    int getCol(int x)
    {
        return x*numCols/getWidth();
    }
    int getRow(int y)
    {
        return y*numRows/getHeight();
    }

    public void mouseReleased(MouseEvent event)
    {
    }
    public void mousePressed(MouseEvent event)
    {
    }
    public void mouseClicked(MouseEvent event)
    {
        int thisCol = getCol(event.getX());
        System.out.println("you clicked in column " + thisCol);

        System.out.println("The button clicked was " + event.getButton());

    // here is where i would need to call the addCounter and removeCounter methods
    // but i do not know how to call these methods correctly
    }

please can anybody help me achieve this?

if you need me to explain any aspect of this program then please ask...
Thanks

If you want to call your own methods from a separate class you need to make sure your methods are class methods. For example, "addCounter" would be "public static void addCounter( ...statements...). The keyword static makes your method accessible at the class level. So if, for instance the separate class was called MyClass you'd call your addCounter method by using the class you wrote the method in which is AbacusPanel. So you'd write AbacusPanel.addcounter( ...arguments to the parameters here... ) to use it from the class MyClass. I hope this answers your question?

Edited 3 Years Ago by joshfizzle: I'm awesome n

Are those methods defined in the AbacusModel class? In that case you created an instance of that class on line 23 as part of your constructor, so you can use myAbacus to call those methods. Without seeing the method definitions it's impossible to comment on what parameter(s) to pass.
I have to disagree with joshfizzle - just defining everything as static reduces Java to the level of beginner's Basic. In this case you create an instance with values for the number of rows and columns - presumably instance variables, which would not be accessible if you made the methods static.

my methods are boolean so i have just made them 'public'. Will that be enough, or do i need to include 'static' too?

In the AbacusPanel class i want to call a method from the AbacusModel class which is a separate class and a separate file altogether. the addCounter(int thisPeg) & removeCounter(int thisPeg) methods need to be called from AbacusPanel to indicate whether a left click or right click has been detected.

Left click = addCounter()
Right click = removeCounter()

i know it has something to do with the event.getButton() and the variable that stores the column which was clicked in. But i don't know how to tie these things all together?

Here is my code for the AbacusModel class, containing the methods i need to call in AbacusPanel

class AbacusModel extends JPanel
{
    int num_of_pegs;
    int max_num_counters;
    int peg_array[];

    public AbacusModel(int num_pegs, int num_counters)
    {
        max_num_counters = num_counters;
        num_of_pegs = num_pegs;
        peg_array = new int[num_of_pegs];
    }

    public boolean addCounter(int thisPeg) 
    {

        if (thisPeg < 0 || thisPeg >= num_of_pegs)
            return false;

        if (peg_array[thisPeg] >= max_num_counters)
            return false;

        else
            peg_array[thisPeg]++;
            return true;

    }

    public boolean removeCounter (int thisPeg)
    {
        if (thisPeg < 0 || thisPeg >= num_of_pegs)
            return false;
        if (peg_array[thisPeg] <= 0)
            return false;
        else
            peg_array[thisPeg]--;
            return true;

    }

    int getNumCounters(int thisPeg)
    {
        if (thisPeg < 0 || thisPeg >= num_of_pegs)
            return 0;
        else
            return peg_array[thisPeg];
    }

public static void main (String[] args)
{
    AbacusModel myAbacus = new AbacusModel(7, 9);
}

i hope this is enough information to help you better understand the program.

Please reply if you can. Thanks

this is what i have attempted to include but the error after inputting this states:

"error: non-static method addCounter(int) cannot be referenced from a static context
            AbacusModel.addCounter(thisCol);"
                       ^

but if i make the methods static then the variables become an error as they are instance variables??
e.g.

"error: non-static variable peg_array cannot be referenced from a static context"




public void mouseClicked(MouseEvent event)
    {
        int thisCol = getCol(event.getX());
        System.out.println("you clicked in column " + thisCol);

        System.out.println("The button clicked was " + event.getButton());

        if (buttonClick == 1)
        {
            AbacusModel.addCounter(thisCol);
        }

    repaint();

Making stuff static is not the answer. When you say AbacusModel.addCounter(thisCol); AbacusModel is a class, not an instance, so you cannot use that to call an instance method.
However, in your constructor for AbacusPanel you do (correctly) create an instance of AbacusModel
myAbacus = new AbacusModel(numCols,numRows);
now you can use that instance to call the instance emethods of the AbacusModel class, eg
myAbacus.addCounter(thisCol);

Thanks thats made perfect sense and cleared things up. I was unsure whether you had to refer to the instance created or not. But after doing that it's now compiling fine :) i am extremely greatful for you taking the time to help me with this! You have saved me a massive amount of time. You clearly have an incredible knowledge of java! Thanks again.

sorry, there is one more thing that might be of use to me when testing. Is there a way i can show the amount of counters that are present in each column? maybe just using a println(...)? i have tried using the array pag_array[thisPeg] which stores the number of counters in each element of the abacus but it says error: cannot find symbol?? i assume this is because it is from the AbacusModel class and i am trying to reference it from the AbacusPanel class??

When you println(something) the implementation actually calls something.toString() to convert the object to a printable string. Every class inherits a toString method from Object, so it always works, but usually isn't very helpful.
When you create your own class its a very good idea to override the toString method so when you print an instance of that class you get a meaningful output. In your case you may want to do something like:

@Override
public String toString() {
   String temp = "";
   // for each of the rows on this abacus append the number of counters to temp
   return temp;
}

Then you can call System.out.println(myAbacus); and get a useful ouput.

Edited 3 Years Ago by JamesCherrill

OK i am trying to understand the answer you have suggested. How can i append the number of counters as they are stored in an array (peg_array)?

Would this be included in the AbacusModel class or the AbacusPanel class?

Is there another way i could achieve this?
My attempt at this is below (written in the AbacusPanel class - mouseClicked(MouseEvent event) method):

System.out.println("Column " + thisCol + " has " + peg_array[thisPeg] + " counters");

I just want to keep it relatively simple as its just a test for my benefit to show me that everything is working as it should be. At this stage there are no counters in any of the program so it should be returning 0 everytime at the moment

e.g.
2b98aac7f60de9a49e41b4f260141ee6

These are just simple tests to tell me where the mouse is being clicked and with which button. With limited knowledge of java i don't know how i can add your suggestion to my program??

You are heading in the wrong direction! Just take a step back and look at the problem. You want to see the current state of your abacus. That info is all in the AbacusModel class. Java has a standard way of doing that, which uses the public String toString() method that every class has. In your AbacusModel class you override toString so it returns all the info you want to see. Now you can just print an instance of AbacusModel and see all the info.
eg suppose you have an ordinary Person class

class Person {
   private String familyName, givenName;
   private Date dateOfBirth;
   ... etc etc

in that class you override toString...

 public String toString() {
    return "Person: " + familyName + " " + givenName + "\nD.O.B. " + dateOfBirth;
 }

Now anywhere you have a Person, you can just print it, eg

 Person me = new Person(etc
 System.out.println(me);  // prints:  Person: Cherill James\nD.O.B. etc

Do the same thing for your AbacusModel, returning numbers of counters or anything else interesting, and then you can print out all its info from anywhere inAbacusPanel by just calling

System.out.println(myAbacus);

Edited 3 Years Ago by JamesCherrill

Ok thanks,
so i would need to write something like this in the AbacusModel class:

public String toString()
{
    return "number of counters: " + peg_array[thisPeg]; 
}

    // somewhere else in the AbacusModel class...
    AbacusModel counterCount = new AbacusModel;
    System.out.println(counterCount);

then to print this info from AbacusPanel i would then write:

System.out.println(myAbacus); // within the mouseClicked method of the AbacusPanel class

would this work?

thisPeg is var from the Panel, yes? So it's not available in the Model.
The best way is to make toString nicely general so you can use it whenever/wherever you want to see what's happening in the model, not just in mouseClicked. So I would show everything (pseudocode):

String temp = "Abacus Model:\n";
for each element i in peg_array
    append "peg " + i + " = " + peg_array[i] + "\n"  to temp
return temp

Your lines 6,7,8 are not needed, all you need is the toString method then you can simply print myAbacus from within mouseClicked or anywhere else that you are working with myAbacus

thisPeg is a variable from Model that refers to ANY of the pegs in the abacus.

i am little confused now. I clearly don't know enough about java!

so i add this to Model:

public String toString()
{
    return "number of counters: " + peg_array[thisPeg]; 
}

then i add this to Panel:

System.out.println(myAbacus);

but do i add this? if so where do i add this??:

// i do not understand what this means/does (sorry)

    String temp = "Abacus Model:\n";
    for each element i in peg_array
        append "peg " + i + " = " + peg_array[i] + "\n"  to temp
    return temp

Sorry to be such a pain in the ass, and thanks for your time and patience...

Be careful about thisPeg. It's not a variable of the AbacusModel class. There are a number of thisPeg variables that are the parameters passed into various methods. They are all different, and they all cease to exist the instant their method is finished. You can't use any of them in any other method. (Do not worry, that's the way it shouyld be. Don't change it.)

That pseudo code is a suggestion for code to go inside the toString() method - ie instead of just returning one of the pegs, build a string that has all the pegs in it. That way the toString tells you everything about the model, so it will be very useful in all kinds of places - as your code develops there will be lots of places in AbacusPanel where you will want to check that the model is getting all the right data etc.

ok its starting to make more sense now...

so when building the string how can i write the code for testing all pegs (5 pegs inc 0)?

Would i need to write a for loop? I really dont know how to begin this? So far all i have added into my program is the 'toString()' method, which i placed just above the addCounter(thisPeg) method of the Model class. Then i have also added the

System.out.println(myAbacus);

to the mouseClicked method.

All i need to know now is what i have to add to this bit. I saw in one of your previous responses of family names, people etc. But the only variable i want to print is the num of counters. When i try "number of counters: + num_counters" it says error: cannot find symbol?

return "number of counters: " + /*variable here??*/;

I don't like to write code for people, its far better for them to write their own, so please take time to understand this rather than just copy/paste, but it's something like...

@Override
public String toString() {
   String temp = "Abacus Model:\n";
   for (int i = 0; i < peg_array.length; i++) { // standard loop through an array
      // append info about each peg to temp...
      temp +=  "peg " + i + " has " + peg_array[i] + " counters\n";
   }
   return temp;
}
This question has already been answered. Start a new discussion instead.