ActionListener between two classes

2019-06-24 03:13发布

问题:

import javax.swing.*;

class Labels extends JFrame{ JPanel pnl = new JPanel();

ImageIcon duke = new ImageIcon("duke.png");

JLabel lbl1 = new JLabel(duke);
JLabel lbl2 = new JLabel("Duke is the friendly mascot of Java technology.");
JLabel lbl3 = new JLabel ("Duke", duke, JLabel.CENTER);

public Labels(){

    super("Swing Labels");
    setSize(1000 , 800);
    setDefaultCloseOperation( EXIT_ON_CLOSE);
    add(pnl);
    setVisible(true);

    lbl1.setToolTipText("Duke - the Java Mascot");

    lbl3.setHorizontalTextPosition(JLabel.CENTER);
    lbl3.setVerticalTextPosition(JLabel.BOTTOM);

    pnl.add(lbl1);
    pnl.add(lbl2);
    pnl.add(lbl3);

}
    public static void main(String [] args){
        Labels gui = new Labels();
    }

}

What if I want to use this as a JApplet? what has to be done? Is it hard to change?

The things that run on a JFrame are the same as the ones on a JApplet?

回答1:

As I recommended in one of your previous questions, you should re-organize your program to conform to the Model-View-Controller pattern, or one of its variants, as this will allow you to cleanly separate out the control code (that called by the ActionListener) from the GUI. For an example of an M-V-C program, please check out my suggestions and code in this recent answer.



回答2:

Well okay first check this out: action listener in another class - java

now all you have to do is edit it to your needs, and in the actionPerformed(ActionEvent ae) you will then get the values in controlB.java class by accessing the data using a accessor/get method or make the Actionlistener class extend the ControlB so it will have access to all its public data, then once you have the values, pass them to the Graph.java either during initiation or using a mutator/set method?



回答3:

Some class, preferably an inner class of B if you're going to allow input only from JPanel B, has to implement ActionListener. That ActionListener has to be added to the JTextField:

myInputTextField.addActionListener(theActionListenerIAmGoingToWrite). 

That ActionListener has to define actionPerformed() something like this :

String text = inputTextField.getText();
Integer inputInteger = Integer.getInteger(text).toInt(); 
graph.doStuffWithIntegerInput(inputInteger);

The design questions to be answered are :

Is the ActionListener an anonymous inner class? If you're only going to use it with a specific instances of graph and B which know about each other, then go this way. If so, it has to get a reference to the Graph instance from its containing class, which implies B has such an instance to offer it.

Is the action of the ActionListener reusable elsewhere? Will the "enter numbers" widget appear elsewhere on other JPanels? If so make it a stand alone class. You still need a reference to graph so either graph in as a constrcutor parameter and/or have a setGraph method because somehow it needs to know about the graph instance so it can send it a message.

done!

edit 2

OK so let's map what you have to an MVC framework. So your view consists of the Graph class and your class B and your textFields.

Now contained within your graph class, you also have the data you want to graph. That's the start, finish, x , y variables you've defined. To be a good citizen of MVC-land, you would have to pull these out and contain them within a separate object b/c they constitute the model of your graph. A model is, very basically, the set of facts you wish to present, irrespective of how they are going to be presented, while the view is all the code concerned with painting stuff to the screen.

So this model object would be a simple data object with getters and setters for all the variables you've defined and would be passed into the Graph object either at the constructor or through a setter on the Graph object.

By creating this GraphData object, you've separated the view, the Graph from it's model the GraphData object.

With a more complicated Graph, you'd actually specify in a GraphModel what "kind" of Graph object you want to create, what the axis names would be, what kind of line you want to draw, stuff like that, but that's overkill for what you have.

OK so now you have your Graph and GraphData objects and some way to get them together.

Next let's look at your class B. Since it's a JPanel, a view, it's essentially an aggregator and presenter of its contained Views. Those would be the Graph and the JTextFields. So you add them as you have, specifying the layout.

So a hypothetical refactoring goes like this:

Create main program. In that main create: JTextFields, ActionListener, JPanel (B), Graph and GraphModel.

Associate GraphModel with Graph.

Associate Graph with JPanel.

Associate ActionListener with JJtextField

Associate JTextField with JPanel

As far as writing ActionListener goes just make it its own class, that's the easiest to write and understand. So thus:

public class MyTextFieldListener implements ActionListener
{
   private Graph graph;
   public   MyTextFieldListener(Graph graph)
   {   
      this.graph = graph;
   }// construtor

   public void actionPerformed (ActionEvent ae) 
  {
      String text =  ((JTextField)ae.getSource()).getText();
      Integer inputInteger = Integer.getInteger().(text).toInt();
      graph.doStuffWithIntegerInput(inputInteger); 
  } // actionPerformed
}// class

Now a complication could be that you can't update the graph until you have info from all four textfields. There are different ways to change this code to accommodate that but this is the basic idea of where you need to go.

HTH



回答4:

OK. Let's talk about your RangeXY object. What is its purpose? I ask because it seems to not need anything from the JTextFields , that is from the user input.

Where you're calling graph.doStuffWithIntegerInput(), actually, you're not using the integer input from the user, which is what comes from the text field. You're using (and this is just wrong) an int you passed into the constructor of RangeXY. Then you're (and here comes the "just wrong" part) giving that int to the Integer static method getInteger(). Actually, that wouldn't compile since getInteger takes a String and turns it into an Integer.

OK so let's just do this. Do one thing at a time. First, write a class that fits this description:

It implements ActionListener; It has a member variable for Graph; THe member variable for Graph is set either in a setter or passed in to the constructor. It has an EMPTY actionPerformed method (for now)

Just do that and we'll take it from there.