Good Day,
I am writing a custom event handler in Java. I have a class called BoogieCarMain.java that instantiates three instances of a type called BoogieCar. Whenever any of the three instances exceeds a certain speed limit, then an event should be fired off. The code I currently have is working, so here is what I have:
// BoogieCar.java
import java.util.ArrayList;
public class BoogieCar {
private boolean isSpeeding = false;
private int maxSpeed;
private int currentSpeed;
private String color;
BoogieSpeedListener defaultListener;
public BoogieCar(int max, int cur, String color) {
this.maxSpeed = max;
this.currentSpeed = cur;
this.color = color;
}
public synchronized void addSpeedListener(BoogieSpeedListener listener) {
defaultListener = listener;
}
public void speedUp(int increment) {
currentSpeed += increment;
if (currentSpeed > maxSpeed) {
processSpeedEvent(new BoogieSpeedEvent(maxSpeed, currentSpeed, color));
isSpeeding = true;
} else {
isSpeeding = false;
}
}
public boolean getSpeedingStatus() {
return isSpeeding;
}
private void processSpeedEvent(BoogieSpeedEvent speedEvent) {
defaultListener.speedExceeded(speedEvent);
}
}
// BoogieCarMain.java
import java.util.ArrayList;
public class BoogieCarMain {
public static void main(String[] args) {
BoogieCar myCar = new BoogieCar(60, 50, "green");
BoogieCar myCar2 = new BoogieCar(75, 60, "blue");
BoogieCar myCar3 = new BoogieCar(65, 25, "pink");
BoogieSpeedListener listener = new MySpeedListener();
myCar.addSpeedListener(listener);
myCar2.addSpeedListener(listener);
myCar3.addSpeedListener(listener);
myCar.speedUp(50); // fires SpeedEvent
System.out.println(myCar.getSpeedingStatus());
myCar2.speedUp(20);
System.out.println(myCar2.getSpeedingStatus());
myCar3.speedUp(39);
System.out.println(myCar3.getSpeedingStatus());
}
}
// BoogieSpeedListener.java
public interface BoogieSpeedListener { // extends java.util.EventListener
public void speedExceeded(BoogieSpeedEvent e);
}
// MySpeedListener.java
public class MySpeedListener implements BoogieSpeedListener {
#Override
public void speedExceeded(BoogieSpeedEvent e) {
if (e.getCurrentSpeed() > e.getMaxSpeed()) {
System.out.println("Alert! The " + e.getColor() + " car exceeded the max speed: " + e.getMaxSpeed() + " MPH.");
}
}
}
// BoogieSpeedEvent.java
public class BoogieSpeedEvent { // extends java.util.EventObject
private int maxSpeed;
private int currentSpeed;
private String color;
public BoogieSpeedEvent(int maxSpeed, int currentSpeed, String color) {
// public SpeedEvent(Object source, int maxSpeed, int minSpeed, int currentSpeed) {
// super(source);
this.maxSpeed = maxSpeed;
this.currentSpeed = currentSpeed;
this.color = color;
}
public int getMaxSpeed() {
return maxSpeed;
}
public int getCurrentSpeed() {
return currentSpeed;
}
public String getColor() {
return color;
}
}
My question is: While this code works, I would like the BoogieCar type to notify BoogieCarMain directly without me have to "poll" the BoogieCar type by having to invoke the getSpeedingStatus() method.
In other words, perhaps defining a variable in BoogieCarMain.java that changes whenever one of the three cars exceeds its predefined speed limit. Is it possible to have the BoogieCar type set the variable?
Is there a cleaner way to do this?
TIA,
coson
Callbacks are ideal for this scenario.
// BoogieCarMain provides a sink for event-related information
public void handleSpeeding(BoogieCar car) {
System.out.println(car.getSpeedingStatus());
}
// MySpeedListener knows about an object that wants event-related information.
// I've used the constructor but an addEventSink method or similar is probably better.
public MySpeedListener(BoogieCarMain eventSink) {
this.eventSink = eventSink;
}
// MySpeedListener handles events, including informing objects that want related information.
// You decide if the event is an appropriate type for the sink to know about.
// Often it isn't, and instead your listener should pull the relevant info out of the event and pass it to the sink.
public void speedExceeded(BoogieSpeedEvent e) {
if (e.getCurrentSpeed() > e.getMaxSpeed()) {
// I've taken the liberty of adding the event source as a member of the event.
eventSink.handleSpeeding(e.getCar());
}
}
Related
I have a class Player that has three variables, one of these is a List<List<Box>> and of course class Box does implement Serializable.
Box has some variables too, all of them are primitive types except for a class Dice which does implement Serializable too.
I have to send this class through the network with a socket and when I send this to the Client side the List<List<Box>> looks ok, and each Box too, the problem is that the Dice class that should be in the Box is always set to null even if the one I sent to the Client from the Server is not and I am absolutely sure that the network part is correct.
Forgot to mention that List<List<Box>> when instantiated becomes an ArrayList<ArrayList<Box>> which should be Serializable.
Dice class:
package ingsw.model;
import java.io.Serializable;
import java.util.Random;
public class Dice implements Serializable {
private int faceUpValue;
private final Color diceColor;
public Dice(Color diceColor) {
this.diceColor = diceColor;
}
public Dice(int faceUpValue, Color diceColor) {
this.faceUpValue = faceUpValue;
this.diceColor = diceColor;
}
/**
* Draft the dice
* get a random number between 1 and 6 and set the faceUpValue
*/
void roll() {
int value = (new Random()).nextInt(6) + 1;
setFaceUpValue(value);
}
public int getFaceUpValue() {
return faceUpValue;
}
public void setFaceUpValue(int faceUpValue) {
this.faceUpValue = faceUpValue;
}
public Color getDiceColor() {
return diceColor;
}
#Override
public String toString() {
if (faceUpValue != 0) {
return diceColor.toString() + String.valueOf(faceUpValue);
} else {
return diceColor.toString();
}
}
}
Card class implements Serializable:
public abstract class PatternCard extends Card {
private int difficulty;
protected List<List<Box>> grid;
public PatternCard(String name, int difficulty) {
super(name);
fillGrid();
this.difficulty = difficulty;
}
#Override
public String toString() {
return "PatternCard{" +
"'" + getName() + "'" +
'}';
}
public int getDifficulty() {
return difficulty;
}
public void setGrid(List<List<Box>> grid) {
this.grid = grid;
}
public List<List<Box>> getGrid() {
return grid;
}
private void fillGrid() {
this.grid = new ArrayList<>(4);
this.grid.add(new ArrayList<>(5));
this.grid.add(new ArrayList<>(5));
this.grid.add(new ArrayList<>(5));
this.grid.add(new ArrayList<>(5));
}
}
Box class:
public class Box implements Serializable {
private Color color;
private Integer value;
private Dice dice;
public Box(Color color) {
this.color = color;
}
public Box(Integer value) {
this.value = value;
}
public Color getColor() {
return color;
}
public Integer getValue() {
return value;
}
public boolean isValueSet() {
return value != null;
}
public void insertDice(Dice dice) {
this.dice = dice;
//TODO the dice at this point must removed from the dice drafted --> dices (set).remove();
}
public void removeDice() {
if (dice != null) dice = null;
//TODO dice must be re-added?
}
public Dice getDice() {
return dice;
}
#Override
public String toString() {
if (isValueSet()) return String.valueOf(value);
else return color.toString();
}
Boolean isDiceSet(){ return dice != null; }
}
I've investigated a bit and thought that I should probably Serialize the object and De-serialize it by myself but I don't know if that could be the real issue here since ArrayLists are Serializable and every object inluded in these ArrayLists are too.
What could possibly be wrong in this?
I have an issue with JavaFX TableView UI update. After I change the observable object, it does not update the UI of TableView. But if I perform a magical ritual of pulling TableView's scroll bar down and up again - it seems to redraw the table and update items in it.
Through debugging I've ensured, that the PreferencesSet ArrayList and object are updated correctly.
Here's gif demonstration of what is happening
This is my first time asking a question here, so I could have left out some important info. Feel free to ask me for it. Thank you in advance.
Here's code (I have left out unrelated stuff):
ControllerClass:
public class TestSomethingController implements Initializable {
public TableView<PreferenceValues.PreferencesSet> preferencesTable;
public TableColumn mdColumn;
public TableColumn typeColumn;
public TableColumn tradeColumn;
public TableColumn plastColumn;
public TableColumn capColumn;
public TableColumn multColumn;
public TableColumn sizeColumn;
#Override
public void initialize(URL location, ResourceBundle resources) {
setNorthPanel();
setTableColumns();
fillAllInfo();
}
private void setTableColumns() {
mdColumn.setCellValueFactory(new PropertyValueFactory<PreferenceValues.PreferencesSet, MarketDirection>("md"));
typeColumn.setCellValueFactory(new PropertyValueFactory<PreferenceValues.PreferencesSet, UserOfferType>("type"));
tradeColumn.setCellValueFactory(new PropertyValueFactory<PreferenceValues.PreferencesSet, Boolean>("trade"));
plastColumn.setCellValueFactory(new PropertyValueFactory<PreferenceValues.PreferencesSet, Long>("plast"));
capColumn.setCellValueFactory(new PropertyValueFactory<PreferenceValues.PreferencesSet, Double>("cap"));
multColumn.setCellValueFactory(new PropertyValueFactory<PreferenceValues.PreferencesSet, Double>("mult"));
sizeColumn.setCellValueFactory(new PropertyValueFactory<PreferenceValues.PreferencesSet, Long>("size"));
}
private void fillAllInfo() {
preferencesTable.setItems(FXCollections.observableArrayList(CurrentSession.currentUser.getPreferencesList()));
fillNorthPanel();
}
public void applyClicked(ActionEvent actionEvent) {
applyNorthPanelChanges();
}
private void applyNorthPanelChanges() {
PreferenceValues.PreferencesSet preferencesSet = CurrentSession.currentUser.getPreferencesSet(dirChoiceBox.getSelectionModel().getSelectedItem(), offerTypeChoiceBox.getSelectionModel().getSelectedItem());
preferencesSet.setTrade(tradeCheckBox.isSelected());
preferencesSet.setPlast(plastSpinner.getValue());
preferencesSet.setCap(capRateSpinner.getValue());
preferencesSet.setMult(multSpinner.getValue());
preferencesSet.setSize(sizeSpinner.getValue());
preferencesSet.savePreferences();
}
User class:
public class User {
private PreferenceValues preferenceValues;
public PreferenceValues.PreferencesSet getPreferencesSet(MarketDirection md, UserOfferType userOfferType) {
return preferenceValues.getPreferencesSet(md, userOfferType);
}
public ArrayList<PreferenceValues.PreferencesSet> getPreferencesList() {
return preferenceValues.getPreferencesList();
}
}
PreferenceValues class:
import java.util.ArrayList;
import java.util.TreeMap;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;
public class PreferenceValues {
private Preferences preferences;
private ArrayList<PreferencesSet> preferencesList;
private TreeMap<String, PreferencesSet> preferencesMap;
public PreferenceValues(User user) {
preferencesList = new ArrayList<>();
preferencesMap = new TreeMap<>();
preferences = Preferences.userRoot().node("prefexample" + user.getwmId());
for (MarketDirection md : MarketDirection.values()) {
for (UserOfferType userOfferType : UserOfferType.values()) {
if (userOfferType != UserOfferType.UNDEF) {
PreferencesSet preferencesSet = new PreferencesSet(md, userOfferType, preferences);
preferencesList.add(preferencesSet);
preferencesMap.put(md.toString() + userOfferType.toString(), preferencesSet);
}
}
}
}
protected ArrayList<PreferencesSet> getPreferencesList() {
return preferencesList;
}
private String getMapKey(MarketDirection md, UserOfferType userOfferType) {
return md.toString() + userOfferType.toString();
}
protected PreferencesSet getPreferencesSet(MarketDirection md, UserOfferType userOfferType) {
return preferencesMap.get(getMapKey(md, userOfferType));
}
public void clear() throws BackingStoreException {
preferences.clear();
}
public class PreferencesSet {
Preferences preferences;
private MarketDirection md;
private UserOfferType type;
private boolean trade;
private int plast;
private double cap;
private double mult;
private int size;
public PreferencesSet(MarketDirection md, UserOfferType type, Preferences preferences) {
this.md = md;
this.type = type;
this.preferences = preferences;
trade = preferences.node(md.toString()).node(type.toString()).getBoolean("trade", false);
plast = preferences.node(md.toString()).node(type.toString()).getInt("plast", 222);
cap = preferences.node(md.toString()).node(type.toString()).getDouble("cap", 333);
mult = preferences.node(md.toString()).node(type.toString()).getDouble("mult", 1);
size = preferences.node(md.toString()).node(type.toString()).getInt("size", 15000);
}
public void savePreferences() {
preferences.node(md.toString()).node(type.toString()).putBoolean("trade", trade);
preferences.node(md.toString()).node(type.toString()).putInt("plast", plast);
preferences.node(md.toString()).node(type.toString()).putDouble("cap", cap);
preferences.node(md.toString()).node(type.toString()).putDouble("mult", mult);
preferences.node(md.toString()).node(type.toString()).putInt("size", size);
}
public MarketDirection getMd() {
return md;
}
public UserOfferType getType() {
return type;
}
public boolean isTrade() {
return trade;
}
public int getPlast() {
return plast;
}
public double getCap() {
return cap;
}
public double getMult() {
return mult;
}
public int getSize() {
return size;
}
public void setTrade(boolean trade) {
this.trade = trade;
}
public void setPlast(int plast) {
this.plast = plast;
}
public void setCap(double cap) {
this.cap = cap;
}
public void setMult(double mult) {
this.mult = mult;
}
public void setSize(int size) {
this.size = size;
}
}
}
Since the only way for PropertyValueFactory to retrieve the value is using the getter, changes of a property cannot be observed and therefore the update only happens, when the item is associated with a new TableRow.
Starting with JavaFX 8u60 you can simply call the refresh method of TableView, which will force an update to be executed.
However the usual way of doing this is by providing access to a property object containing the property value, e.g.
In PreferencesSet
private final IntegerProperty plast = new SimpleIntegerProperty();
public void setPlast(int plast) {
this.plast.set(plast);
}
public int getPlast() {
return plast.get();
}
// this method will be used by the PropertyValueFactory
// and returns a Property which notifies TableView of changes
public IntegerProperty plastProperty() {
return plast;
}
There are other property types for the other data types, see javafx.beans.property package
I'm writing a game-like program and it has a class that has to act as an item. Normally I would just keep it as an item but every one has to wait 10 game-days in order to start doing what it's meant to. Is there a way to update the days in all the classes at once? I've tried to use a static method but you can't use instance variables in those so it didn't work. I've thought about possibly making a code that expands every time a new instance is made but I can't find anything i can understand about it. Is there any way to add to a method, make this an item, anything? This is what I have at the moment:
public class Tree
{
private boolean fullGrown;
private int day;
private int APDay; //apples per day
private static int totalApples;
public Tree()
{
fullGrown = false;
day = 0;
APDay = (int) (Math.random()*2) + 4;
}
public void updateDay()
{
day = day + 1;
if (day == 10) fullGrown = true;
if (fullGrown == true) totalApples = totalApples + APDay;
}
public void skipGrowth()
{
fullGrown = true;
}
}
Although this works, you have to update the day for every instance separately. I need a way to update all the instances at the same time. This will also be used by a code and not the actual interface, just in case that's helpful.
Observer and factory pattern looks like a good candidate here.
I hope the code below explain rest to you
public interface DayEventListener {
public void onDay10(DayEvent DayEvent);
}
public class DayEvent {
//... pojo
}
public class AwesomeGame {
private List<DayEventListener> dayEventListenerList = new ArrayList<>();
public void addDayListener(DayEventListener del) {
dayEventListener.add(del);
}
public void fireDay10Event(DayEvent de) {
for(DayEventListener del : dayEventListenerList) {
del.onDay10(de);
}
}
public class Item implements DayEventListener {
//All constructors should be private
public static Item buildItem() {
Item Item = new Item();
awesomeGame.addDayEventListener(Item);
return item;
}
}
so I did some research and while I was working on another project I discovered that i could use a vector to keep track of all my instances, so here is that class:
import java.util.Vector;
public class catcher
{
private static Vector allInstances = new Vector();
private int catchLeft;
private String name;
public catcher(String name)
{
catchLeft = Integer.parseInt(name.substring(name.indexOf("#") + 1, name.length()));
catchLeft--;
this.name = name;
if (catchLeft != 0) allInstances.add(this);
}
public static synchronized Vector getAllInstances()
{
return (Vector) (allInstances.clone());
}
public boolean check(String name, boolean change)
{
boolean foo;
if (this.name.equals(name))
{
if (change == true) catchLeft--;
foo = true;
}
else foo = false;
if (catchLeft <= 0) this.finalize();
return foo;
}
public void finalize()
{
allInstances.removeElement(this);
}
public static void clear()
{
allInstances.clear();
}
}
now that I have a record of all the instances, I used this method in another class to assess all the instances:
import java.util.Iterator;
import java.util.Vector;
public class recipe
{
private boolean checkForList(String name, boolean add)
{
Iterator list = catcher.getAllInstances().iterator();
boolean running = true;
boolean booleanReturn = true;
while (running == true)
{
if (list.hasNext())
{
catcher Foo = (catcher) (list.next());
if (Foo.check(name, false) == true)
{
Foo.check(name, true);
running = false;
booleanReturn = true;
}
}
else
{
if (add == true) new catcher(name);
running = false;
booleanReturn = false;
}
}
return booleanReturn;
}
}
I'm sure that this can be modified to update the classes instead of just accessing them.
I have an assignment from my Java 1 class (I'm a beginner) and the question instructs us to make some code more object-oriented. I've done what I can for the assignment, but one of my files consistently gives me a Cannot Find Symbol Method error even though the files are in the same project. I know the methods are there, so what's going on? The error only occurs in AlienPack, which doesn't seem to recognize the other files, all of which are in the same project (including AlienPack). The getDamage() method that's being called in AlienPack isn't being found (it's in SnakeAlien, OgreAlien, etc).
EDIT: The new error for the getDamage() methods I'm trying to invoke in AlienPack is that the methods still aren't being found. AlienDriver can't find calculateDamage() either.
Here's the code I've got so far:
Alien:
public class Alien {
// instance variables
private String name;
private int health;
// setters
public void setName(String n) {
name = n; }
public void setHealth(int h) {
if(h>0&&h<=100) {
health = h;
} else {
System.out.println("Error! Invalid health value!");
System.exit(0); } }
// getters
public String getName() {
return name; }
public int getHealth() {
return health; }
// constructors
public Alien() {
setName("No name");
setHealth(100); }
public Alien(String n, int h) {
setName(n);
setHealth(h); }
public Alien(Alien anAlien) {
setName(anAlien.getName());
setHealth(anAlien.getHealth()); }
public Alien clone() {
return new Alien(this);
} }
SnakeAlien:
public class SnakeAlien extends Alien { // new file
// instance variables
private int damage;
// setters
public void setDamage(int d) {
if(d>0) {
damage = d;
} else {
System.out.println("Error! Invalid damage value!");
System.exit(0); } }
// getters
public int getDamage() {
return damage; }
// constructors
public SnakeAlien() {
super();
setDamage(0); }
public SnakeAlien(String n, int h, int d) {
super(n, h);
setDamage(d); }
public SnakeAlien(SnakeAlien anAlien) {
super(anAlien);
setDamage(anAlien.getDamage()); }
public SnakeAlien clone() {
return new SnakeAlien(this);
} }
OgreAlien:
public class OgreAlien extends Alien { // new file
// instance variables
private int damage;
// setters
public void setDamage(int d) {
if(d>0) {
damage = d;
} else {
System.out.println("Error! Invalid damage value!");
System.exit(0); } }
// getters
public int getDamage() {
return damage; }
// constructors
public OgreAlien() {
super();
setDamage(0); }
public OgreAlien(String n, int h, int d) {
super(n, h);
setDamage(d); }
public OgreAlien(OgreAlien anAlien) {
super(anAlien);
setDamage(anAlien.getDamage()); }
public OgreAlien clone() {
return new OgreAlien(this);
} }
MarshmallwManAlien:
public class MarshmallowManAlien extends Alien { // new file
// instance variables
private int damage;
// setters
public void setDamage(int d) {
if(d>0) {
damage = d;
} else {
System.out.println("Error! Invalid damage value!");
System.exit(0); } }
// getters
public int getDamage() {
return damage; }
// constructors
public MarshmallowManAlien() {
super();
setDamage(0); }
public MarshmallowManAlien(String n, int h, int d) {
super(n, h);
setDamage(d); }
public MarshmallowManAlien(MarshmallowManAlien anAlien) {
super(anAlien);
setDamage(anAlien.getDamage()); }
public MarshmallowManAlien clone() {
return new MarshmallowManAlien(this);
} }
AlienPack:
public class AlienPack { // new file, this one isn't recognizing the others
// instance variables
private Alien[] pack;
// setters
public void setPack(Alien[] aliens) {
pack = new Alien[aliens.length];
for(int i = 0; i<aliens.length; i++) {
pack[i]=aliens[i].clone(); } }
// getters
public Alien[] getPack() {
Alien[] temp = new Alien[pack.length];
for(int i = 0; i<pack.length; i++) {
temp[i]=pack[i].clone(); }
return temp; }
// constructors
public AlienPack() {
Alien[] nothing = new Alien[1];
nothing[0]=null;
setPack(nothing); }
public AlienPack(Alien[] aliens) {
setPack(aliens);}
// other methods
public int calculateDamage() {
int damage = 0;
for(int i = 0; i<pack.length; i++) {
if((new SnakeAlien()).getClass()==pack[i].getClass()) {
pack[i].getDamage() +=damage;
} else if((new OgreAlien()).getClass()==pack[i].getClass()) {
pack[i].getDamage() +=damage;
} else if((new MarshmallowManAlien()).getClass()==pack[i].getClass()) {
pack[i].getDamage() +=damage;
} else {
System.out.println("Error! Invalid object!");
System.exit(0); } }
return damage; } }
AlienDriver:
public class AlienDriver { // driver class
public static void main(String[] args) {
Alien[] group = new Alien[5];
group[0]= new SnakeAlien("Bobby", 100, 10);
group[1]= new OgreAlien("Timmy", 100, 6);
group[2]= new MarshmallowManAlien("Tommy", 100, 1);
group[3]= new OgreAlien("Ricky", 100, 6);
group[4]= new SnakeAlien("Mike", 100, 10);
System.out.println(group.calculateDamage());
} }
Two problems:
pack[i].getClass().getDamage() ...
should be just
pack[i].getDamage() ...
You seem to be confused about what the getClass() method does. It returns an object which represents the class (i.e. java.lang.Class) of another object. It is used for reflection. To invoke getDamage() you would just invoke it directly on pack[i] as shown above.
However...
You are attempting to invoke the method getDamage() using a reference of type Alien, which is a base class of all the concrete alien types. If you want to do it that way,
getDamage() needs to be declared abstract in the base class so it can be found and dispatched to the correct subclass when invoking it via an Alien reference.
In Alien:
public abstract class Alien {
...
public abstract int getDamage();
An alternative is to cast to the appropriate subclass at each point since you know what it is:
((SnakeAlien)pack[i]).getDamage() +=damage;
However (again) even that is wrong. You can't apply += to an "rvalue". What you need to do here is either:
Also declare setDamage() abstract in Alien and do pack[i].setDamage(pack[i].getDamage()+damage);
If casting, ((SnakeAlien)pack[i]).setDamage( ((SnakeAlien)pack[i].getDamage()) + damage);
My Recommendation:
In class Alien:
public abstract class Alien {
...
private int damage = 0; // Move damage up to the abstract base class
public int addToDamage(int n) { this.damage += n; }
...
}
In your driver, no need to test the class. Invoke the addToDamage() method on the Alien reference.
I think that at least part of your problem is the getClass() method. You are expecting it to return an object but it does not. Just call directly to the array.
pack[I].getDamage()
should work assuming that the correct type of object is stored in pack()
So thanks to the wonderful people here i've managed to get something semi workable, still have a couple bugs but maybe you guys can help me figure it out. So far none of the solution provided were a exact match (which is why i havent up voted them) but they did help me look at things in a new way and get things moving forward. So here is the current problem.
First the code then the explination
RaceButtons[RaceCounter] = new JToggleButton();
RaceButtons[RaceCounter].setIcon(RCiconSM);
RaceButtons[RaceCounter].setBorder(BorderFactory.createEmptyBorder());
RaceButtons[RaceCounter].setContentAreaFilled(false);
RaceButtons[RaceCounter].setActionCommand(temp_race.getRaceNameString(RaceCounter));
RaceButtons[RaceCounter].addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
Race race = new Race(1, 1, GenderList[PHYSICAL_SEX]);
race.setRaceID(race.getRaceIDFromString(ae.getActionCommand()));
//System.out.println(race.getraceID());
if (RaceButtons[race.getraceID()].isSelected()){
RaceButtons[race.getraceID()].setBorderPainted(true);
RaceButtons[race.getraceID()].setBorder(new LineBorder(Color.blue,2));
MyRaceArray.add(new Race(race.getraceID(), 1, GenderList[PHYSICAL_SEX]));
}else{
RaceButtons[race.getraceID()].setBorderPainted(false);
};
So first i create an array of Toggle buttons and when you click it it draw the border and then getting it's info i can add it to the array for races but this lives me with another problem i cant quite figure the logic off. Namly if there are already selected button it adds another instances to the button, it shouldn't do that it should ignore iexaisting entries but that means i have to check the arry for a matching object of type Race withthe same info right? What's the best way to do that?
And when you deselect it how do i remove that same object.
This is how your code should look like with a Race class:
import java.util.ArrayList;
import java.util.List;
public class Race {
private int raceID;
private double purity;
private int strMod;
private int dexMod;
private int conMod;
private int wisMod;
public int getRaceID() {
return raceID;
}
public void setRaceID(int raceID) {
this.raceID = raceID;
}
public double getPurity() {
return purity;
}
public void setPurity(double d) {
this.purity = d;
}
public int getStrMod() {
return strMod;
}
public void setStrMod(int strMod) {
this.strMod = strMod;
}
public int getDexMod() {
return dexMod;
}
public void setDexMod(int dexMod) {
this.dexMod = dexMod;
}
public int getConMod() {
return conMod;
}
public void setConMod(int conMod) {
this.conMod = conMod;
}
public int getWisMod() {
return wisMod;
}
public void setWisMod(int wisMod) {
this.wisMod = wisMod;
}
#Override
public String toString() {
return "Race [raceID=" + raceID + ", purity=" + purity + ", strMod="
+ strMod + ", dexMod=" + dexMod + ", conMod=" + conMod
+ ", wisMod=" + wisMod + "]";
}
public static void main(String args[]) {
//create a list of race objects
List<Race> raceCollection = new ArrayList<Race>();
//create a race object
Race race = new Race();
race.setRaceID(1);
race.setPurity(0.75);
race.setStrMod(5);
race.setDexMod(7);
race.setConMod(-2);
race.setWisMod(3);
//add race object to collection
raceCollection.add(race);
//You can create and add multiple objects of race to the collection
//Iterate your list and print the objects
for(Race raceObj:raceCollection) {
System.out.println(raceObj);
}
}
}
You will be able to make it work using an ArrayList of arrays, but that possibly isn't the best way in the long run. It can be very fiddly and error-prone to deal with - what happens when you insert a new race or attribute, but forget to to change the index somewhere?
Arrays and ArrayLists are usually best reserved for situations where you actually have a sequence / list (often with a meaningful sequence order).
In your case I'd be more inclined to adopt a prototype model. Typically in Java you would represent each race with a HashMap (or a data structure containing a HashMap), there the map represents the relationship between the "Attribute ID" and the "Default Value".
Creating a new elf is then just a case of initialising the elf's attributes using the default values from his race (or a average of different races, if you want...)
Some people may suggest making an OOP class with lots of named fields. This can also work, but IMHO a prototype model is better - it gives you much more flexibility in the long run. You often want to process large groups of attributes in the some way, and doing this is pretty messy if you have to refer to each of the attribute fields individually.
import java.util.ArrayList;
import java.util.List;
public class Race
{
private final int raceID;
private final double purity;
private final int strMod;
private final int dexMod;
private final int conMod;
private final int wisMod;
public Race (int raceID, double purity, int strMod, int dexMod, int conMod, int wisMod)
{
this.raceID = raceID;
this.purity = purity;
this.strMod = strMod;
this.dexMod = dexMod;
this.conMod = conMod;
this.wisMod = wisMod;
}
public int getRaceID ()
{
return raceID;
}
public double getPurity ()
{
return purity;
}
public int getStrMod ()
{
return strMod;
}
public int getDexMod ()
{
return dexMod;
}
public int getConMod ()
{
return conMod;
}
public int getWisMod ()
{
return wisMod;
}
#Override public String toString ()
{
return "RaceID:" + raceID
+ " purity:" + purity
+ " strMod:" + strMod
+ " dexMod:" + dexMod
+ " conMod:" + conMod
+ " wisMod:" + wisMod;
}
#override public int hashCode ()
{
return raceID;
}
#override public boolean equals (Race r)
{
return (r != null && this.raceID == r.getRaceID());
}
#override public Object clone ()
{
return new Race(this.raceID,this.purity,this.strMod,this.dexMod,this.conMod,this.wisMod);
}
public static void main(String args[])
{
// simple test
ArrayList<Race> races = new ArrayList<Race>();
Race a = new Race(0,0.5,1,2,3,4);
Race b = new Race(1,0.75,2,3,4,5);
Race c = new Race(2,0.25,-1,-2,-3,-4);
races.add(a);
races.add(b);
races.add(c);
for(Race race : races)
{
// System.out.println(race.toString());
System.out.println(race);
}
}
}
Then we have the visual model, which can be handled like this:
class RacePanel implements ActionListener
{
private Map<Integer,JToggleButton> r;
private Map<Integer,Race> f;
public RacePanel()
{
r = new TreeMap<Integer,JToggleButton>();
f = new TreeMap<Integer,Race>();
}
public JToggleButton add (Race a)
{
JToggleButton button = new JToggleButton();
button.setIcon(RCiconSM);
button.setBorder(BorderFactory.createEmptyBorder());
button.setContentAreaFilled(false);
button.setActionCommand(a.getRaceID());
button.addActionListener(this);
r.put(a.getRaceID, button);
f.put(a.getRaceID, a);
}
public void remove (int raceID)
{
r.remove(a.getRaceID);
f.remove(a.getRaceID);
}
// When a button is clicked
public void actionPerformed(ActionEvent e)
{
// related race
Race a = f.get(e.getActionCommand());
// clicked button
JToggleButton b = r.get(e.getActionCommand());
// ..
}
public ArrayList<JToggleButton> getButtonList ()
{
return new ArrayList<Value>(r.values());
}
public ArrayList<Race> getRaceList ()
{
return new ArrayList<Value>(f.values());
}
public Race getRace (int raceID)
{
return f.get(raceID);
}
public JToggleButton getButton (int raceID)
{
return r.get(raceID);
}
// ..
}