I've run into a little problem.
In my GUI, I have a text area in the center (BorderLayout). Then I have a JList on the West.
When I click on a member of the song titles I have in my list, the text area should display the title, artist, and price of the song.
I have everything working, but the problem is that when I click on a member, the title,artist, and the price is displayed TWICE.
Here is the code for "valueChanged()" and parts of codes relevant.
public void valueChanged(ListSelectionEvent e)
{
Object source = e.getSource();
int index = songList.getSelectedIndex();
Song selection = songCollection[index];
if(source == songList)
{
textArea.append(selection.getTitle() + " " + selection.getArtist() + " " + selection.getPrice() + "\n" );
}
}
private Song songCollection[] = new Song[5];
private String songTitle[] = new String[5];
//Fill song array
songCollection = getSongs();
songTitle = getSongTitle();
//Methods:
public Song[] getSongs()
{
Song[] array = new Song[5];
array[0] = new Song("Summer", "Mozart", 1.50);
array[1] = new Song("Winter", "Mozart", 1.25);
array[2] = new Song("Spring", "Mozart", 2.00);
array[3] = new Song("Baby", "Justin Bieber", 0.50);
array[4] = new Song("Firework", "Katy Perry", 1.00);
return array;
}
public String[] getSongTitle()
{
String[] names = new String[5];
for(int i = 0; i < 5; i++)
names[i] = songCollection[i].getTitle();
return names;
}
I noticed something just now when I was fiddling around with my program again. When I press a member in the list, it is still printed TWICE like before. However, I noticed that it prints once when I press and hold down my mouse, and it prints AGAIN when I let go of it. So if I press my mouse on 1 member, and drag the cursor up/down to other members, they print once, but when I let go of the mouse, it prints the one I ended in one more time.
JTextArea.append() is being called twice from your ListSelectionListener.
The reason can be found in How to Use Lists:
Many list selection events can be generated from a single user action such as a mouse click. The getValueIsAdjusting method returns true if the user is still manipulating the selection. This particular program is interested only in the final result of the user's action, so the valueChanged method does something only if getValueIsAdjusting returns false.
You need to check that the selection in the JList is no longer being manipulated. You can surround the append method with the check:
if (!e.getValueIsAdjusting()) {
textArea.append(...);
}
Related
Working on a school project, I am trying to get the action of clicking a button pull the selected index of a Combo Box string array, and associated that index with an int array so that a final price can be computed. Doesn't seem to work the price just remains at zero when button is pressed.
private final String[] deckArray = {"The Master
Thrasher ", "The Dictator", "The Street King"};
private final String[] trucksArray = {"7.75-inch
axle", "8-inch axle", "8.5-inch axle"};
private final String[] wheelsArray = {"51mm", "55mm",
"58mm", "61mm"};
private final int[] deckPrice = {60,45,50};
private final int[] trucksPrice = {35,40,45};
private final int[] wheelsPrice = {20,22,24,28};
comboDecks = new ComboBox();
comboDecks.getItems().addAll(deckArray);
comboTrucks = new ComboBox();
comboTrucks.getItems().addAll(trucksArray);
comboWheels = new ComboBox();
comboWheels.getItems().addAll(wheelsArray);
btnCalc = new Button("Calculate Total");
lblFinalPrice = new Label("Final Price:");
txtSubtotal = new Text("Subtotal: " + finalSubPrice);
txtTax = new Text("Tax:" + finalTaxPrice);
txtFinalPrice = new Text("Final Price: " +
finalTotalPrice);
EventHandler<ActionEvent> calcHandler = new
EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
finalDeckPrice = deckPrice[comboDecks.getSelectionModel().getSelectedIndex()];
finalTruckPrice = trucksPrice[comboTrucks.getSelectionModel().getSelectedIndex()];
finalWheelsPrice = wheelsPrice[comboWheels.getSelectionModel().getSelectedIndex()];
finalSubPrice = finalDeckPrice + finalTruckPrice + finalWheelsPrice;
finalTaxPrice = finalSubPrice * salesTax;
finalTotalPrice = finalSubPrice + finalTaxPrice;
}
};
You made the button, you made the event handler, but you never connected the event handler to the button. Same goes for the calculation and the label, you calculated but did not update the label with the calculated value.
Add the following line to your code after you create the handler.
btnCalc.setOnAction(calcHandler);
And add txtFinalPrice.setText(""+finalTotalPrice); after you finish calculations inside handle() method.
public void handle(ActionEvent actionEvent) {
...
finalTotalPrice = finalSubPrice + finalTaxPrice;
txtFinalPrice.setText("Final Price: " + finalTotalPrice);
}
Explanation (Abstract)
(1) When you create an Event Handler object you just wrote the code you want it to run but it won't run in serial as the code executes top to bottom, since as you said you want it to work when you click the button. So you have to let the Button know that when it gets clicked to execute this code. setOnAction() method takes as parameter an Event Handler object and executes it when some action happens to the Button, the action for the Button is when it gets clicked.
(2) Just by calculating the value, doesn't mean the Label knows that the value got calculated or something. The point where you calculating the price is the point that you have to tell to the Label take this value and use this as your content.
Suggestion
Event handlers, action events etc need a bit of good understanding to use them correctly. The baseline is that all of that work asynchronously and you gotta get at least the idea of it so you can understand the rest (no offense but from the question i believe you need some work on it).
I have a Java SWT GUI that I've built using Eclipse. I'm using a while loop to reference a text file. The while loop iterates through each line of the text file and builds a series of combo or text boxes for specific items on each line. Each line represents one visual column in the GUI and, depending on how many items I have in the text file, the GUI builds to the right. For simplicity's sake I am including just the code that I am trying to figure out.
For instance, assume I have three lines that create six combo boxes in the GUI (three columns by two rows). I would like a change on the top row in the second column to execute a Listener on the bottom row, also in the second column. However, right now the Listener loops through all of the combo's and makes a change to all three, not just the one I want. I can't figure out how to make this work. See the code below. I appreciate the help.
private void buildMultipleSatPulldowns() {
try {
FileReader fr = new FileReader("MultipleSatellites.txt");
BufferedReader br = new BufferedReader(fr);
String line = null;
String[] tempS;
String constellation = null;
String satellite = null;
while ((line = br.readLine()) != null) {
tempS = line.split("~");
constellation = tempS[4];
satellite = tempS[6];
constNameCombo = new Combo(satellitesComposite2, SWT.NONE);
constNameCombo.setToolTipText("Pulldown constellation name");
constNameCombo.setBounds(startX + x2, 71, 125, 28);
constNameCombo.setItems(constNameArray);
constNameCombo.setText(constellation);
constNameCombos.add(constNameCombo);
constNameCombo.addModifyListener(new ModifyListener() { // captures changed combo values
public void modifyText(ModifyEvent arg0) {
setConstellationPD();
}
});
sPullDown(constellation); // builds the satellite array for the constellation and populates each pulldown
satNameCombo = new Combo(satellitesComposite2, SWT.NONE);
satNameCombo.setToolTipText("Pulldown satellite name");
satNameCombo.setBounds(startX + x2, 106, 125, 28);
satNameCombo.setItems(satNameArray);
satNameCombo.setText(satellite);
satNameCombos.add(satNameCombo);
startX = startX + nextX;
}
br.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
private void setConstellationPD() {
int constellations = 0;
for (Combo constNameCombo : constNameCombos) {
// What do I do here so that only the desired satNameCombo changes to reflect the desired pull down?
setSatellitesPD(constellations, constNameCombo)
constellations++;
}
}
private void setSatellitesPD(int c, String cN) {
int satellites = 0;
for (Combo satNameCombo : satNameCombos) {
if (c == satellites) {
satNameCombo.setText(satNameCombos.get(satellites).toString());
satNameCombo.removeAll();
sPullDown(cN);
satNameCombo.setText("select Satellite");
}
satellites++;
}
}
private void sPullDown(String cName) {
// sPullDown takes the constellation name and returns a String Array of all objects in the constellation. This code works correctly when called.
}
If I understood correctly, you need a way to know which combo fired the event in order to affect some other components.
SWT events like ModifyEvent have the method getSource() which will return the object on which the event occurred.
Having that you just need to properly identify it; for example you could simply use constNameCombos.indexOf(eventCombo) to retrieve its index.
Or, more efficiently, you could attach some data to your combos with the method setData and retrieve it inside the event with getData, for example inside the loop:
// "i" would be the index of the combo
constNameCombo.setData("index", i);
i++;
and in the event:
Combo eventCombo = (Combo) arg0.getSource();
int index = eventCombo.getData("index");
With these information you should be able to identify the other components that you want to change.
I know that it is possible in an event driven program in Java to find out what object caused an event (e.g. JRadioButton was selected, therefore a certain action will take place). My question is, if you have 2 JRadioButtons in a buttongroup, both with action listeners added to them, and you keep selecting from one to the other, is it possible to find out what JRadioButton was previously selected? In other words, if I selected another JRadioButton, is it possible to write code that determines which JRadioButton was previously selected before selecting the current JRadioButton?
public class Drinks extends JPanel implements ActionListener{
double drinksPrice = 2.10;
double noDrinks = 0;
static String selectedDrink;
JRadioButton btnPepsi = new JRadioButton("Pepsi"); //add a button to choose different drinks
JRadioButton btnMtDew = new JRadioButton("Mt Dew");
JRadioButton btnDietPepsi= new JRadioButton("Diet Pepsi");
JRadioButton btnCoffee = new JRadioButton("Coffee");
JRadioButton btnTea = new JRadioButton("Tea");
JRadioButton btnNone = new JRadioButton("None");
JLabel lblDrinksHeading = new JLabel("Choose a drink (each drink is $2.10):");
ButtonGroup drinksButtonGroup = new ButtonGroup();
private static final long serialVersionUID = 1L;
public Drinks(){
setLayout(new FlowLayout()); //Using GridLayout
btnPepsi.setActionCommand(btnPepsi.getText()); //set the ActionCommand to getText so I can retrieve the name for the receipt
btnMtDew.setActionCommand(btnMtDew.getText());
btnDietPepsi.setActionCommand(btnDietPepsi.getText());
btnCoffee.setActionCommand(btnCoffee.getText());
btnTea.setActionCommand(btnTea.getText());
btnNone.setActionCommand(btnNone.getText());
drinksButtonGroup.add(btnPepsi);
drinksButtonGroup.add(btnMtDew);
drinksButtonGroup.add(btnDietPepsi);
drinksButtonGroup.add(btnCoffee);
drinksButtonGroup.add(btnTea);
drinksButtonGroup.add(btnNone);
btnNone.setSelected(true); //set default to "none"
btnPepsi.addActionListener(this);
btnMtDew.addActionListener(this);
btnDietPepsi.addActionListener(this);
btnCoffee.addActionListener(this);
btnTea.addActionListener(this);
btnNone.addActionListener(this);
add(lblDrinksHeading);
add(btnPepsi);
add(btnDietPepsi);
add(btnMtDew);
add(btnCoffee);
add(btnTea);
add(btnNone);
repaint();
revalidate();
selectedDrink = drinksButtonGroup.getSelection().getActionCommand();
//add the drink price to totalPrice, it is adding it every time though, even if its none
/*if(drinksButtonGroup.getSelection() == btnNone){
MenuFrame.totalPrice += 0;
}
else{
MenuFrame.totalPrice += drinksPrice;
}
*/
// buttonGroup1.getSelection().getActionCommand()
//String selectedDrink = drinksButtonGroup.getSelection().toString();
//class
}
#Override
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if(source == btnNone) {
MenuFrame.totalPrice += 0;
TaxAndGratuityFrame.subtotalTextField.setText("$" + MenuFrame.totalPrice);
TaxAndGratuityFrame.subtotalVariable = MenuFrame.totalPrice;
TaxAndGratuityFrame.taxVariable = TaxAndGratuityFrame.subtotalVariable * TaxAndGratuityFrame.TAX_RATE;
TaxAndGratuityFrame.taxTextField.setText("$" + TaxAndGratuityFrame.taxVariable);
Receipt.receiptTotal.setText("Total: $" + (MenuFrame.totalPrice));
Receipt.receiptsubtotal.setText("Subtotal: " + (TaxAndGratuityFrame.subtotalVariable));
}
else {
MenuFrame.totalPrice += drinksPrice;
TaxAndGratuityFrame.subtotalTextField.setText("$" + MenuFrame.totalPrice);
TaxAndGratuityFrame.subtotalVariable = MenuFrame.totalPrice;
TaxAndGratuityFrame.taxVariable = TaxAndGratuityFrame.subtotalVariable * TaxAndGratuityFrame.TAX_RATE;
TaxAndGratuityFrame.taxTextField.setText("$" + TaxAndGratuityFrame.taxVariable);
Receipt.receiptTotal.setText("Total: $" + (MenuFrame.totalPrice));
Receipt.receiptsubtotal.setText("Subtotal: " + (TaxAndGratuityFrame.subtotalVariable));
}
}
Edit: I'll be more specific. I am creating an "imaginary" restaurant program. In it, I list several drinks that have the same price (e.g. Pepsi: $2.10, Mountain Due: $2.10, etc). These listed drinks are JRadioButtons. Once a customer clicks one of these buttons to "order a drink", $2.10 will be added to a "total" variable. However, a problem occurs when a user wants to change there drink, because if they click a different JRadioButton, $2.10 will still be added to the "total" variable. I want to make it so that they can change there drink without adding $2.10 to the order every time.
I think the problem is at this line:
MenuFrame.totalPrice += drinksPrice;
Because "+=" increments a value by another value instead of simply adding two values.
So every time the user clicks on one of the radio buttons, it will continuously add 2.10 to your total value, whereas if you were you just say:
MenuFrame.totalPrice = MenuFrame.totalPrice + drinksPrice;
It will set your total price equal to the current total price plus the price of drinks, instead of adding 2.10 to the total value every time a button is pressed.
Perhaps I am misunderstanding the question, but I am thinking along the lines of creating a public variable, and then inside the action listeners updating the variable with the radio button that was just selected. When the selected event fires, you can look at the variable to see which radio button had last been selected, do what you want to about it, and then update it with the new radio button.
I am nowhere near complete with this code it is just a template and I have not finished formatting my code. I am having trouble calling the message part of the array in my other class. I basically have an if/else statement saying when roomId = some#, it will outprint the message the correlates to the # from the array. I am just having trouble understanding how to call the array. Eclipse is throwing me an error in the if/else statement under "grid" saying grid cannot be resolved to a variable. I also tried calling the array method inside the method that the statements are in.Thanks for the help guys.
public class location{
public int roomId;
public String name, message;
public location() {
roomId = 0;
}
public location(String name, int roomId, String message){
this.name = name;
this.roomId = roomId;
this.message = message;
}
public void LocArray() {
location[][] grid = new location[4][4];
grid [1][0] = new location("LABORATORY", 0, "You're in the lab.");
grid [2][0] = new location("DUNGEON", 1, "You entered the dungeon.");
grid [3][0] = new location("COURTYARD ENTRANCE",2,"You have left the dungeon out the backdoor. Either head east and search the courtyard maze, or travel north back to the dungeon");
grid [3][1] = new location("FIRST PATH", 3,"You have now entered the courtyard, either continue east or move north.");
grid [3][2] = new location("DEADEND", 4,"You have reached a deadend that has a Magic Shop. Go inside and explore it.");
grid [3][3] = new location ("MAGIC SHOP", 5, "Search around the Magic Shop and see what there is. When you're done searching continue through the maze.");
grid [2][1] = new location("SECOND PATH",6,"Search the surroundings for items that will help you get into the locked room, then keep moving.");
grid [2][2] = new location("END MAZE", 7, "You've made it to the end of the courtyard. There seems to be a cave in the distance; go check it out.");
grid [1][2] = new location("CAVE",8,"Explore the cave to find the remaining items that will lead to your freedom.");
grid [0][0] = new location("EXIT",9,"This room will lead to your freedom, but you need the three essential items that will open this door.");
}
}
//This is a different class called projectTwo.
while (stillPlaying) {
Scanner scan = new Scanner(System.in);
userInput = scan.nextLine();
if (roomId == 0){
if (userInput.equals("n")) {
System.out.println(grid[2][0].message);
roomId = 1; // Moves user from location 0 to 1
}
grid variable is declared inside the locArray method.
You can't call it in another method or in an another method inside another class.
I am having a problem with my text array, the text keeps switching constantly. This is the code that I have so far for it:
private void drawSplash(Graphics2D g) {
if (displayed == false) {
Random r = new Random();
String list;
String items[] = { "Buggy!", "New Game!", "Roll up, roll up!",
"Made from Scratch" };
int amount;
amount = (int) (Math.random() * 25 + 1);
list = items[r.nextInt(3 + 1)];
System.out.println(list);
g.setFont(font2);
g.setColor(Color.BLACK);
g.drawString(list, 320, 240);
displayed = true;
}
}
I want to make it so that whenever the program is restarted, the string change.
Can anyone help me with this please? It's really bugging me.
Problem is that you want to keep state between program startups, otherwise you will get repeats. So what you want to do is:
During startup: if no property file with a shuffled list exists, create a shuffled list, set index to 1
Then:
during startup: retrieve shuffled list and index from property file
put the item with the given index in a static field
increase the index and store the property file again
display the item during paint
I'll leave it up to you what you do when you run out of items.
For a quick fix that simply displays a random item each time the class is used:
private static String ITEMS[] = { "Buggy!", "New Game!",
"Roll up, roll up!", "Made from Scratch" };
private String itemDisplayed = chooseItem();
private String chooseItem() {
Random r = new SecureRandom();
int i = r.nextInt(ITEMS.length);
return ITEMS[i];
}
private void drawSplash(Graphics2D g) {
g.setColor(Color.BLACK);
g.setFont(font2);
g.drawString(itemDisplayed, 320, 240);
displayed = true;
}
I guess drawSplash is called each time the text changes. If you only want to draw a random String on e.g. initialize make a own function for
list = items[r.nextInt(3+1)];
which gets only called once
The problem is not drawSplash(), but a) how often it gets called, and b) even if it gets called frequently, then somebody must change the value of displayed to false outside of the method.
Just some minor comments:
if (!displayed) is the usual style
amount is never used
Random r is not really needed
Here is what is wrong:
list = items[r.nextInt(3+1)]
Each time drawSplash() method is executed, list has a new random value.
You should init it only once:
String list;
Random r = new Random();
public void initListIndex(){
String items[] = { "Buggy!", "New Game!", "Roll up, roll up!",
"Made from Scratch" };
int listIndex = r.nextInt(3 + 1);
list= items[listIndex];
}
private void drawSplash(Graphics2D g) {
if (displayed == false) {
System.out.println(list);
g.setFont(font2);
g.setColor(Color.BLACK);
g.drawString(list, 320, 240);
displayed = true;
}
}