I am task to do a simple order system. I want the JLabel (Amount: $0.00) show the corresponding amount on what the user picks for his burger and condiments. For example, if the user click on beef, the label will change into "Amount: $4.00", and when he choose a condiment, it will add $0.50 to the total based on how many condiments he picks and vice versa. Also, when the user unchecks a condiment (JCheckBox), it will deduct $0.50 dollars to the total.
My code for beef JRadioButton:
private void beef_radioBtnActionPerformed(java.awt.event.ActionEvent evt) {
total_amount.setText("Amount: $4.00");
ketchup_Checkbox.setEnabled(true);
mustard_Checkbox.setEnabled(true);
pickles_Checkbox.setEnabled(true);
}
Code for ketchup JCheckBox:
private void ketchup_CheckboxActionPerformed(java.awt.event.ActionEvent evt) {
float condiments_amount = (float) 0.50;
float beef_amount = (float) 4.00;
float total;
if (beef_radioBtn.isSelected()){
total = beef_amount + condiments_amount;
total_amount.setText("Amount: $" + decimal.format(total));
if (!ketchup_Checkbox.isSelected()){
total_amount.setText("Amount: $" + decimal.format(4.50 - condiments_amount));
}
else if (mustard_Checkbox.isSelected()){
total_amount.setText("Amount: $" + decimal.format(4.50 + condiments_amount));
}
else if (pickles_Checkbox.isSelected()){
total_amount.setText("Amount: $" + decimal.format(4.50 + condiments_amount));
}
}
}
Okay, buckle up, this is going to be a bit of ride.
One of the most powerful concepts you have available to you is the concept of "model". A model is just something that "models" something and is a way to seperate different areas of your program. So a model, models the data (think of it like a container) and the view will then use those models to format the data to the user (separation of concerns). A model may also contain business logic or perform calculations depending on its requirements.
The allows you to centralise concepts so you don't end up repeating yourself or forgetting to do things. It's also a way to change how parts of the program work, also known as "delegation"
Starting point, some interfaces
Well, that's a lot of "blah", so let's get started. I prefer to use interfaces to describe things, it provides a lot of freedom, as you can put different interfaces together to suit different requirements.
The Menu
Okay, simple concept, this will be a list of items which are available to sell
public interface Menu {
public List<MainMenuItem> getMenuItems();
}
Menu items
A description of a menu item, pretty basic
public interface MenuItem {
public String getDescription();
public double getPrice();
}
"Main" menu items
These are all the "top level", "stand alone" menu items and in our case, can have condiments :D
public interface MainMenuItem extends MenuItem {
public List<Condiment> getCondiments();
}
Condiments
Condiments are a "special" MenuItem, as they are associated with a MainMenuItem
public interface Condiment extends MenuItem {
}
Burgers
This is just a demonstration of some of the things you could do, Burger isn't anything special, but as you will see, we can use this concept to do different things
public interface Burger extends MainMenuItem {
}
Order
And finally, the "order", what have we ordered and what condiments do we want with it
public interface Order {
public MainMenuItem getItem();
public void setItem(MainMenuItem item);
public List<Condiment> getCondiments();
public void addCondiment(Condiment condiment);
public void removeCondiment(Condiment condiment);
public double getTally();
}
This is a good demonstration of the power of the model. The Order has a getTally method, which is used to calculate what is owed. Different implementations of the model might apply different calculations, like tax or discounts
Implementations
Okay, since you're probably aware, we can't create an instance of a interface, we need some "default" implementations to work with...
public class DefaultOrder implements Order {
private MainMenuItem item;
private List<Condiment> condiments = new ArrayList<>();
#Override
public MainMenuItem getItem() {
return item;
}
#Override
public List<Condiment> getCondiments() {
return Collections.unmodifiableList(condiments);
}
#Override
public double getTally() {
double tally = 0;
if (item != null) {
tally += item.getPrice();
}
for (Condiment condiment : condiments) {
tally += condiment.getPrice();
}
return tally;
}
#Override
public void setItem(MainMenuItem item) {
this.item = item;
// Oh look, we've established a "rule" that this model
// applies, by itself, sweet
condiments.clear();
}
#Override
public void addCondiment(Condiment condiment) {
// Bit pointless if the menu item is not set
if (item == null) {
return;
}
// Probably should check for duplicates
condiments.add(condiment);
}
#Override
public void removeCondiment(Condiment condiment) {
// Bit pointless if the menu item is not set
if (item == null) {
return;
}
condiments.remove(condiment);
}
}
public class DefaultMenu implements Menu {
private List<MainMenuItem> menuItems = new ArrayList<>();
public void add(MainMenuItem menuItem) {
menuItems.add(menuItem);
}
#Override
public List<MainMenuItem> getMenuItems() {
return Collections.unmodifiableList(menuItems);
}
}
public abstract class AbstractMenuItem implements MenuItem {
private String description;
private double price;
public AbstractMenuItem(String description, double price) {
this.description = description;
this.price = price;
}
#Override
public String getDescription() {
return description;
}
#Override
public double getPrice() {
return price;
}
}
public class DefaultCondiment extends AbstractMenuItem implements Condiment {
public DefaultCondiment(String description, double price) {
super(description, price);
}
}
public class DefaultBurger extends AbstractMenuItem implements Burger {
private List<Condiment> condiments;
public DefaultBurger(String description, double price, List<Condiment> condiments) {
super(description, price);
// Protect ourselves from external modifications
this.condiments = new ArrayList<>(condiments);
}
#Override
public List<Condiment> getCondiments() {
return Collections.unmodifiableList(condiments);
}
}
Okay, try not to get too caught up in this, but have a look at the use of abstract here. AbstractMenuItem encapsulates a lot of the "common" functionality that all MenuItem implementations are going to need, so we don't need to repeat ourselves, sweet.
Some of these implementations are already making decisions or applying rules. For example, the DefaultOrder will clear the condiments when ever the MainMenuItem is changed. It could also make sure that the condiment which is been applied is actually available fo this item.
Also note, the tally method is not a stored property, but is re-calculated every time you call it. This is design decision, it wouldn't be hard to make it a stored property instead, so each time you change the MenuMenuItem, add and/or remove condiments, the property was updated, but I'm feeling lazy. But you can see how these things can be changed, and it will effect ALL users of these models, sweet :D
Okay, but how does this actually answer the question? Well, quite a bit actually.
So, the idea is, you start with a blank Order. The user selects a "main item" (ie a burger), you set this to the Order and then you update the UI in response. The UI asks the Order to calculate the tally and presents that to the user.
More over, the same concept works for condiments as well. Each time a condiment is added or removed by the user, the Order is updated and you update the UI.
Okay, but maybe, it's a little easier to understand with an example...
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.border.EmptyBorder;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
List<Condiment> condiments = new ArrayList<>(3);
condiments.add(new DefaultCondiment("Ketchup", 0.5));
condiments.add(new DefaultCondiment("Mustard", 0.5));
condiments.add(new DefaultCondiment("Pickles", 0.5));
DefaultMenu menu = new DefaultMenu();
menu.add(new DefaultBurger("Beef", 4.0, condiments));
menu.add(new DefaultBurger("Chicken", 3.5, condiments));
menu.add(new DefaultBurger("Veggie", 4.0, condiments));
MenuPane menuPane = new MenuPane();
menuPane.setMenu(menu);
frame.add(menuPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class MenuPane extends JPanel {
private Menu menu;
private Order order;
private List<Condiment> selectedCondiments = new ArrayList<>();
private JPanel burgerPanel;
private JPanel condimentPanel;
private JPanel totalPanel;
private JLabel totalLabel;
private JButton clearButton;
private JButton payButton;
private NumberFormat currencyFormatter;
public MenuPane() {
setLayout(new GridBagLayout());
order = new DefaultOrder();
burgerPanel = new JPanel();
burgerPanel.setBorder(new EmptyBorder(8, 8, 8, 8));
condimentPanel = new JPanel();
condimentPanel.setBorder(new EmptyBorder(8, 8, 8, 8));
totalPanel = makeTotalPanel();
totalPanel.setBorder(new EmptyBorder(8, 8, 8, 8));
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.BOTH;
gbc.weightx = 1;
gbc.weighty = 0.5;
add(burgerPanel, gbc);
gbc.gridy++;
add(condimentPanel, gbc);
gbc.gridy++;
gbc.weighty = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
add(totalPanel, gbc);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 200);
}
protected NumberFormat getCurrentFormatter() {
if (currencyFormatter != null) {
return currencyFormatter;
}
currencyFormatter = NumberFormat.getCurrencyInstance();
currencyFormatter.setMinimumFractionDigits(2);
return currencyFormatter;
}
protected JPanel makeTotalPanel() {
JPanel totalPanel = new JPanel(new GridBagLayout());
totalLabel = new JLabel();
clearButton = new JButton("CLR");
payButton = new JButton("PAY");
clearButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
order = new DefaultOrder();
buildCondiments();
orderDidChange();
}
});
GridBagConstraints gbc = new GridBagConstraints();
gbc.weightx = 1;
gbc.gridx = 0;
gbc.gridy = 0;
totalPanel.add(totalLabel, gbc);
gbc.weightx = 0;
gbc.gridx++;
totalPanel.add(clearButton, gbc);
gbc.gridx++;
totalPanel.add(payButton, gbc);
return totalPanel;
}
protected void buildBurgerMenu() {
burgerPanel.removeAll();
burgerPanel.setLayout(new GridBagLayout());
if (menu == null) {
return;
}
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.anchor = GridBagConstraints.NORTHWEST;
gbc.weightx = 1;
ButtonGroup bg = new ButtonGroup();
// Stick with me, this is a little more advanced, but provides
// a really nice concept and ease of use
// We could also make use of the Action API, but that might
// pushing you just a little to far ;)
ActionListener actionListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (!(e.getSource() instanceof JComponent)) {
return;
}
JComponent comp = (JComponent) e.getSource();
Object obj = comp.getClientProperty("MenuItem");
// I'm putting this here to demonstrate part of the concept
// of polymorphism - techncially, we don't have to care
// of it's a burger or some other type of menu item,
// only that this is going to represent the "main" item
if (!(obj instanceof MainMenuItem)) {
return;
}
MainMenuItem item = (MainMenuItem) obj;
order.setItem(item);
buildCondiments();
orderDidChange();
}
};
System.out.println(menu.getMenuItems().size());
for (MenuItem item : menu.getMenuItems()) {
// Only interested in burgers
// Could have the Menu do this, but that's a design
// decision
if (!(item instanceof Burger)) {
continue;
}
Burger burger = (Burger) item;
JRadioButton btn = new JRadioButton(burger.getDescription() + " (" + getCurrentFormatter().format(burger.getPrice()) + ")");
// Ok, this is just a little cheeky, but we're associating the
// butger with the button for simplicity
btn.putClientProperty("MenuItem", burger);
bg.add(btn);
// Add all the buttons share the same listener, because of polymorphism :D
btn.addActionListener(actionListener);
burgerPanel.add(btn, gbc);
}
}
protected void buildCondiments() {
condimentPanel.removeAll();
condimentPanel.setLayout(new GridBagLayout());
if (menu == null || order.getItem() == null) {
return;
}
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.anchor = GridBagConstraints.NORTHWEST;
gbc.weightx = 1;
// Stick with me, this is a little more advanced, but provides
// a really nice concept and ease of use
// We could also make use of the Action API, but that might
// pushing you just a little to far ;)
ActionListener actionListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (!(e.getSource() instanceof JCheckBox)) {
return;
}
JCheckBox checkBox = (JCheckBox) e.getSource();
Object obj = checkBox.getClientProperty("Condiment");
if (!(obj instanceof Condiment)) {
return;
}
Condiment condiment = (Condiment) obj;
if (checkBox.isSelected()) {
order.addCondiment(condiment);
} else {
order.removeCondiment(condiment);
}
orderDidChange();
}
};
for (Condiment condiment : order.getItem().getCondiments()) {
JCheckBox btn = new JCheckBox(condiment.getDescription() + " (" + getCurrentFormatter().format(condiment.getPrice()) + ")");
// Ok, this is just a little cheeky, but we're associating the
// butger with the button for simplicity
btn.putClientProperty("Condiment", condiment);
// Add all the buttons share the same listener, because of polymorphism :D
btn.addActionListener(actionListener);
condimentPanel.add(btn, gbc);
}
}
public Menu getMenu() {
return menu;
}
public void setMenu(Menu menu) {
this.menu = menu;
order = new DefaultOrder();
buildBurgerMenu();
orderDidChange();
}
protected void orderDidChange() {
if (order == null) {
totalLabel.setText("Amount: " + getCurrentFormatter().format(0));
return;
}
// And now, some magic, how easy is it to get the expected
// tally amount!!
totalLabel.setText("Amount: " + getCurrentFormatter().format(order.getTally()));
}
}
public interface Menu {
public List<MainMenuItem> getMenuItems();
}
public interface MenuItem {
public String getDescription();
public double getPrice();
}
public interface Condiment extends MenuItem {
}
public interface MainMenuItem extends MenuItem {
public List<Condiment> getCondiments();
}
public interface Burger extends MainMenuItem {
}
public interface Order {
public MainMenuItem getItem();
public void setItem(MainMenuItem item);
public List<Condiment> getCondiments();
public void addCondiment(Condiment condiment);
public void removeCondiment(Condiment condiment);
public double getTally();
}
public class DefaultOrder implements Order {
private MainMenuItem item;
private List<Condiment> condiments = new ArrayList<>();
#Override
public MainMenuItem getItem() {
return item;
}
#Override
public List<Condiment> getCondiments() {
return Collections.unmodifiableList(condiments);
}
#Override
public double getTally() {
double tally = 0;
if (item != null) {
tally += item.getPrice();
}
for (Condiment condiment : condiments) {
tally += condiment.getPrice();
}
return tally;
}
#Override
public void setItem(MainMenuItem item) {
this.item = item;
// Oh look, we've established a "rule" that this model
// applies, by itself, sweet
condiments.clear();
}
#Override
public void addCondiment(Condiment condiment) {
// Bit pointless if the menu item is not set
if (item == null) {
return;
}
// Probably should check for duplicates
condiments.add(condiment);
}
#Override
public void removeCondiment(Condiment condiment) {
// Bit pointless if the menu item is not set
if (item == null) {
return;
}
condiments.remove(condiment);
}
}
public class DefaultMenu implements Menu {
private List<MainMenuItem> menuItems = new ArrayList<>();
public void add(MainMenuItem menuItem) {
menuItems.add(menuItem);
}
#Override
public List<MainMenuItem> getMenuItems() {
return Collections.unmodifiableList(menuItems);
}
}
public abstract class AbstractMenuItem implements MenuItem {
private String description;
private double price;
public AbstractMenuItem(String description, double price) {
this.description = description;
this.price = price;
}
#Override
public String getDescription() {
return description;
}
#Override
public double getPrice() {
return price;
}
}
public class DefaultCondiment extends AbstractMenuItem implements Condiment {
public DefaultCondiment(String description, double price) {
super(description, price);
}
}
public class DefaultBurger extends AbstractMenuItem implements Burger {
private List<Condiment> condiments;
public DefaultBurger(String description, double price, List<Condiment> condiments) {
super(description, price);
// Protect ourselves from external modifications
this.condiments = new ArrayList<>(condiments);
}
#Override
public List<Condiment> getCondiments() {
return Collections.unmodifiableList(condiments);
}
}
}
Okay, that's a lot to take in. Lets take a closer look at the buildBurgerMenu method. This gets called when ever the main menu is changed.
Pay close attention to the actionListener used in this method, there's only one and it's shared by all the buttons
protected void buildBurgerMenu() {
burgerPanel.removeAll();
burgerPanel.setLayout(new GridBagLayout());
if (menu == null) {
return;
}
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.anchor = GridBagConstraints.NORTHWEST;
gbc.weightx = 1;
ButtonGroup bg = new ButtonGroup();
// Stick with me, this is a little more advanced, but provides
// a really nice concept and ease of use
// We could also make use of the Action API, but that might
// pushing you just a little to far ;)
ActionListener actionListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (!(e.getSource() instanceof JComponent)) {
return;
}
JComponent comp = (JComponent) e.getSource();
Object obj = comp.getClientProperty("MenuItem");
// I'm putting this here to demonstrate part of the concept
// of polymorphism - techncially, we don't have to care
// of it's a burger or some other type of menu item,
// only that this is going to represent the "main" item
if (!(obj instanceof MainMenuItem)) {
return;
}
MainMenuItem item = (MainMenuItem) obj;
order.setItem(item);
buildCondiments();
orderDidChange();
}
};
System.out.println(menu.getMenuItems().size());
for (MenuItem item : menu.getMenuItems()) {
// Only interested in burgers
// Could have the Menu do this, but that's a design
// decision
if (!(item instanceof Burger)) {
continue;
}
Burger burger = (Burger) item;
JRadioButton btn = new JRadioButton(burger.getDescription() + " (" + getCurrentFormatter().format(burger.getPrice()) + ")");
// Ok, this is just a little cheeky, but we're associating the
// butger with the button for simplicity
btn.putClientProperty("MenuItem", burger);
bg.add(btn);
// Add all the buttons share the same listener, because of polymorphism :D
btn.addActionListener(actionListener);
burgerPanel.add(btn, gbc);
}
}
When ever the actionListener is triggered (via a user interaction for example), it makes a bunch of decisions, which, if all goes well, ends in the Order been updated, the buildCondiments and orderDidChange methods been called, which updates the available condiments and updates the UI's tally.
This is all done in a "abstract" way. The actionListener doesn't care about what type of MainMenuItem the user selected, that doesn't change its workflow, it only needs to apply the item to the Order. In the same vain, the Order doesn't care, as it just needs the price information in order to calculate the tally.
So you can add new menu items and/or change the prices and everything just keeps on working (🤞).
Let's look at the orderDidChange method...
protected void orderDidChange() {
if (order == null) {
totalLabel.setText("Amount: " + getCurrentFormatter().format(0));
return;
}
// And now, some magic, how easy is it to get the expected
// tally amount!!
totalLabel.setText("Amount: " + getCurrentFormatter().format(order.getTally()));
}
Not super complicated is it! All the work is been done by the, MODEL!
What I left out
For brevity, I left out one other concept, often used with models, the concept of the "observer pattern".
The observer pattern allows an interested party to be notified when some other object changes. It's pretty common concept and you've already used, ActionListener is an example of an observer pattern. It allows you to "observer" "actions events" when they are triggered by a given object.
Sure, but how is that helpful?
Well, imagine now if, instead of having to manually call orderDidChange every time you wanted to update the UI (or even forgetting to and spending a few hours debugging why), the MenuPane could, instead, registered itself as an observer directly to the Order and be notified when the order changed!! Super sweet!
This further helps you de-couple your code and makes it super easy to update the UI in a verity of ways independently of the model or other code requirements.
Models 💪
I want to display a JComboBox that shows the text values but stores the actual int values for the user to select for session timeout values.
private static final String[] SESSION_TIMEOUT_OPTION_NAMES = new String[]{
"5 Minutes",
"10 Minutes",
"15 Minutes",
...
};
private static final Integer[] SESSION_TIMEOUT_OPTION_VALUES = new Integer[]{
TimeConstants.FIVE_MINUTES,
TimeConstants.TEN_MINUTES,
TimeConstants.FIFTEEN_MINUTES,
...
};
I know this can be done with a ListCellRenderer but the only way I could see it working is with a big mapping Basically alongs the lines of:
sessionTimeoutJComboBox.setRenderer(new ListCellRenderer<Integer>()
{
private DefaultListCellRenderer defaultRenderer = new DefaultListCellRenderer();
#Override
public Component getListCellRendererComponent(...)
{
JLabel jlabel = (JLabel)defaultRenderer.getListCellRendererComponent(...);
for(int x=0; x<SESSION_TIMEOUT_OPTION_VALUES.length; x++)
{
if(SESSION_TIMEOUT_OPTION_VALUES[x] == value)
{
jlabel.setText(SESSION_TIMEOUT_OPTION_NAMES[x]);
return jlabel;
}
}
throw new RuntimeException("Invalid mapping");
}
});
Is there a better way to do this?
Btw the reason I want to do this is so that I can just do
(int)sessionTimeoutJComboBox.getSelectedItem();
and not have to care more than that.
You could use enums:
private enum TimeConstants {
FIVE_MINUTES("5 Minutes", 5),
TEN_MINUTES("10 Minutes", 10);
private final String text;
private final int value;
private TimeConstants( String text, int value ) {
this.text = text;
this.value = value;
}
public int getValue() {
return this.value;
}
#Override
public String toString() {
return this.text;
}
}
And heres how to use them with JComboBox:
TimeConstants[] constants = {TimeConstants.FIVE_MINUTES, TimeConstants.TEN_MINUTES};
JComboBox<TimeConstants> combo = new JComboBox<TimeConstants>(constants);
System.out.println( "Selected value: " + ((TimeConstants)combo.getSelectedItem()).getValue());
You could use a Map instead of doing the mappings manually. i.e.:
Map<Integer, String> timeoutOptions = new HashMap<>();
timeoutOptions.put( TimeConstants.FIVE_MINUTES, "5 Minutes");
...
and then in your renderer you could just do this:
sessionTimeoutJComboBox.setRenderer(new DefaultListCellRenderer<Integer>()
{
#Override
public Component getListCellRendererComponent(...)
{
JLabel label = (JLabel)super.getListCellRendererComponent( ... );
label.setText( timeoutOptions.get( value ) );
return label;
}
});
I need to change background of JLabels dynamically.
I've 70 JLabels in a class. All JLabels represent some specific items. The items names are same as the variable of JLabel. The Sold Items names are saved in database. If I run a query that will return an array of the sold items. The sold items that are same as the JLabel should change the background. Rest will not change.
I've got the variables of all fields like this:
Field fld[] = BlueLine.class.getDeclaredFields();
for (int i = 0; i < fld.length; i++)
{
System.out.println("Variable Name is : " + fld[i].getName());
}
How can I cast my fld to a JLabel and change background of the JLabel when certain condition meets ? for example:
if(fld[i] == label5){
label5.setBackground.(Color.red);
} // or something like this. ?
Any outline will help.
Currently you're just looking at the fields themselves - you're interested in the values of those fields. For example:
Object value = fld[i].get(target); // Or null for static fields
if (value == label5) {
...
}
Here target is a reference to the object whose fields you want to get the values from. For static fields, just use null, as per the comment.
It's not at all clear that all of this is a good idea, however - problems which can be solved with reflection are often better solved in a different way. We don't really have enough context to advise you of specifics at the moment, but I would recommend that you at least try to think of cleaner designs.
Try it using Jcomponent.putClientProperty() and Jcomponent.getClientProperty().
Steps to follow:
First set the name of the JLabel same as its variable name
Put it as client property of JPanel where JLabel is added
Get it back using client property from JPanel using name of JLabel
Note: you can access it by using Field.getName() as defined in your question.
Sample code :
final JFrame frame = new JFrame();
final JPanel panel = new JPanel();
panel.addContainerListener(new ContainerListener() {
#Override
public void componentRemoved(ContainerEvent e) {
String name = e.getChild().getName();
if (name != null) {
System.out.println(name + " removed");
panel.putClientProperty(name, null);
}
}
#Override
public void componentAdded(ContainerEvent e) {
String name = e.getChild().getName();
if (name != null) {
System.out.println(name + " added");
panel.putClientProperty(name, e.getChild());
}
}
});
MyLabels myLabels = new MyLabels();
panel.add(myLabels.getProduct1());
panel.add(myLabels.getProduct2());
panel.add(myLabels.getProduct3());
JButton btn = new JButton("Product1 and Product3 are sold");
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String[] soldItems = new String[] { "Product1", "Product3" };
for (String soldItem : soldItems) {
Object obj = panel.getClientProperty(soldItem);
if (obj instanceof JLabel) {
((JLabel) obj).setForeground(Color.RED);
}
}
}
});
panel.add(btn);
frame.add(panel);
frame.setSize(400, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
MyLabels.java:
class MyLabels {
private JLabel Product1;
private JLabel Product2;
private JLabel Product3;
public MyLabels() {
Product1 = new JLabel("Product1");
Product1.setName(Product1.getText());
Product2 = new JLabel("Product2");
Product2.setName(Product2.getText());
Product3 = new JLabel("Product3");
Product3.setName(Product3.getText());
}
public JLabel getProduct1() {
return Product1;
}
public void setProduct1(JLabel product1) {
Product1 = product1;
}
public JLabel getProduct2() {
return Product2;
}
public void setProduct2(JLabel product2) {
Product2 = product2;
}
public JLabel getProduct3() {
return Product3;
}
public void setProduct3(JLabel product3) {
Product3 = product3;
}
}
I created a list basically copying the 'ListDemo.java' from the oracle site. I included a picture of what I have.
public static class BackpackList extends JPanel implements ListSelectionListener {
private JList list;
private DefaultListModel listModel;
private static final String useString = "Use";
private JButton useButton;
public BackpackList() {
super(new BorderLayout());
listModel = new DefaultListModel();
listModel.addElement("Flashlight");
listModel.addElement("Health potion");
listModel.addElement("Snacks");
//Create the list and put it in a scroll pane.
list = new JList(listModel);
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list.setSelectedIndex(0);
list.addListSelectionListener(this);
list.setVisibleRowCount(10);
JScrollPane listScrollPane = new JScrollPane(list);
useButton = new JButton(useString);
useButton.setActionCommand(useString);
useButton.addActionListener(new UseListener());
//Create a panel that uses BoxLayout.
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new BoxLayout(buttonPane,
BoxLayout.LINE_AXIS));
buttonPane.add(useButton);
buttonPane.add(Box.createHorizontalStrut(5));
buttonPane.add(new JSeparator(SwingConstants.VERTICAL));
buttonPane.add(Box.createHorizontalStrut(5));
buttonPane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
add(listScrollPane, BorderLayout.CENTER);
add(buttonPane, BorderLayout.PAGE_END);
}
class UseListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
//This method can be called only if
//there's a valid selection
//so go ahead and remove whatever's selected.
int index = list.getSelectedIndex();
listModel.remove(index);
int size = listModel.getSize();
if (size == 0) { //Nobody's left, disable firing.
useButton.setEnabled(false);
}
else { //Select an index.
if (index == listModel.getSize()) {
//removed item in last position
index--;
}
list.setSelectedIndex(index);
list.ensureIndexIsVisible(index);
}
}
}
#Override
public void valueChanged(ListSelectionEvent e) {
if (e.getValueIsAdjusting() == false) {
if (list.getSelectedIndex() == -1) {
//No selection, disable fire button.
useButton.setEnabled(false);
}
else {
//Selection, enable the fire button.
useButton.setEnabled(true);
}
}
}
}
Question 1: I am setting up a backpack for a basic text based game. I want to set up specific actions depending on what item you have selected in the list. What would be the code to make it so the health potion would do something different than the snacks?
Question 2: How could I make it so it would say something along the lines of "x2 Snacks" if you have 2 snacks or "x3 Snacks" if you have 3 snacks, etc.
The backpack needs to keep track of items that are defined elsewhere. JList can hold a list of any kind of object so what you need to do is create objects for the inventory items. Below shows an example using an enum:
public class InventoryManager {
public enum InventoryItem {
LIGHT("Flashlight") {
boolean isOn;
#Override public void doAction() {
isOn = !isOn;
}
#Override public String toString() {
return name;
}
},
POTION("Health Potions") {
#Override public void doAction() {
Game.getPlayer().setHealth(Game.getPlayer().getHealth() + 25);
remove(1);
}
},
SNACK("Snacks") {
#Override public void doAction() {
Game.getPlayer().setEnergy(Game.getPlayer().getEnergy() + 10);
remove(1);
}
};
private final String name;
private int quantity = 0;
private InventoryItem(String n) {
name = n;
}
public abstract void doAction();
public void add(int q) {
if ((quantity += q) < 0) quantity = 0;
}
public void remove(int q) {
add(-q);
}
#Override public String toString() {
return name + " x" + quantity;
}
}
public static InventoryItem[] getHeldItems() {
EnumSet<InventoryItem> items = EnumSet.allOf(InventoryItem.class);
Iterator<InventoryItem> it = items.iterator();
while (it.hasNext()) {
if (it.next().quantity < 1) {
it.remove();
}
}
return items.toArray(new InventoryItem[items.size()]);
}
}
The enum example is entirely static so there are some problems with actually doing it this way (I chose it primarily because it's the shortest code). But ultimately what you'll have is a superclass Item with abstract methods that the subclasses implement differently. Then you will populate the JList with the items held. When the user selects an item from the list, list.getSelectedValue() returns an Item object you can use in the game.
// or Item can be an interface classes implement
public abstract class Item {
public void doAction() {
Game.updateState();
}
}
public class Light extends InventoryItem {
boolean lighted;
#Override public void doAction() {
lighted = !lighted;
super.doAction();
}
}
public class Potion extends InventoryItem {
#Override public void doAction() {
player.hp++;
super.doAction();
}
}
public class Snack extends InventoryItem {
#Override public void doAction() {
player.energy++;
super.doAction();
}
}
The other way to do this is to use straight program logic, for example:
switch (list.getSelectedItem()) {
case "Flashlight": {
toggleFlashlight();
break;
}
case "Health Potion": {
usePotion();
break;
}
case "Snack": {
useSnack();
break;
}
}
But I have a feeling trying to do it all with logic like that will ultimately turn out to be more complicated.
fairly new to java here. I'm writing a GUI program of which I want to be able to append the strings (rather than the index number) of selected list items to a text area using a JButton. I am unaware of which java method would allow me to do this. When I use the getSelectedIndex method, it only allows me to append the index number, rather than the string value of the list item to my text area. If it is still unclear what I am asking, here is my code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class FantasyInterface extends JFrame implements ActionListener{
private JList list1;
private JList list2;
private JLabel runningbacks;
private JButton addPlayer1;
private JButton addPlayer2;
private JTextArea text;
String lineSeparator = System.getProperty("line.separator");
private String[] rbs = {"Matt Forte", "Arian Foster", "Maurice Jones-Drew", "Adrian Peterson", "Ray Rice"};
FantasyTeam team1 = new FantasyTeam(5);
FantasyTeam team2 = new FantasyTeam(5);
public FantasyInterface(){
super("Fantasy Football Simulator");
// Set up listsPanel
JPanel listsPanel = new JPanel();
runningbacks = new JLabel("Running Backs:");
listsPanel.add(runningbacks);
list1 = new JList(rbs);
list1.setVisibleRowCount(5);
list1.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
listsPanel.add(list1);
addPlayer1 = new JButton("Add To Team 1");
listsPanel.add(addPlayer1);
list2 = new JList(rbs);
list2.setVisibleRowCount(5);
list2.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
listsPanel.add(list2);
addPlayer2 = new JButton("Add To Team 2");
listsPanel.add(addPlayer2);
// Add formatted JPanels to Content Pane
getContentPane().add(listsPanel, BorderLayout.NORTH);
// Set up textPanel, where info will appear
JPanel textPanel = new JPanel();
text = new JTextArea(20, 20);
textPanel.add(text);
// Add formatted JPanels to Content Pane
getContentPane().add(text, BorderLayout.SOUTH);
ListSelectionListener listSelectionListener = new ListSelectionListener() {
public void valueChanged(ListSelectionEvent listSelectionEvent) {
//System.out.println("First index: " + listSelectionEvent.getFirstIndex());
//System.out.println(", Last index: " + listSelectionEvent.getLastIndex());
boolean adjust = listSelectionEvent.getValueIsAdjusting();
//System.out.println(", Adjusting? " + adjust);
if (!adjust) {
JList list = (JList) listSelectionEvent.getSource();
int selections[] = list.getSelectedIndices();
Object selectionValues[] = list.getSelectedValues();
for (int i = 0, n = selections.length; i < n; i++) {
if (i == 0) {
System.out.println(" Selections: ");
}
System.out.println(selections[i] + "/" + selectionValues[i] + " ");
}
}
}
};
list1.addListSelectionListener(listSelectionListener);
addPlayer1.addActionListener(this);
}
public void actionPerformed(ActionEvent event){
Object srcObj = event.getSource();
if (srcObj == addPlayer1){
text.append(lineSeparator + list1.getSelectedIndex());
}
}
}
The last part,
if (srcObj == addPlayer1){
text.append(lineSeparator + list1.getSelectedIndex());
}
is where I am wondering if there is a method to get the selected index in string form. Thanks to anyone who helps!
Use:
if (!list1.isSelectionEmpty()) {
text.append(lineSeparator + list1.getModel().getElementAt(list1.getSelectedIndex()));
}