getActionCommand() vs getSource() - java

For the longest time I have been invoking getActionCommand on ActionEvent objects to retrieve information from some JButtons, but as my programs grew more complex, I wanted to send several bits of information through setActionCommand, i.e. having a command like "r3" to indicate to the Action Listener that I wanted to remove the 3rd button from a panel within a JFrame. Eventually, I grew tired of parsing the strings and extracting the information that I wanted to use and instead started using getSource. (I want to know which one is better to use to retrieve information)
Also, I created a subclass of JButton called OperationButton that has two instance fields: an int ID and an Operation op (Operation is a custom enumerated type whose values are ADD, REMOVE, SWITCH, etc). I want to know if the following method is more efficient/a better practice than simply using getActionCommand, or if there is a third way of handling events that I have not thought of yet.
public void actionPerformed(ActionEvent e)
{
OperationButton opButton = (OperationButton) e.getSource();
int ID = opButton.getID();
Operation op = opButton.getOperation();
switch (op)
{
case ADD: //adds a custom panel to frame
break;
case REMOVE: //removes a button and a custom panel with the specified ID
break;
case SWITCH: //highlights a button with the specified ID and
//displays a custom panel with the specified ID
//...
}
}
(OperationButtons are the only buttons in my program)
Again, I want to retrieve information without having to set the action command of a JButton, but I'm not entirely sure if this is the right way to go. Also, would this method be feasible for future programs in which I might want to send more than 2 pieces of information?

Related

Java - drawing a sudoku - How to build the code in the right way?

(A general Question)
I have an assignment in which I have to build a sudoku and I thought about the classes/logic to build it and thought I could use an advice.
I want to use a JFrame and build on it a JPanel with TextFields (the user is supposed to "solve" the sudoku).
I have a class called "DrawSudoku" which draws an empty board. I have to draw an empty board first, so the "user" can type numbers in it.
On that board I have to check some logic. So I have to access the textFields themselves.
So far that's all I've done. Now I am thinking about building another class with the "logic" behind the board.
But I've encountered a problem
How do I get the JTextFields that exists on the JPanel, from another class?
Can I have separate classes for the Drawing and Logic Behind it?
Thanks!
On that board I have to check some logic. So I have to access the textFields themselves.
Not necessarily
How do I get the JTextFields that exists on the JPanel, from another class?
How do you assess the state of any object from another object -- via an accessor or "getter" method.
Can I have separate classes for the Drawing and Logic Behind it?
Not only can you, you absolutely should.
If this were my project I would consider doing the following:
First and foremost, create a non-GUI Sudoku model class. This could include:
SudokuCellValue enum (name it what you want), an enum that can hold a value from 1 to 9 as well as possibly an EMPTY value (although you could use null to represent this)
SudokuCell objects, ones that have boolean editable, and holds a single value to the above enum.
SudokuGrid object, a 9 x 9 grid of SudokuCells.
A mechanism to hook listeners into the model so that they are notified of changes in state -- i.e., changes in the SudokuCellValue held by one or more SudokuCell objects. The View (the GUI) will be one of the major listeners to this model, and will change its display when the model's state changers.
I'd create a View class, meaning the GUI,
One that holds a reference to its model (see above)
and one that has attached listeners to its model -- I like to use PropertyChangeListeners for this
I'd hook it up with a grid of JTextFields,
These text fields would use a DocumentFilter to allow the user to either clear the field or enter only 1 through 9 single digit numeric text.
Would be enabled for input (or perhaps better -- focusable for input), based on the editable state of the corresponding model cell.
I'd create a Controller that would control some of the communication between the view and model.
With this type of set up, outside classes could listen for changes to the model and wouldn't have to have any access directly to the JTextFields of the view.
You don't need to have access to the text fields themselves if you include public methods in your DrawSudoku class that your logic class can then call. This would be very similar to writing getter and setter methods for private variables. For example, if you wanted your logic class to be able to write the number "6" into a certain square on the board, you could write a method in DrawSudoku like this:
public void setSquareText(String text, int row, int column) {
// change the appropriate text field here
textField.setText(text);
}
Then, call this method in your logic class, by making an instance of the drawing class:
DrawSudoku drawer = new DrawSudoku();
drawer.setSquareText("6", 1,1);
Alternatively, you could write a method in DrawSudoku that returns a given JTextField, like this:
public JTextField getTextField(int row, int column){
// find the appropriate text field, then return it
return textField;
}
Then, call this method in your logic class to get access to the JTextField, like this:
JTextField textField = drawer.getTextField(1,1);
textField.getText();
textField.setText("6");

how do I re-use an action listener multiple times on a JTextField in java?

My program is supposed to get information about a person (first and last names, address, phone) so that it can add the person into an address book.
I made a JLabel which gives instructions on what to enter right below. Below the JLabel is a JTextField which has an ActionListener listening to what is being entered. My method has about 8 ActionListener's with 8 actionPerformed methods. I am running into trouble it is not working. I can't figure out any other way.
Best to create a form, perhaps with GridBagLayout or MigLayout that holds displays JLabel/JTextField pairs, so that the user can enter all the data on a single simple form, much like most software you use.
If you absolutely must use a single JTextField, then you should use a single ActionListener, but change how it responds based on the state of the GUI. That is, perhaps use an int counter variable, that you increment each time data is entered, and base what the listener does with the data based on the value held by the counter.
You can create an instance of the listener and reuse it across the class, like:
...
OnChangeListener listener = new OnChangeListener() {
//All the code here
};
...
textField1.addOnChangeListener(listener);
textField2.addOnChangeListener(listener);
textField3.addOnChangeListener(listener);
...

Disable source button upon click with actionPerformed

I am working on a GUI java program for class where there are 10 numbered buttons in a grid layout. The user is trying to guess a 3 digit number where each digit is unique. When they click a number the corresponding number should be stored as one of the digits in the guess and then the button should be disabled. This is done in the actionPerformed method.
My problem is how to tell which button is disabled.
Currently I am trying to successfully read the value and disable the button for one digit and my code looks like this:
private class NumberListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent click){
Object source = click.getSource();
keyTry1 = getButtonNumber(source);
source.setEnabled(false); //error
}
However at the line I marked error NetBeans complains that source has no method setEnabled, presumably because in the method it is declared as type Object. However if I try to declare it as JButton I cannot use click.getsource();
I know I could go the brute force approach and have a long string of if/else statements or even another method which disables the button based on the number it represents, but I was wondering if there is a way to access source as a JButton, since it obviously is referencing a JButton.
source is an Object and does not have an setEnabled method, so it makes no sense to the compiler to allow you to make such a call. You need to first case the instance of source to it's appropriate class type.
Assuming you can guarantee that the source of the action is the button, you can use something like...
((JButton)click.getSource()).setEnabled(false);
If you can't guarantee that source is JButton, but might be component of some kind, you might even be able to use something like...
((Component)click.getSource()).setEnabled(false);
If you can't guarantee that, then you need to make appropriate checks (which you should do anyway)...
Object source = click.getSource();
if (source instanceof JButton) {
((JButton)source).setEnabled(false);
}
This concept is an example of Polymorphism, where one instance of an Object can act like one it's parents

I want to reset/reload a JFrame so all fields are set back to default value

I have several different text fields, combo boxes etc. I want to reset them all back to their defaults (as if the program was just opened) without doing it manually.. i.e. xField.text = "", or whatever.
I want to reset them all back to their defaults (as if the program was just opened) without doing it manually.
You will have to do it manually, but you can make it easier on yourself by organizing your code a bit.
For instance you can put your JTextComponents in an ArrayList<JTextComponent> and all other components of similar type into their own List as well. Then in your resetAll() method that you will write, iterate through all these lists resetting all components.
i.e.,
public void reset() {
// for all JTextFields and JTextAreas
for (JTextComponent textComponent: textComponentList) {
textComponent.setText("");
}
// for all JCheckBoxes and JRadioButtons
for (JToggleButton toggleButton: toggleButtonList) {
toggleButton.setSelected(false);
}
// iterate through other lists doing likewise
}
Another way, which I don't recommend is to recursively go through all the components of your GUI, getting the type via instanceof and then setting the components based on type.

How to implement undo/redo in Java for MVC model?

I am having trouble understanding the undo/redo functions using UndoManager, and integrating it with the MVC model.
I am not sure where to put the various methods(in model, view or control)
and I am still not sure how to use the undo manager.
My control class implements UndoableEditListener
It creates:
private UndoManager manager = new UndoManager();
and in:
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("Undo")) {
try {
manager.undo();
} catch (CannotUndoException ex) {
ex.printStackTrace();
}
}
}
I understand up to here, but the rest I am not sure what to do. I know I will have to add more in the model and view class, but not sure where.
DO I have to have the following classes?
public class UndoAction extends AbstractAction {}
public void undoableEditHappened(UndoableEditEvent e) {
I am simply placing an integer number in a textfield, and then I want to be able to undo this.I set the number in the textfield in the view class.I want to acheive this the simplest way possible, no fancy coding! This is a minor part of my assg but I just cant get it working!!
==========================================================
Here is a more detailed description of my code, maybe it will help:
I have a model, view and control package.
Contol has:
ButtonGUIControl.java, which implements both
ActionListener and
UndoableEditListener.
final UndoManager manager = new UndoManager();
In the actionPerformed method, it calls
if (e.getActionCommand().equals("Undo")){
try {
manager.undo();
}
and in:
public void undoableEditHappened(UndoableEditEvent evt) {
manager.addEdit(evt.getEdit());
}
In the View:
Grid.java , which extends JTextField will add the following, wherever it needs to display a number on the GUI:(model is simply an instance of my Model class)
getDocument().addUndoableEditListener(new ButtonGUIControl(model));
Could it be because the UndoManager is being created in a different package? I really have no idea how to debug this anymore!!
I could post my entire code if that helps. I guess Im not sure how to integrate this with my mvc model structure.
Take a step back for a second. The whole idea here is that a user will use your app and will make a series of changes to something. A text editor is a good example. You can insert characters and lines, delete them again, replace text with other text, scroll the text, etc. In order to support this with MVC you have a model that holds state and a View that displays it.
Your first instinct might be to have the view directly access the model, and then refresh the view every time the user makes a change, but it's very hard to undo those changes with that implementation. Instead, you encode every kind of change the user can make in classes that are able to perform that change and can later undo that change.
For example, an action that inserts text would be implemented by a class that knows the character offset of the insertion point and the string of characters that is to be inserted. The perform action would insert the string at the offset and the undo action would remove the right number of characters after that insertion point. You'd have a different class that would handle deletion, another to handle scrolling etc.
Every time the user takes some action, the view would construct one of these UndoableEdit classes and would tell the instance to run itself (redo()). Once executed, you put that UndoableEdit at the end of a list of UndoableEdit instances that represent all of the actions the user has taken so far. This list makes it very easy to support any sequence of undo requests, redo requests and actual edit actions (resulting in more UndoableEdit's being put on the list).
So back to your question. If your app needs to support undo and redo, then you'll need to implement an UndoManager which simply manages the list of UndoableEdit's and performs undo and redo as necessary. You also have to implement a whole bunch of UndoableEdits, one for each kind of thing your user will do against the UI. As for a listener, I can't see that you really need to do that one.
If you need only simple undo/redo, you can use UndoManager as it is, you don't need to subclass or customize it in any way.
JTextField (more specifically its model, the Document) has some built-in support for undo, which means you don't need to write UndoableEdit implementations either, the UndoableEdit objects will be automagically created for you (actually AbstractDocument.DefaultDocumentEvent implements UndoableEdit).
Full simple working example is here

Categories

Resources