1

So, I made a JFrame class and a JPanel class (which is pretty complicated beacuse there are some buttons in this panel). In this JFrame class, I have to make an array of the JPanel class, so it goes like this

public class frame extends JFrame
{
    //SOME VARIABLES AND METHODS HERE
    int lines;

    public frame()
    {
        //SOME CODE HERE
        panelWithButton[] pwb = new panelWithButton[5];
        //SOME CODE HERE
    }
}

And the problem is, the buttons in this JPanel have different ActionListeners for each button where it should change the variables in that JFrame class

public class panelWithButton extends JPanel
{
    //SOME VARIABLES AND METHOD
    Jbutton aButton = new JButton();
    Jbutton bButton = new JButton();
    Jbutton cButton = new JButton();

    public button()
    {
        //SOME CODE HERE
        add(aButton);
        aButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {   
                frame.lines = 4;
            }
        });

        add(bButton);
        aButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {   
                frame.lines = 5;
            }
        });

        add(cButton);
        aButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {   
                frame.lines = 6;
            }
        });
        //SOME CODE HERE
     }
}

So, that's it. Each button will change the variable of the frame differently. But it's not working. I think the problem is with this code, but I don't know what should I change it to:

frame.lines

Here is the error: non-static variable lines cannot be referenced from a static context.

Please help me. Sorry for my broken English and if my question is not clear enough, just ask. Thanks in advance. :)

Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
YorS
  • 25
  • 7
  • I would have a `public Action[] getActions()` method in the frame class (or better still, a class that extends `Object` with a `public JFrame getFrame()` method), then iterate the `Action` array and add each to a `JToolBar`. Generally though: For better help sooner, post an [MCVE](http://stackoverflow.com/help/mcve) (Minimal Complete and Verifiable Example). And please use meaningful names. E.G. `aButton`, `bButton`, `cButton` -> `exitButton`, `maximizeButton`, `restoreButton`.. – Andrew Thompson Mar 24 '14 at 10:58

1 Answers1

2

"Here is the error: non-static variable lines cannot be referenced from a static context."

You're getting this error because you're trying to access the lines in a static way, when lines isn't a static variable, it's an instance variable. So what to you want to do is get a reference to that instance variable.

One way is to pass the frame reference to the panelWithButton through constructor injection, then you can access the instance field lines. Something like

public class frame extends JFrame {
    private int lines;    // private for encapsulation. getter/setter below
    ...
    panelWithButton panel = new panelWithButton(frame.this);
    ...
    public void setLines(int lines) {
        this.lines = lines;
    }
}

public class panelWithButton extends JPanel {
    private frame f;

    public panelWithButton(final frame f) {
        this.f = f;
    }

    public void button() {
        ...
        public void actionPerformed(ActionEvent e) {
            f.setLines(5);
        }
    }
}

By passing the same instance of frame to panelWithButton, it's able to access the instance members, like the method setLines. I used the private field with the setter as to not break the rules of encapsulation.

There are better solutions to this common scenario though. This one is just one simple fix (bu with holes). This method exposes the frame class unnecesarily. What I would do in this particular situation is use some sort of MVC architecture. An easier solution would be to use an interface as a middleman and have the frame implement it (example here, but since all you want to do is manipulate data, the MVC design is the best approach.


Side Notes

  • Use Java naming convention. Class names begin with capital letters.

UPDATE

Here's an example of a simple MVC (Model, View, Controller) design, using some of your program ideas. I'll walk you through it.

Model LinesModel class. The only property is has is an int lines. It has a setLines method. The special thing about this method is that it fires a property change event so when ever the method is called, the view can be changed

public void setLines(int value) {
    int oldValue = lines;
    lines = value;
    propertySupport.firePropertyChange(LINES_PROPERTY, oldValue, lines);
}

Controller PanelWithButtons class. Then button , when pressed, calls the setLines method of the LinesModel, which fires the property change and notifies the interested listener.

fiveLines.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        lineModel.setLines(4);
    }
});

View PaintPanel class. It basically takes the number of lines from the LinesModel and paints that number of lines.

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    int y = 50;
    for (int i = 0; i < lineModel.getLines(); i++) {
        g.drawLine(50, y, 200, y);
        y += 20;
    }
}

Here's the complete running program. You can run through it and try and learn what's going on.

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.Serializable;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class Frame extends JFrame {

    private LinesModel lineModel;
    private PaintPanel paintPanel;
    private PanelWithButtons panelWithButtons;

    public Frame() {
        lineModel = new LinesModel();
        paintPanel = new PaintPanel();
        panelWithButtons = new PanelWithButtons(lineModel);

        lineModel.addPropertyChangeListener(new PropertyChangeListener(){

            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                String prop = evt.getPropertyName();
                if (LinesModel.LINES_PROPERTY.equals(prop)) {
                    paintPanel.repaint();
                }
            }   
        });

        add(paintPanel);
        add(panelWithButtons, BorderLayout.SOUTH);

        setTitle("MVC Example");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        pack();
        setVisible(true);
    }

    public class PaintPanel extends JPanel {

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            int y = 50;
            for (int i = 0; i < lineModel.getLines(); i++) {
                g.drawLine(50, y, 200, y);
                y += 20;
            }
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(300, 300);
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable(){
            public void run() {
                new Frame();
            }
        });
    }
}


class PanelWithButtons extends JPanel {

    private final JButton fourLines = new JButton("FOUR");
    private final JButton fiveLines = new JButton("FIVE");
    private LinesModel lineModel;

    public PanelWithButtons(LinesModel lineModel) {
        this.lineModel = lineModel;

        fiveLines.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                PanelWithButtons.this.lineModel.setLines(4);
            }
        });

        fourLines.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                PanelWithButtons.this.lineModel.setLines(5);
            }
        });

        add(fourLines);
        add(fiveLines);
    }
}

class LinesModel implements Serializable {

    public static final String LINES_PROPERTY = "linesProperty";
    private int lines;

    private PropertyChangeSupport propertySupport;

    public LinesModel() {
        propertySupport = new PropertyChangeSupport(this);
    }

    public int getLines() {
        return lines;
    }

    public void setLines(int value) {
        int oldValue = lines;
        lines = value;
        propertySupport.firePropertyChange(LINES_PROPERTY, oldValue, lines);
    }

    public void addPropertyChangeListener(PropertyChangeListener listener) {
        propertySupport.addPropertyChangeListener(listener);
    }

    public void removePropertyChangeListener(PropertyChangeListener listener) {
        propertySupport.removePropertyChangeListener(listener);
    }  
}
Community
  • 1
  • 1
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • Sorry, I was trying to simplify my code by changing some variables, but it turned out to make things worse. Your answer isn't what I'm looking for but I do learn some new trick from your answer and my program is working now thanks to you. Oh, and thanks for some of your notes and advices. I think you're better than my lecturer. Thanks!! – YorS Mar 24 '14 at 16:41