Adam
Adam

Reputation: 344

Java Interacting with objects in different classes

I am trying to create a simple keypad and display program for learning purposes. I have it working however I am wondering if there is a better way to interact with objects in the different classes.

I have created a class called KeypadPanel that is panel with a grid layout and all of my buttons are added to it. I then created an ActionListener and attached it to the buttons with events for each button. I then added this panel to the center of a border layout panel.

Then I created a DisplayPanel class to hold a label that is added to the North section of the border layout panel. However I am still new and learning Java, so the only way I could interact with the label in the DisplayPanel is to make the label static and the setDisplay method static. Then I can call them from within the ButtonListener and change the display.

here is my code for the keypad, display and the main class

public class KeypadPanel extends JPanel {

// setup button objects
private JButton b1 = new JButton("1");
private JButton b2 = new JButton("2");
private JButton b3 = new JButton("3");
private JButton b4 = new JButton("4");
private JButton b5 = new JButton("5");
private JButton b6 = new JButton("6");
private JButton b7 = new JButton("7");
private JButton b8 = new JButton("8");
private JButton b9 = new JButton("9");
private JButton b0 = new JButton("0");
private JButton bStar = new JButton("*");
private JButton bPound = new JButton("#");

public KeypadPanel() {

    // setup panel
    setLayout(new GridLayout(4, 3));
    setBorder(BorderFactory.createMatteBorder(2, 2, 2, 2, Color.black));

    setPreferredSize(new Dimension(150, 150));

    // add listeners to buttons
    b1.addActionListener(new ButtonListener());
    b2.addActionListener(new ButtonListener());
    b3.addActionListener(new ButtonListener());
    b4.addActionListener(new ButtonListener());
    b5.addActionListener(new ButtonListener());
    b6.addActionListener(new ButtonListener());
    b7.addActionListener(new ButtonListener());
    b8.addActionListener(new ButtonListener());
    b9.addActionListener(new ButtonListener());
    b0.addActionListener(new ButtonListener());
    bStar.addActionListener(new ButtonListener());
    bPound.addActionListener(new ButtonListener());

    // add buttons to panel
    add(b1);
    add(b2);
    add(b3);
    add(b4);
    add(b5);
    add(b6);
    add(b7);
    add(b8);
    add(b9);
    add(bPound);
    add(b0);
    add(bStar);

}

// setup listener for buttons
private class ButtonListener implements ActionListener {

    public void actionPerformed(ActionEvent e) {

        // determine which button raised event and call setDisplay
        if (e.getSource() == b1) {
            DisplayPanel.setDisplay("1");
        } else if (e.getSource() == b2) {
            DisplayPanel.setDisplay("2");
        } else if (e.getSource() == b3) {
            DisplayPanel.setDisplay("3");
        } else if (e.getSource() == b4) {
            DisplayPanel.setDisplay("4");
        } else if (e.getSource() == b5) {
            DisplayPanel.setDisplay("5");
        } else if (e.getSource() == b6) {
            DisplayPanel.setDisplay("6");
        } else if (e.getSource() == b7) {
            DisplayPanel.setDisplay("7");
        } else if (e.getSource() == b8) {
            DisplayPanel.setDisplay("8");
        } else if (e.getSource() == b9) {
            DisplayPanel.setDisplay("9");
        } else if (e.getSource() == b0) {
            DisplayPanel.setDisplay("0");
        } else if (e.getSource() == bStar) {
            DisplayPanel.setDisplay("*");
        } else if (e.getSource() == bPound) {
            DisplayPanel.setDisplay("#");
        } else {
            return;
        }
    }

}

------------

}
public class DisplayPanel extends JPanel {

// setup display label object
private static JLabel display = new JLabel("");

public DisplayPanel() {

    // setup panel and add label
    setPreferredSize(new Dimension(200, 25));
    setBorder(BorderFactory.createLineBorder(Color.black, 3));
    add(display);

}
/**
 * @param incoming
 *            the text to add to the display
 */
public static void setDisplay(String incoming) {

    // get the incoming string and add to existing display string

    String current, changed;

    current = display.getText();
    changed = current.concat(incoming);
    display.setText(changed);

}
/**
 * 
 * clears the current text from the display
 */
public static void clearDisplay() {
    // clears display
    display.setText("");

}
}
-----------------
public class KeypadTest {

/**
 * @param args
 */
public static void main(String[] args) {
    // TODO Auto-generated method stub
    //setup frame
    JFrame frame = new JFrame ("Keypad Demo");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    //setup main panel and layout
    JPanel panel = new JPanel();
    panel.setLayout(new BorderLayout(3, 3));

    //create panel objects to fill frame and panel
    KeypadPanel keypad = new KeypadPanel();
    ClearPanel clear = new ClearPanel();
    DisplayPanel display = new DisplayPanel();

    // add to main panel
    panel.add(display, BorderLayout.NORTH);
    panel.add(keypad, BorderLayout.CENTER);
    panel.add(clear, BorderLayout.EAST);


    // setup frame
    frame.getContentPane().add(panel);
    frame.pack();
    frame.setVisible(true);
}

}

Upvotes: 3

Views: 3208

Answers (3)

Pete
Pete

Reputation: 10918

You might want to consider using Dependency Injection. It's a bit more advanced but once you've got it, it's much more versatile, flexible and convenient than to work with construction parameters.

The easiest way would be to add java spring to your classpath (google for that) and then use an application-context.xml file you load at application startup(see below) where you load all your beans, that is specificly(e.g.@Component) annotated classes.

Now Spring will take care of object management for you. You don't need to create or dispose them and most importantly, you can inject them everywhere you like:

    @Component     
    public class DisplayPanel extends JPanel {


        private JLabel display = new JLabel("");

        public DisplayPanel() {
            // ...
        }
        public void setDisplay(String value){
            this.display.setText(value);
        }
    }

    @Component
    public class ButtonListener implements ActionListener {

        @Inject
        private DisplayPanel displayPanel;

        public void actionPerformed(ActionEvent e) {

            if (e.getSource() == b1) {
                displayPanel.setDisplay("1");
            // ...
            }
        }
    }

simple application-context.xml:

<beans xmlns="http://www.springframework.org/schema/beans" 

    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd   
                        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
    default-autowire="byName">

    <context:annotation-config />
    <!-- scan your package for annotated class -->
    <context:component-scan base-package="your.base.package.name" />

</beans>

Load it at startup:

ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:application-context.xml");   

Upvotes: 0

JB Nizet
JB Nizet

Reputation: 691685

Construct the display panel, then pass it as an argument to the constructor of the keypad panel. The constructor will then store the display panel in an instance field (attribute), and the listener will use this attribute to call the setDisplay method. Of course, the setDisplay and clearDisplay methods (and the label field) should not be static. Think about it : how would it work if your application needed two different instances of your DisplayPanel?

Note that your code could be enhanced in other areas. For example, you could create only one instance of your ButtonListener, and add this unique instance as a listener of each button.

setPreferredSize should almost never be called : the preferred size is automatically computed by the layout manager, based on the components of the panel.

Finally, all the code in the main method should run in the event dispatch thread, by using SwingUtilities.invokeLater :

SwingUtilities.invokeLater(new Runnable() {
    @Override
    public void run() {
        // put the main code here
    }
});

Upvotes: 2

CamelSlack
CamelSlack

Reputation: 573

To interact with objects in other classes you have to declare them as public not private.

public JButton b1 = new JButton("1");

Upvotes: 0

Related Questions