【问题标题】:JPanel in different class, is what I did bad ? why?不同班级的JPanel,我做错了吗?为什么?
【发布时间】:2015-08-12 23:38:57
【问题描述】:

我创建了一个扩展 JFrame 的新类和扩展 JPanel 的新类以制作摇摆 GUI。太好了,我喜欢它,因为它易于阅读。

但是,当涉及到事件处理时,事情开始变得复杂。我所做的似乎并不是真正的解决方案。就像打破好习惯让某事发挥作用一样。我怎样才能使它正常工作?

这是我的 JFrame 类

public class MainFrame extends JFrame{
    private JTextArea textArea;

    public MainFrame(String title){
        super(title);

        //set layout
        setLayout(new BorderLayout());

        //create components
        JButton buttonOne = new JButton("click me");
        textArea = new JTextArea();
        JPanel detailedPanel = new leftPanel();

        //add to panel
        Container c = getContentPane();

        c.add(buttonOne, BorderLayout.SOUTH);
        c.add(textArea, BorderLayout.CENTER);
        c.add(detailedPanel, BorderLayout.WEST);

        //Event Listening
        leftPanel.buttonAdd.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e) {
                textArea.setText(textArea.getText() + " " + leftPanel.fieldName.getText() + " : " + leftPanel.fieldOccupation.getText());
            }

        });

    }

}

这是我的 JPanel

public class leftPanel extends JPanel {

    public static JTextField fieldName;
    public static JTextField fieldOccupation;
    public static JButton buttonAdd;

    public leftPanel(){
        Dimension panelSize = getPreferredSize();
        panelSize.width = 250;
        setPreferredSize(panelSize);

        setBorder(BorderFactory.createTitledBorder("Personal Info"));

        //labels
        JLabel labelName = new JLabel("name: ");
        JLabel labelOccupation = new JLabel("Occupation: ");

        //textFields
        fieldName = new JTextField(10);
        fieldOccupation = new JTextField(10);

        //buttons
        buttonAdd = new JButton("Add !");

        //actions
        buttonAdd.addActionListener(new ActionListener(){
            //on click
            public void actionPerformed(ActionEvent e) {
                String name = fieldName.getText();
                String occupation = fieldOccupation.getText();

                System.out.print(name + ": " + occupation);                    
            }    
        });

        setLayout(new GridBagLayout());

        GridBagConstraints gbc = new GridBagConstraints();

        //// First Y  add //////////////////////////////////////

        //label NAME
        gbc.anchor = GridBagConstraints.FIRST_LINE_END;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridx = 0;
        gbc.gridy = 0;
        add(labelName, gbc);

        //label Occupation
        gbc.anchor = GridBagConstraints.FIRST_LINE_END;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridx = 0;
        gbc.gridy = 1;
        add(labelOccupation, gbc);

        //// SECOND Y add /////////////////////////////////////  

        //text field name
        gbc.anchor = GridBagConstraints.FIRST_LINE_START;
        gbc.weightx = 2;
        gbc.weighty = 1;
        gbc.gridx = 1;
        gbc.gridy = 0;
        add(fieldName, gbc);

        //text feld occupation
        gbc.anchor = GridBagConstraints.FIRST_LINE_START;
        gbc.weightx = 2;
        gbc.weighty = 1;
        gbc.gridx = 1;
        gbc.gridy = 1;
        add(fieldOccupation, gbc);

        //// THIRD Y add //////////////////////////////////////

        //add button
        gbc.anchor = GridBagConstraints.FIRST_LINE_START;
        gbc.gridx = 1;
        gbc.gridy = 3;
        gbc.weightx = 1;
        gbc.weighty = 10;
        add(buttonAdd, gbc); 
    }
}

【问题讨论】:

  • offtopic...用大写的第一个字母命名您的类是一个好习惯...public class leftPanel 可以是public class LeftPanel
  • 另外,static 不是你的朋友,它不是跨对象通信机制,千万不要这样使用

标签: java swing user-interface event-handling jpanel


【解决方案1】:

在大多数情况下,您的组件应尽可能自包含,这表明该组件应负责处理由其直接子级生成的事件。

这并不意味着组件不会生成它自己的事件,而是组件自己管理它的直接子级。

您应该尽量避免直接(使用public 字段或getters)或间接(通过事件对象)暴露您的子组件,这可能会导致外部资源滥用这些组件,这永远不会令人愉快.

在您的示例中,您的第一个班级只想知道何时发生需要更新文本区域的事情。

这表明LeftPanel 需要生成某种事件(可能是ActionEvent)并为可能有兴趣访问LeftPanel 管理的信息的任何人提供getter .

例如...

import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class LeftPanel extends JPanel {

    private JTextField fieldName;
    private JTextField fieldOccupation;
    private JButton buttonAdd;

    public LeftPanel() {

        setBorder(BorderFactory.createTitledBorder("Personal Info"));

        //labels
        JLabel labelName = new JLabel("name: ");
        JLabel labelOccupation = new JLabel("Occupation: ");

        //textFields
        fieldName = new JTextField(10);
        fieldOccupation = new JTextField(10);

        //buttons
        buttonAdd = new JButton("Add !");

        //actions
        buttonAdd.addActionListener(new ActionListener() {
            //on click
            public void actionPerformed(ActionEvent e) {
                fireActionPerformed();
            }
        });

        setLayout(new GridBagLayout());

        GridBagConstraints gbc = new GridBagConstraints();

        //// First Y  add //////////////////////////////////////
        //label NAME
        gbc.anchor = GridBagConstraints.FIRST_LINE_END;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridx = 0;
        gbc.gridy = 0;
        add(labelName, gbc);

        //label Occupation
        gbc.anchor = GridBagConstraints.FIRST_LINE_END;
        gbc.weightx = 1;
        gbc.weighty = 1;
        gbc.gridx = 0;
        gbc.gridy = 1;
        add(labelOccupation, gbc);

        //// SECOND Y add /////////////////////////////////////  
        //text field name
        gbc.anchor = GridBagConstraints.FIRST_LINE_START;
        gbc.weightx = 2;
        gbc.weighty = 1;
        gbc.gridx = 1;
        gbc.gridy = 0;
        add(fieldName, gbc);

        //text feld occupation
        gbc.anchor = GridBagConstraints.FIRST_LINE_START;
        gbc.weightx = 2;
        gbc.weighty = 1;
        gbc.gridx = 1;
        gbc.gridy = 1;
        add(fieldOccupation, gbc);

        //// THIRD Y add //////////////////////////////////////
        //add button
        gbc.anchor = GridBagConstraints.FIRST_LINE_START;
        gbc.gridx = 1;
        gbc.gridy = 3;
        gbc.weightx = 1;
        gbc.weighty = 10;
        add(buttonAdd, gbc);

    }

    public void addActionListener(ActionListener listener) {
        listenerList.add(ActionListener.class, listener);
    }

    public void removeActionListener(ActionListener listener) {
        listenerList.remove(ActionListener.class, listener);
    }

    protected void fireActionPerformed() {
        ActionListener[] listeners = listenerList.getListeners(ActionListener.class);
        if (listeners.length > 0) {
            ActionEvent evt = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "PropertiesSet");
            for (ActionListener listener : listeners) {
                listener.actionPerformed(evt);
            }
        }
    }

    public String getPersonName() {
        return fieldName.getText();
    }

    public String getPersonOccupation() {
        return fieldOccupation.getText();
    }

}

这里的LeftPanel 现在管理其组件的内部状态(没有staticpublic 字段)。它还提供了ActionListener 支持,以向感兴趣的各方提供通知,他们可以通过 getter 获取组件正在管理的信息

MainFrame 然后简单地使用LeftPanel 的实例并向其注册ActionListener,以便在面板更新时通知它并使用getter 获取它感兴趣的信息。

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextArea;

public class MainFrame extends JFrame {

    private JTextArea textArea;

    public MainFrame(String title) {
        super(title);

        //set layout
        setLayout(new BorderLayout());

        //create components
        JButton buttonOne = new JButton("click me");
        textArea = new JTextArea();
        LeftPanel detailedPanel = new LeftPanel();

        //add to panel
        Container c = getContentPane();

        c.add(buttonOne, BorderLayout.SOUTH);
        c.add(textArea, BorderLayout.CENTER);
        c.add(detailedPanel, BorderLayout.WEST);

        //Event Listening
        detailedPanel.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                textArea.append(textArea.getText() + " " + detailedPanel.getPersonName() + " : " + detailedPanel.getPersonOccupation() + "\n");
            }

        });

    }

}

在 OO 中,您希望将逻辑和责任封装到对象中,然后根据需要从回调(例如 Observer Pattern)向感兴趣的各方提供一些预定义状态已更改的通知。然后简单地通过 getter 公开对象正在管理的信息(并且在需要时,设置器让其他人根据需要更改信息)

【讨论】:

    猜你喜欢
    • 2016-08-05
    • 2022-11-17
    • 1970-01-01
    • 2013-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多