java - JFrame、JPanel、JButton 和继承

标签 java swing jframe jbutton jlabel

所以,我创建了一个 JFrame 类和一个 JPanel 类(这非常复杂,因为这个面板中有一些按钮)。在这个 JFrame 类中,我必须创建一个 JPanel 类的数组,所以它是这样的

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
    }
}

问题是,这个JPanel中的按钮对于每个按钮都有不同的ActionListeners,它应该在该JFrame类中更改变量

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
     }
}

所以,就是这样。每个按钮都会不同地改变框架的变量。但这不起作用。我认为问题出在这段代码上,但我不知道应该将其更改为什么:

frame.lines

这是错误:无法从静态上下文引用非静态变量行。

请帮我。抱歉我的英语很蹩脚,如果我的问题不够清楚,尽管问。提前致谢。 :)

最佳答案

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

您收到此错误是因为您尝试以静态方式访问 lines,而 lines 不是 static > 变量,它是一个实例变量。因此,您要做的就是获取对该实例变量的引用。

一种方法是通过构造函数注入(inject)将frame引用传递给panelWithButton,然后就可以访问实例字段lines。类似的东西

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);
        }
    }
}

通过将 frame 的相同实例传递给 panelWithButton,它可以访问实例成员,例如方法 setLines。我将私有(private)字段与 setter 一起使用,以免违反封装规则。

对于这种常见情况,有更好的解决方案。这只是一个简单的修复(但有漏洞)。此方法不必要地公开了frame 类。在这种特殊情况下我会做的是使用某种 MVC architecture 。一个更简单的解决方案是使用 interface 作为中间人,并让 frame 实现它(例如 here ,但由于您想要做的只是操作数据,因此MVC 设计是最好的方法。

<小时/>

旁注

  • 使用 Java 命名约定。类名以大写字母开头。
<小时/>

更新

这是一个简单的 MVC(模型、 View 、 Controller )设计示例,使用了您的一些程序想法。我将引导您完成它。

模型 LinesModel 类。唯一的属性是一个intlines。它有一个 setLines 方法。此方法的特殊之处在于它会触发属性更改事件,因此每当调用该方法时, View 都可以更改

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

Controller PanelWithButtons 类。然后,按钮在按下时会调用 LinesModelsetLines 方法,该方法会触发属性更改并通知感兴趣的监听器。

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

View PaintPanel 类。它基本上从 LinesModel 获取行数并绘制该行数。

@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;
    }
}
<小时/>

这是完整的运行程序。您可以运行它并尝试了解发生了什么。

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);
    }  
}

关于java - JFrame、JPanel、JButton 和继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22606293/

相关文章:

java - DecimalFormat 四舍五入

java - B 样条基函数似乎产生不正确的值

Java:某些表单元素被其他元素部分覆盖

java - 如何读取/恢复已删除的文件

java - 使用 findOne() MongoDB 从集合中检索第一个文档

java - Idea 中无法查看应用程序服务器

java - 该功能与 JTable 模型配合使用是否正常?

Java Swing : Extended jpanel class will not brighten upon repainting.

java - 在分形的 Paint() 方法中使用递归

java - 加载子面板时 Swing Parent JFrame/JPanel 不可用/不可点击