I am relatively new to Java programming. I am trying to make an application that acts a budget calculator and I wanted to implement an undo feature where I could perform multiple undos in a row to undo any numbers inputted in their respective fields. As of now the code can only perform one undo at a time. If I try to undo multiple times in a row, it will only undo once and prevent me from undoing further. Something I observed when trying to fix this was that the last text field in my UI does work as intended, where it will undo the whole textfield if I keep pressing the undo button. This makes me think I am implementing my stack incorrectly but I have yet to find a solution for this. The following are methods involved in the undo feature.
public void saveState() {
Map<String, Double> incomeValues = new HashMap<>();
Map<String, Double> spendingValues = new HashMap<>();
// Get current values from income fields
for (Map.Entry<String, JTextField> entry : incomeFields.entrySet()) {
String fieldName = entry.getKey();
JTextField field = entry.getValue();
String text = field.getText();
double value = text.isEmpty() ? 0 : Double.parseDouble(text);
incomeValues.put(fieldName, value);
}
// Get current values from spending fields
for (Map.Entry<String, JTextField> entry : spendingFields.entrySet()) {
String fieldName = entry.getKey();
JTextField field = entry.getValue();
String text = field.getText();
double value = text.isEmpty() ? 0 : Double.parseDouble(text);
spendingValues.put(fieldName, value);
}
stateStack.push(new BudgetState(new HashMap<>(incomeValues), new HashMap<>(spendingValues)));
}
public void undo(int count) {
while (count > 0 && !stateStack.isEmpty()) {
stateStack.pop();
count--;
}
BudgetState prevState = stateStack.isEmpty() ? null : stateStack.peek();
restoreState(prevState);
updateTotals();
}
public void restoreState(BudgetState state) {
Map<String, Double> incomeValues = state.getIncomeValues();
Map<String, Double> spendingValues = state.getSpendingValues();
// Set values in text fields
for (Map.Entry<String, Double> entry : incomeValues.entrySet()) {
String fieldName = entry.getKey();
double value = entry.getValue();
JTextField field = incomeFields.get(fieldName);
field.setText(String.valueOf(value)); // Set text field value
}
for (Map.Entry<String, Double> entry : spendingValues.entrySet()) {
String fieldName = entry.getKey();
double value = entry.getValue();
JTextField field = spendingFields.get(fieldName);
field.setText(String.valueOf(value)); // Set text field value
}
}
This is the other class which handles serves as a container to store and represent the state of income and spending values within the budget calculator application.
package Budget;
import java.util.*;
public class BudgetState {
private Map<String, Double> incomeValues;
private Map<String, Double> spendingValues;
public BudgetState(Map<String, Double> incomeValues, Map<String, Double> spendingValues) {
this.incomeValues = new HashMap<>(incomeValues);
this.spendingValues = new HashMap<>(spendingValues);
}
public Map<String, Double> getIncomeValues() {
return incomeValues;
}
public Map<String, Double> getSpendingValues() {
return spendingValues;
}
}
In the
undo
method you are usingpeek
to get the previous state from the Stack. Thepeek
method is for inspecting the top element but it doesn't remove it. Usepop
instead.Note that you are passing null to
restoreState
when the stack is empty but that method doesn't have special handling for the null case.