800 likes | 877 Views
Object-Oriented Programming (Java), Unit 28. Kirk Scott.
E N D
Object-Oriented Programming (Java), Unit 28 Kirk Scott
LitlaDimun is a small island between the islands of Suouroy and StoraDimun in the Faroe Islands. It is the smallest of the main 18 islands, being less than 100 hectares (250 acres) in area, and is the only one uninhabited. The island can be seen from the villages Hvalba and Sandvik. • The southern third of the island is sheer cliff, with the rest rising to the mountain of Slaettirnir, which reaches 414 metres (1,358 ft). The island is only inhabited by feral sheep and seabirds. Getting ashore is difficult and can only be performed in perfect weather. The cliffs can be climbed with the aid of ropes placed by the owners of the sheep.
Actions, Multicasting, and Text Areas • 28.1 Actions and Multicasting • 28.2 Text Areas
MiscAction • This is the key idea of this example: • Having more than one different event trigger the same listener. • The example program illustrates this in the following way: • Clicking the Swap button triggers the swap listener • Pressing the key combination CTRL+S triggers exactly the same listener code.
Keyboard input was initially given with the ClickKey example. • You may have had some trouble getting both keystrokes and other actions to work using that approach. • The approach given here is a more general solution.
It is your choice which approach to use in the final project. • The point of these tail-end units in the course is to give you options for the project. • In programming, you typically have choices to make. • No path is ideal. • Each has its own pitfalls.
A screenshot of the application is shown below. • There is no change in the appearance of this example from the previous example.
This example illustrates the use of something called an action object • This is attached to both the button and the keystroke combination. • It is only necessary to make changes in the panel class in order to accomplish this.
The following UML diagram is not a diagram of the complete application. • It shows the structure of the subset of the application which is new or different from previous examples. • In other words, it shows how the action object, and instance of SwapAction, is tied to both a button and a keystroke. • (It isn’t pretty)
The code is shown for that part of the application where there are changes from the previous example or new elements. • The parts of the MiscActionPanel() constructor which are different from the panel constructor in the previous example are given on the following overheads.
public MiscActionPanel() • { • … • /* Step 1. Create the swap action object. */ • /* This is the listener for the application. */ • Action swapActionObject = new SwapAction("Swap");
/* Step 2. Create a button, giving it the swap action object. */ • JButtonmyButton = new JButton(swapActionObject);
/* Step 3. Attach the button to the application as usual. */ • JPanelbuttonPanel = new JPanel(); • buttonPanel.add(myButton); • add(buttonPanel);
/* Step 4. This is part of the application that is focus related. */ • /* Get the input map belonging to the panel under construction. */ • /* Notice how this is analogous to getting a content pane. */ • /* A panel, by definition, has an input map associated with it. */ • InputMapinmap = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
/* Step 5. This continues the part of the application which is focus related. • /* You call the put() method on the input map. */ • /* You give it two parameters: */ • /* The first parameter is the keystroke combination of interest. */ • /* The second parameter is a symbolic name that will be associated with this keystroke combination. */ • inmap.put(KeyStroke.getKeyStroke("ctrl S"), "registerswap");
/* Step 6. This is part of the application that is related to connecting the input map and the swap action object. */ • /* Get the action map belonging to the panel under construction. */ • /* Notice how this is analogous to getting a content pane. */ • /* A panel, by definition, has an action map associated with it. */ • ActionMapactmap = getActionMap();
/* Step 7. This is the last step, which glues things together. */ • /* You call the put() method on the action map. */ • /* You give it two parameters: */ • /* The first parameter is the symbolic name of the input keystroke combination of interest. */ • /* The second parameter is the swap action object. */ • /* When the keystroke combination occurs, the action object listener will be called. */ • actmap.put("registerswap", swapActionObject); • }
If you cut out the messy details, it’s these two lines of code which give the same listener to the button and the keystroke combination: • JButtonmyButton = new JButton(swapActionObject); • … • actmap.put("registerswap", swapActionObject);
The class SwapAction is a new inner class of the MiscActionPanel class. • The code for SwapAction is given on the overhead following the next one. • This example is slightly different from previous examples. • It includes a constructor. • The constructor includes a parameter.
These details are not of great practical consequence to the application. • However, they do illustrate one thing. • We are creating a generic action, not a listener for something that is predefined (like a particular mouse click). • We are seeing the machinery that makes it possible to associate names and other information with something generic.
What is of consequence, as usual, is the actionPerformed() method. • This is the code that is run when the listener is triggered, whether by a button click or the keystroke combination. • The code is shown on the following overhead.
private class SwapAction extends AbstractAction • { • public SwapAction(String name) • { • putValue(Action.NAME, name); • putValue(Action.SHORT_DESCRIPTION, "Swap register contents."); • } • public void actionPerformed(ActionEvent event) • { • registerA.swapRegisterContents(registerB); • } • }
This application, MiscAction, is a standalone example. • The elements in it that support responsiveness to the keyboard are not retained in future examples. • Keep in mind the point of the example: • More than one event can trigger the same action. • In other words, more than one different event can cause the same actionPerformed() method to be executed.
MiscMulti • In the previous example, different events could trigger the same listener. • The MiscMulti example illustrates the converse idea. • There are many listeners for one event. • This structure in a program is known as multicasting.
This example is one more step removed from practicality than the previous example • It might be possible to dream up areas of the final project where you could apply this idea • However, it would probably not be a good idea to do down that path • This example is presented as background information that might be useful to you in the future
This application illustrates the idea of multicasting in the following way: • There are two registers. • When each register is constructed, a button listener will be constructed in it.
There is a single clear button. • The two button listeners, one for each register, will be added to the button. • Each of the listeners listens for the same event, the clicking of the clear button. • In short, one event triggers two listeners.
The visual result of clicking the clear button is that both of the text fields have their values set to 00000000. • Not only should the text fields be cleared, but the state or model underlying them should also be changed • The screenshot given on the following overhead shows the result of clicking the clear button.
The following UML diagram is not a diagram of the complete application. • It shows the structure of the subset of the application which is new or different from previous examples. • It contains the class FieldButtonActionListener. • The class name is meant to suggest that this is the listener for the button which affects the contents of the text fields.
On the following overhead the parts of the MiscMultiPanel() constructor which are different from the panel constructor in the previous example are given. • One button is constructed. • A reference to that button is passed to each of the registers when they are constructed.
public MiscMultiPanel() • { • JButton myButton2 = new JButton("Clear"); • registerA = new MiscMultiRegister("11110000", myButton2); • registerB = new MiscMultiRegister("00001111", myButton2); • … • JPanel buttonPanel2 = new JPanel(); • buttonPanel2.add(myButton2); • add(buttonPanel2); • }
The following overhead shows the MiscMultiRegister() constructor. • In it an action listener is created and added to the button which is passed in as a parameter. • Keep in mind that two registers are constructed in the application, so construction of a listener happens twice, once for each register. • However, in both cases it is the same button that is passed in that has the listener added to it.
public MiscMultiRegister(String stringIn, JButtonbuttonIn) • { • registerByte = new MiscMultiByte(stringIn); • myField = new JTextField(stringIn, 8); • TextFieldListenermyListener = new TextFieldListener(); • myField.addActionListener(myListener); • FieldButtonActionListenermyActionListener = new FieldButtonActionListener(); • buttonIn.addActionListener(myActionListener); • }
The code for the listener class for the clear button is shown on the next overhead. • It is an inner class of the MiscMultiRegister class. • All aspects of the code will be explained in detail on the overheads following this complete listing of the class.
private class FieldButtonActionListener implements ActionListener • { • public void actionPerformed(ActionEvent event) • { • registerByte.setByteToThisString(MiscMultiByte.junk); • myField.setText(registerByte.getStringFromByte()); • } • }
Each time a register is constructed, a listener is constructed. • When the button is clicked, both listeners are triggered. • Each listener makes calls on registerByte and myField. • Those are the objects that belong to a register.
registerByte is part of the model of the application. • myField is part of the view of the application. • Each of the instances of the register class have a registerByte and a myField instance variable. • The two listeners refer, respectively, to these instance variables of the two registers.
The listener code contains this call: • registerByte.setByteToThisString(MiscMultiByte.junk); • For the one listener, this applies to the registerByte instance variable of the instance of the outer class, MiscMultiRegister, which that listener was constructed in. • For the other listener, this applies to the registerByte of the MiscMultiRegister which it was constructed in.
Similarly, the listener code also contains this call: • myField.setText(registerByte.getStringFromByte()); • Just like with the registerByte, for one of the listeners, this applies to the myField instance variable of the register it was constructed in. • For the other listener, it applies to the myField instance variable of the register it was constructed in.
Incidentally, the first line of the listener code makes use of this static variable: • MiscMultiByte.junk. • This shows the declaration of the variable junk in the MiscMultiByte class. • This provides the value in the listener which clears the register by setting their contents to all 0’s. • public static final String junk = "00000000";
MiscMulti is a standalone example. • The elements in it that support a clear button with multicasting are not retained in future examples.