I have a JComboBox that I made this way, using an enum for its values:
JComboBox<StudyGrade> maxLevelOfStudiesCombo = new JComboBox<StudyGrade>(StudyGrade.values());
The enum looks like this:
public enum StudyGrade {
ELEMENTARY ("Primaria"),
MIDDLE ("Secundaria"),
MIDDLE_HIGH ("Preparatoria"),
HIGH ("Universidad"),
MASTERS ("Maestría / Posgrado"),
DOCTORATE ("Doctorado"),
POST_DOCTORATE ("Post Doctorado");
private String studies;
private StudyGrade(String studies) {
this.studies = studies;
}
public String getStudies() {
return studies;
}
public void setStudies(String studies) {
this.studies = studies;
}
#Override
public String toString() {
return studies;
}
}
As you can see I'm overriding the toString() method, so I can have the studies values shown instead of the enum ones...
However I want to show the studies values only in the JComboBox not everytime I use the StudyGrade enum.
How would I change the code, so whenever I use something like:
System.out.println(StudyGrade.HIGH);
I get printed HIGH instead of Universidad, but not for the JComboBox?
I'm overriding the toString() method, so I can have the studies values shown instead of the enum ones...
I've never used a enum before but I assume you can use it like any custom object added to the combo box so you should be able to use a custom renderer so you can control which data is displayed by the combo box.
Check out Combo Box With Custom Renderer for more information and a helper class.
You're looking to extend an enum, but that's impossible. It means that something is wrong with your requirement.
Rendering is done in the UI component, and it's not enum's business to deal with presentation of data. You should make you UI component render enum the way you'd like instead of trying to make enum understand where it's being used. Since you're a Swing fanatic you should know how to do that, something like this:
maxLevelOfStudiesCombo.setRenderer(new DefaultListCellRenderer() {
#Override
public Component getListCellRendererComponent(JList<?> jList, Object o, int i, boolean b, boolean b1) {
Component rendererComponent = super.getListCellRendererComponent(jList, o, i, b, b1);
setText(o instanceof StudyGrade ? ((StudyGrade) o).getStudies() : o.toString());
return rendererComponent;
}
});
That's going to do that.
You could just remove the toString override as the default toString for an enum is to return the name of the enum element.
And you could just have a simple for loop that would iterate through the values in your enums and add it to a string array. Then, you would need to pass that array as the argument for your JComboBox and it should be gold.
The code for it should look a bit like that:
//get all study grades
StudyGrade[] temp = StudyGrade.values();
//create a string array of same length as the array
String[] str = new String[temp.length];
//append all the studies value to the string array
for(int i = 0; i< temp.length; i++){
str[i] = temp[i].getStudies();
System.out.println(temp[i]);//debug
}
System.out.println("---------------------");//debug
for(String s : str){//debug
System.out.println(s);//debug
}//debug
//pass it
JComboBox<StudyGrade> maxLevelOfStudiesCombo = new JComboBox<StudyGrade>(StudyGrade.values());
Here is an example I made on repl.it
https://repl.it/GH28/1
Related
I have created buttons inside a panel using Java Swing. I have a button "Produce" that when clicked, I need it to create an object from type Produce (which is defined in another class and has items such as vendor, weight, and price).
When the button is clicked, the Produce object should be created using information that a user has typed in to the text fields in the same panel. So if a user typed in the vendor, weight, and price for an item into the textfields, the Produce object needs to be created with those values.
So far I have:
public void createButtons() {
JButton produceBtn = new JButton("Produce");
JButton prepMealBtn = new JButton("Prepared Meal");
infoPanel.add(produceBtn, BorderLayout.SOUTH);
infoPanel.add(prepMealBtn, BorderLayout.SOUTH);
produceBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
Object source = e.getSource();
if(source == produceBtn){
Produce myProduce = new Produce();
}
}
}
}
But I can't figure out how to do the mentioned part above.
the Produce object should be created using information that a user has
typed in to the text fields in the same panel. So if a user typed in
the vendor, weight, and price for an item into the textfields, the
Produce object needs to be created with those values.
First, you'll need to create some sort of list/array to hold the created objects.
List<Produce> produce = new ArrayList<>(); // make this global within the class
then, you have two options, either overload the Produce constructor and create another constructor to take 3 params (vendor, weight, and price):
Example constructor:
public Produce(type param1, type param2, type param3){ //Constructor to take 3 params
// assign the values appropriately
}
or create setter methods:
public void setVender(type vender){
// assign the values appropriately
}
public void setWeight(type weigth){
// assign the values appropriately
}
public void setPrice(type price){
// assign the values appropriately
}
then you can do this:
if(source == produceBtn){
String vender = someTextField.getText();
String weight = someTextField.getText();
String price = someTextField.getText();
//perform any conversion from string to numbers if needed.
/*
*/
//then create the object
Produce myProduce = new Produce(vender,weight,price);
// make sure the order in which you input the data into the arguments of the constructor above is the same as the order in which the constructor definition of the Produce class is.
produce.add(myProduce);
}
or you can use the setter methods.
Lastly but not least, you seem to have a typo with addActionListener, you're missing the closing ).
Also, you can simplify your code by using lambda expression:
produceBtn.addActionListener(e -> {
Object source = e.getSource();
if(source == produceBtn){
// do something
}
});
The purpose of the program is to calculate the volumes of different geometrical figures (Like a cylinder or a pyramid). I've started out by adding a list where the user can choose between the different figures.
The problem is that I don't know how to make the program know which formula to use. I need to be able to separate the choices instead of just making an int out of the answer.
private void btnAktiveraActionPerformed(java.awt.event.ActionEvent evt) {
String form = listForm.getSelectedValue().toString();
int fo = Integer.valueOf( form );
String höjd = txfHöjd.getText().toString();
int hö = Integer.valueOf( höjd );
String bredd = txfBredd.getText().toString();
int br = Integer.valueOf( bredd );
String radie = txfRadie.getText();
int ra = Integer.valueOf(radie);
String djup = txfDjup.getText();
int dj = Integer.valueOf(djup);
double ACyl = 3.14*ra*ra*hö;
double APyr = (br*dj*hö)/2;
double AKub = br*dj*hö;
double ARät = br*dj*hö;
txfHöjd.setEnabled(false);
txfBredd.setEnabled(false);
txfDjup.setEnabled(false);
txfRadie.setEnabled(false);
listForm.setEnabled(false);
}
private void btnBeräknaActionPerformed(java.awt.event.ActionEvent evt) {
// I know this code won't work, its just a reminder.
if (answer == Cyinder){
System.out.print("volymen är: "+ACyl+" cm^3");
}
}
I don't understand your question very clearly. I would suggest to make a plan to solve your problems.
make a list of figures that program will calculate
make a list of methods to count volumes of those figures
create individual classes, variables etc...
create methods
create main method with user input
You mentioned you don't know which formula to use. I assume there won't be many formulas in your program. I would create an individual method for each individual figure i.e. piramidFormula(), cilinderFormula()...
There is no point to refer to polimorphism when I think your level of programming is very basic at this stage.
I hope that will help you a little bit.
You need a list to hold the things, you seem to understand this just fine.
You need a way to select things. Selection is typically not exactly the same thing as the list, you need a class to be responsible for the "selection" behaviour.
Each thing has a routine that can calculate the volume. That means it will need input parameters. This is where it starts to get tricky, because if you want all of your things to be in the same list, you need to decide how to manage the different input parameters for the different types in the list.
public List<VolumeCalculations> volumeCalculations ...
public interface VolumeCalculation {
public double getVolume();
}
public class CubleCalcuation implements VolumeCalculation {
private double side = 0;
public void setSide(double value) {
this.side = value;
}
#Override
public double getVolume() {
return side*side*side;
}
}
the other volume calculations are left as an exercise to you.
Then you need to put them all in the list
volumeCalculations.add(new CubeVolumeCalculation());
...
But when you select the calculation, you will need "something" to ask for the right input.
public interface CalculationInputGather {
public void setCalcualtion(VolumeCalcuation value);
public void askForInputs();
}
which the one for the CubleCalcuation might look like
public CubeInputGather implements CalculationInputGatherer {
#Override
public void setCalculation(VolumeCalcualtion value) {
if (value instanceof CubeCalcuation) {
this.volume = value;
}
throw new IllegalArgumentException("value must be a CubeCalculation");
}
public void askForInputs() {
System.out.println("enter the side value:");
// read the value
volume.setSide(value);
}
}
then when you know the selected item in the list, you can use a Map of Calcuations to their input gatherers to lookup the right input gatherer for the selected calcuation.
If you already have the list for the user to choose from, maybe consider a map instead. You can have all your shapes as the keys of the map and then the formulas for volume as the values of the map. The list of shapes can be provided to the user via the keySet and their response can be matched back against the map to find the formula.
EDIT: You have your formulas for each shape inside an action event. You'll need to move those into a separate class
public static class Formulas() {
// list all formulas here
private String cylinder = "3.14*r*r*h";
}
Then when you hit the action you can either create a new instance of the Formulas class and use any convenience methods you might write in there.
I am working with Vaadin and I have some trouble iterating through choices in a ComboBox. I have my object looking like:
class MyObject{
private String text;
private Integer i;
public MyObject(String text,Integer i){
this.text = text;
this.i = i;
}
public String toString(){
return text;
}
//Getters and setters omitted
}
I add it to the box like this:
MyObject o1 = new MyObject("o1",23);
MyObject o2 = new MyObject("o2",44);
ComboBox box=new ComboBox();
box.addItem(o1);
box.addItem(o2);
This works great when I want to get the chosen data:
MyObject o3 = (MyObject)box.getValue();
But now I need to iterate through the choices in the ComboBox and I don't know how. I seem to need some kind of ID but I don't know how to use that. I tried the following with no success but it doesn't work(and is really ugly):
Collection IDs = box.getItemIds();
Iterator it = IDs.iterator();
while(it.hasNext()){
Object id = it.next();
Item item = IDs.getItem(id);
//What to do now?
}
I'd like to keep my object simple and avoid using beans and complex containers. Vaadins examples are mostly for String and that doesn't help me so much. I'd really appreciate any help.
If you look at the javadoc for ComboBox, you'll see that the addItem method is actually defined on the AbstractSelect class, and it actually takes the itemId as the parameter. (This is in turn delegated to the Select's container, which in this default case is an IndexedContainer)
So, Collection IDs=box.getItemIds(); will return you the collection of MyObject - i.e. what you are actually after.
I'm trying to get the position (as a int) of a JComboBox object, The ComboBox is generated and haves an action listener like this
for (int d=0; d<i; d++)
{
titulos.addItem(listaPraBox[d]);
}
ActionListener comboListener = new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
ItemSelectable is =(ItemSelectable)actionEvent.getSource();
objectoseleccionado = selectedString(is);
DeskMetodos.listaTexto(objectoseleccionado);
}
};
titulos.addActionListener(comboListener);
The executes
static private String selectedString(ItemSelectable is) {
Object selected[] = is.getSelectedObjects();
return ((selected.length == 0) ? "null" : (String)selected[0]);
}
But I wanted the position of the selected object to get a string from another array by that int.
Is this even possible? By the search I've made there isn't even reference to this.
JComboBox defines getSelectedIndex(). The implementation is just to loop over the data model checking equality with getSelectedItem().
That doesn't make it up into ItemSelectable, but neither does the data model itself, so you may need to use the concrete class.
Instead of storing items in a ComboBox and having to use the index to reference another array of values. Just store an object in the ComboBox that has a toString() output that matches your current displayed value and a direct reference to the object in the array. That way any object pulling the selected item or dealing with comobo box can just pull the value they need and not have to also "know" about this other array.
1) In the following method (actionListener) a user select a grade (e.g. A-F) from a JComboBox.
2) There are multiple JComboBoxes, and each selection made gets stored into a single String[] array.
PROBLEM:
Here is the dilemma, if a user goes back and changes a selection made from a random JComboBox the previous grade selection does not get replaced in the array, however the new selection made gets stored at the next array index.
How can I make the program replace the previous grade selection and not just add the new selection?
relevant variables:
int counter;
private JComboBox[] gradeField;
//grade.userGrades[] is array of grades taken from selected combo boxes
Action Listener anonymous class:
gradeField[counter].addActionListener(new ActionListener () {
#Override
public void actionPerformed(ActionEvent e) {
Object holder = e.getSource();
JComboBox tempGradeBox = (JComboBox)holder;
String theGrade = (String)tempGradeBox.getSelectedItem();
grade.userGrades[grade.getNext()] = theGrade;
grade.updateNext();
}
});
Thanks in advance for any help.
I save the grade in an array and increment the index,
Well you should not be incrementing the index. This assumes that the user selects the grades from the combo box in a sequential order. As you have discovered users can often work randomly.
Instead you need to know which combo box has been changed and then update the appropriate entry in your array.
Or a different solution might be to update your array at the end. So maybe you have a "Process Results" button. Then you can sequentually loop through all the combo boxes to get the selected value.
Update the user grade being at the same index as the combo box:
final int index = counter;
gradeField[counter].addActionListener(new ActionListener () {
#Override
public void actionPerformed(ActionEvent e) {
Object holder = e.getSource();
JComboBox tempGradeBox = (JComboBox)holder;
String theGrade = (String)tempGradeBox.getSelectedItem();
grade.userGrades[index] = theGrade;
}
});
Here's another variation of JB Nizet's answer:
class OuterClass
{
...
gradeField[counter].addActionListener( new GradeSettingActionListener( counter ) );
...
class GradeSettingActionListener implements ActionListener
{
// -- Doesn't have to be final here (it does in JB's answer), but I like to be restrictive.
private final int index;
public GradeSettingActionListener( int index )
{
this.index = index;
}
#Override
public void actionPerformed( ActionEvent e )
{
Object holder = e.getSource();
JComboBox tempGradeBox = (JComboBox) holder;
String theGrade = (String) tempGradeBox.getSelectedItem();
grade.userGrades[index] = theGrade;
}
}
}
This approach removes the anonymous class by adding an inner class. The inner class will still have access to grade. You don't gain much here unless there's a chance you'll be splitting out the inner class later.
Of course, camickr's suggestion to process all the grades at once may also be valid, depending on other requirements (i.e., whether additional processing is done after the grades are stored in the array, which seems likely).