I'm looking for a way to dynamically add columns to a vaadin table.
I tried this:
private Button createAddColumnButton() {
Button addProductButton = new Button("Add column");
addProductButton.addClickListener(new ClickListener() {
public void buttonClick(ClickEvent event) {
count = count++;
table.addGeneratedColumn("Column "+count, new ColumnGenerator() {
#Override
public Object generateCell(final Table source, Object itemId, Object columnId) {
String x = "some stuff";
return x;
}
});
}
});
return addProductButton;
}
This button allowed me dynamically add a column, however only one column before I recieved an error saying I cannot have two columns with the same id. How can I change the ID so it is unique & add lots of columns?
TL;DR
Simple change your code to:
count = count + 1;
Explenation
That's beacause assigment
count = count++;
does not work in the way you expect. Take a look at the following code:
public class HelloStackOverflow {
public static void main(String[] args) {
int count = 0;
count = count++;
System.out.println(count);
}
}
This prints on standard output 0. You will even get warning (The assignment to variable count has no effect) if you change your code to:
count = ++count;
You can find even better explanation here.
Related
So im developing a javafx gui that it should return all the valid values found in an ArrayList input range, but instead it's functionality its only valid for the latest value added,
so it's only returning the latest entry on the button click, i leave an example picture of the gui
as i hope this would help to clarify:
so if i add 2 different registration, 2 makes and 2 model and try and get the button search by regNo it only works with the latest entry not the previous one;
I leave the code for the setOnAction Method for the button
public void searchByReg(javafx.event.ActionEvent e) {
// clear the text field from the previous message
txtOutput.clear();
// get the car from the user through the car reg
String carReg = txtReg.getText();
// method to check if the field its empty
for (int i = 0; i < cars.size(); i++) {
if (carReg.equalsIgnoreCase(cars.get(i).getRegNo())) {
txtOutput.setText("You have selected \n" + cars.get(i));
carFound = true;
} else {
txtOutput.setText("That car is not in our Database");
}
}
}
Thank you for your help in Advance!!!
Try this, looks like you override text every time until last valid number.
txtOutput.setText("You have selected");
for (int i = 0; i < cars.size(); i++) {
if (carReg.equalsIgnoreCase(cars.get(i).getRegNo())) {
txtOutput.append("\n" + cars.get(i));
carFound = true;
}
}
if(!carFound) {
txtOutput.setText("That car is not in our Database");
}
This is not a JavaFX issue, but just a muddled-up search loop.
There's better ways to do this since Java 8. The following is much simpler and easier to read and debug:
public class LookupSample {
record Car(String name, String regNo) {
}
public static void main(String[] args) {
List<Car> cars = List.of(new Car("Mazda", "123"), new Car("Ford", "123"), new Car("Dodge", "789"));
String carReg = "123";
String result = cars.stream().filter(car -> car.regNo().equals(carReg)).map(Car::name).collect(Collectors.joining("\n\t ", "You have selected:\n\t", ""));
System.out.println(result);
boolean carFound = cars.stream().anyMatch(car -> car.regNo().equals(carReg));
System.out.println("Car Found? " + carFound);
}
}
I am doing an application, and I need to create 10 TextFields and save value in a XML file that i have. (I know how to save it in XML)
The issue I have is I want to save it all (in a XML) automatically without repeating the code like 10 times for each variable.
I am trying reflect.Field library to do it (Not accomplished) but i don't know if it's the best solution.
public TextField Tf_TestI1;
public TextField Tf_TestF1;
public TextField Tf_TestI2;
public TextField Tf_TestF2;
public TextField Tf_TestI3;
public TextField Tf_TestF3;
public TextField Tf_TestI4;
public TextField Tf_TestF4;
public TextField Tf_TestI5;
public TextField Tf_TestF5;
//Pair them and save it in XML
private void stuffVariables(){
String nameField1= "Tf_TestI";
String nameField2= "Tf_TestF";
Field[] fields = Controller.class.getFields();
for (int i = 0; i <fields.length ; i++) {
if (fields[i].getName().startsWith(nameField1)){
for (int j = 0; j < fields.length ; j++) {
if (fields[j].getName().equals(nameField2+fields[i].getName().substring(fields[i].getName().length()-1))){
System.out.println("EQUALS : "+fields[i].getName() + " = "+ fields[j].getName());
try {
//System.out.println("1: "+fields[i].getValue);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
I am trying to get the pair of Test Initial and Final to finally save it in XML like this...
<TESTS>
<TEST>
<INITIAL>AD</INITIAL>
<FINAL>AVB</FINAL>
</TEST>
<TEST>
<INITIAL>AQEW</INITIAL>
<FINAL>AVFE</FINAL>
</TEST>
<!-- ... MORE TEST -->
<TESTS>
This is not the way you want to do it. As a general rule of thumb, if you feel the need to use reflection, you're doing it wrong.
It looks like you have an arbitrary number of pairs of TextField objects. So that's the first port of call - create a separate class to house those pairs of TextField:
class TextFieldPair {
private TextField initialVal;
private TextField finalVal;
public TextFieldPair(TextField initialVal, TextField finalVal) {
this.initialVal = initialVal;
this.finalVal = finalVal;
}
public TextField getInitialVal() {
return initialVal;
}
public TextField getFinalVal() {
return finalVal;
}
}
...you then want an arbitrary number of these objects. Every time you have an arbitrary number of objects you'll want to use a collection of some sort, such as a list, so we can then loop through them like so:
public class Main {
private List<TextFieldPair> list = new ArrayList<>();
//...Other code that adds textfield objects to the above list
private void stuffVariables() {
for(TextFieldPair pair : list) {
System.out.println("Initial value: " + pair.getInitialVal().getText());
System.out.println("Initial value: " + pair.getFinalVal().getText());
}
}
}
You'll then have all the values printed out from each of those TextField objects, and you can manipulate them (such as outputting XML instead) as you see fit.
My main objective was to make it easy when I add more TextFields...
Using HashMap I only have to add a Key to his Value.
Using numbers in the Key made it more easy in my case.
//[...]
Map<String, TextField> map; //Global variable
//I just have to add the new TextFields to the HashMap
private void mapSaveRangs() {
map = new HashMap<>();
map.put("rangInitial1", tfrangInitial1);
map.put("rangFinal1", tfrangFinal1);
map.put("rangInitial2", tfrangInitial2);
map.put("rangFinal2", tfrangFinal2);
map.put("rangInitial3", tfrangInitial3);
map.put("rangFinal3", tfrangFinal3);
map.put("rangInitial4", tfrangInitial4);
map.put("rangFinal4", tfrangFinal4);
map.put("rangInitial5", tfrangInitial5);
map.put("rangFinal5", tfrangFinal5);
}
private void rangsInPairsXML(Element peeRangs) {
String sKeyrInitial = "rangInitial";
String sValuerInitial;
String sKeyrFinal = "rangFinal";
String sValuerFinal;
//Making sure that we have pair of 2
if (map.size() % 2 == 0) {
//map half size loop
for (int numRang = 1; numRang <= map.size() / 2; numRang++) {
sValuerInitial = map.get(sKeyrInitial + numRang).getText();
sValuerFinal = map.get(sKeyrFinal + numRang).getText();
//Verifying values and saving it in peeRang (XML Element)
if (!(sValuerInitial.equals("") || sValuerFinal.equals(""))) {
Element eRang = new Element("RANG");
eRang.addContent(new Element("INITIAL").addContent(sValuerInitial));
eRang.addContent(new Element("FINAL").addContent(sValuerFinal));
peeRangs.addContent(eRang);
}
}
} else {
System.out.println("ERROR!!");
//[...]
}
}
As the title says. Basically I have an ArrayList where DiceRoll is a class that is used successfully in a TableView to update the values as they are changed.
public class DiceRoll {
private final SimpleIntegerProperty rollNumber = new SimpleIntegerProperty();
private final SimpleIntegerProperty cubeRoll = new SimpleIntegerProperty(0);
private final SimpleIntegerProperty icosahedron = new SimpleIntegerProperty(0);
private final SimpleIntegerProperty dodecahedron = new SimpleIntegerProperty(0);
public DiceRoll(int rollNumber) {
this.rollNumber.set(rollNumber);
}
public void incrementRoll(DiceTypes type){
switch(type){
case CUBE:
this.cubeRoll.set(this.cubeRoll.getValue() + 1);
break;
case DODECAHEDRON:
this.dodecahedron.set(this.dodecahedron.getValue() + 1);
break;
case ICOSAHEDRON:
this.icosahedron.set(this.icosahedron.getValue() + 1);
break;
}
}
public int getRollNumber() {
return rollNumber.get();
}
public SimpleIntegerProperty rollNumberProperty() {
return rollNumber;
}
public int getCubeRoll() {
return cubeRoll.get();
}
public SimpleIntegerProperty cubeRollProperty() {
return cubeRoll;
}
public int getIcosahedron() {
return icosahedron.get();
}
public SimpleIntegerProperty icosahedronProperty() {
return icosahedron;
}
public int getDodecahedron() {
return dodecahedron.get();
}
public SimpleIntegerProperty dodecahedronProperty() {
return dodecahedron;
}
public void reset(){
cubeRoll.set(0);
icosahedron.set(0);
dodecahedron.set(0);
}
}
Like so:
rollNumberColumn.setCellValueFactory(new PropertyValueFactory<>("rollNumber"));
This all works, although I would prefer a non-factory approach. However I can't figure out how to do the same kind of linking with a BarChart.
My BarChart has a CategoryAxis as the X axis and a NumberAxis as the Y axis. I can successfully add data with XYGraph.Series and XYGraph.Data methods but these won't update automagically. How would I do this?
edit:
TableColumn<DiceRoll, Number> rollNumberColumn = new TableColumn<>("Roll Number");
rollNumberColumn.setCellValueFactory(new PropertyValueFactory<>("rollNumber"));
tableView.setItems(FXCollections.observableArrayList(model.getDiceRolls())); //model.getDiceRolls() returns an ArrayList<DiceRoll>
tableView.getColumns().setAll(rollNumberColumn, cubeRollNumberColumn, dodecahedronRollNumberColumn, icosahedronRollNumberColumn);
A DiceRoll is basically initialized as a number that you can roll. I've added this in my table x20 for all 20 possible rolls and just add to it if it gets rolled. In graph form this would mean 3 graphs with on the X axis the roll number and the Y axis the amount of times that it rolled.
The factory comment is kind of irrelevant to my question but I don't really like using the factory pattern which is used here.
Edit2:
ObservableList<DiceRoll> testing = FXCollections.observableArrayList(model.getDiceRolls());
testing.addListener((ListChangeListener)c -> System.out.println("I'm working!"));
I tried doing this as suggested by Chris but the program doesn't print anything. It could be that observableArrayList() returns a new list instead of wrapping existing references but that would mean my table wouldn't work either. What could be wrong?
Edit3:
What was wrong is that observables "change" when the value of the reference changes. And the values of an observablelist are other references which in my case get added once and get never touched again. This means that it NEVER actually changes in the lifetime of the program after startup. I figured out that I can attach listeners to the IntegerProperties in DiceRoll to do whatever the hell I want when one of them changes which is awesome and gives me much needed control.
edit4
this.model.getDiceRolls().parallelStream().forEach(diceRoll -> {
diceRoll.cubeRollProperty().addListener((observable, oldValue, newValue) ->
cubeSeries.getData().get(diceRoll.getRollNumber() - 1).setYValue(newValue)
);
diceRoll.dodecahedronRollProperty().addListener((observable, oldValue, newValue) ->
dodecahedronSeries.getData().get(diceRoll.getRollNumber() - 1).setYValue(newValue)
);
diceRoll.icosahedronRollProperty().addListener((observable, oldValue, newValue) ->
icosahedronSeries.getData().get(diceRoll.getRollNumber() - 1).setYValue(newValue)
);
});
This is what I used at the end to monitor changes. All it requires is that your class uses a so called *Property variable which supports listeners out of the box. The moment it changes you can run a piece of code to update your chart for example.
If you are using an ObservableList you can add a ListChangeListener and call your chart update function when the list changes.
ObservableList<DiceRoll> myList = FxCollections.observableArrayList();
myList.addListener((ListChangeListener)(c -> { updateMyChart() }));
Then in updateMyChart() you would iterate the list:
private void updateMyChart() {
/* Clear series */
for(int i = 0; i < myList.size(); i++ {
/* Create new Series */
}
/* Add Series */
}
And you would just simply add your DiceRoll objects to the list.
myList.add(new DiceRoll(1));
P.S - I left out the steps for creating / deleting a series as you mention you already can do that, if you need to see that too I can add it in.
I'm new to using OOP, I typically just put all my code in a single class and use methods. But I want to maintain state information and think classes are the best fit but I'm having trouble wrapping my head around it.
Say I have a list of items and I want to stop when the total sum of all previous items in the list equals X(in this case 10 so it takes item 1 + 2, then 2+3.etc..until it hits the threshold 10), I can use a method to calculate it but it involves me doing the entire process all over again when all I really need to do is increment by the last item and then see if my data exceeds the threshold. Here's my code so far but I know its not good because although it works its really just using the class as an independent method and recalculating on every loop. My goal is to,using this structure, reduce loops if not necessary to check thresholds.
Any suggestions?
Code:
public class LearningClassesCounter {
public static void main(String[] args) {
int[] list = new int[]{1,2,3,4,5,6,7,8,9,10};
int[] data_list = new int[list.length];
for (int current_location = 0; current_location<list.length;current_location++) {
//can only put commands in here. Nothing above.
Counter checker = new Counter(data_list);
System.out.println(checker.check_data(current_location));
for (int i =0; i<100; i++){
if (checker.check_data(current_location) == false) {
break;
}
data_list[current_location] = (list[current_location]+1); //this is just a random function, it could be any math function I just put it in here to show that some work is being done.
}
}
//its done now lets print the results
for (Integer item : data_list) {
System.out.println(item);
}
}
}
class Counter {
private int[] data_list;
private int total_so_far;
// create a new counter with the given parameters
public Counter(int[] data_list) {
this.data_list = data_list;
this.total_so_far = 0;
}
public boolean check_data(int current_location) {
// TODO Auto-generated method stub
int total_so_far = 0;
//System.out.println(total_so_far);
for (int item : data_list) {
total_so_far = item + total_so_far;
if (total_so_far >= 10) {
break;
}
}
if (total_so_far>=10) {
return false;
} else {
return true;
}
}
}
I don't need anyone to fix my code or anything(I want to do it myself, the code is just to give an idea of what I'm doing). I'm more interested in the flaw in my logic and maybe a way for me to better think about designing classes so I can apply them to my own situations better.
So the solution is that you do not update the data_list directly. Instead have a setter method in the Counter class that takes the index and value to update. It updates the value in the array and also updates a count value.
Something like this:
class Counter{
private final int[] list;
private count = 0;
private final maxCount = 10;
public Counter(int[] list){
this.list = list;
}
public boolean updateValueAndCheckPastMax(int index, int value){
list[index] = value;
count += value;
return count >= maxCount;
}
}
You are way over thinking this, and a counter class is not really necessary in this case.
I'm also interested as to why you'd be doing this line:
data_list[current_location] = (list[current_location]+1);
Do you want your data_list to be the same as list, but each value is incremented by 1?
If you are merely trying to return a sub-array of the values that are < 10, i would suggest just doing this in a for loop, and using an int as a counter.
I have a list that is poulated via a local text file. I have the following code that simple prints the selected item/items when the button is click.
private void jButton5ActionPerformed(java.awt.event.ActionEvent evt) {
int[] selection = jList3.getSelectedIndices();
// selection.toString();
for (int i = 0; i < selection.length; i++){
Object selString = jList3.getModel().getElementAt(selection[i]);
System.out.println(selString);
}
}
Instead of printing the item I would like each button click on each object to be recorded somehow. I have no idea what kind of component, method etc to implement. Any guidance is appreciated.
My end result will be something similar to this.
System.out.println(SelString has been clicked X amount of times);
Use a hash map with your objects (selString) as keys, and a counter as value. Something like:
private Map<Object, Integer> buttonMap = new HashMap<Object, Integer>
private void jButton5ActionPerformed(java.awt.event.ActionEvent evt) {
Integer counter = null;
int[] selection = jList3.getSelectedIndices();
for (int i = 0; i < selection.length; i++){
Object selString = jList3.getModel().getElementAt(selection[i]);
counter = buttonMap.get(selString);
if(counter == null) {
buttonMap.put(selString, new Integer(0));
}
buttonMap.put(selString, new Integer(counter.intValue() + 1));
System.out.println(selString + " has been clicked " + buttonMap.get(selString) + " times.");
}
}
You can use PropertyChangeSupport to notify each time jList items are clicked, besides you should create a listener to receive events notification (through propertyChangeSupport.addPropertyChangeListener).
Once there, you can get the event properties such as the property name and property's new value which will be selected item on jList3 in this case, for counting how many times some item was clicked, you could use a HashMap, setting the key as the item index of jList and the associated value how many time the item has been clicked:
PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
HashMap<Integer, Integer> clickCounter = new HashMap<Integer, Integer>();
public NewJFrame() {
initComponents();
propertyChangeSupport.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("selectedIndex")) {
System.out.println("Selected index: " + evt.getNewValue());
System.out.println("Selected text: " + jList3.getModel().getElementAt(evt.getNewValue()));
if (clickCounter.containsKey((Integer) evt.getNewValue())) {
clickCounter.put((Integer) evt.getNewValue(), clickCounter.get((Integer) evt.getNewValue()) + 1);
} else {
clickCounter.put((Integer) evt.getNewValue(), 1);
}
}
}
});
}
private void jList1MouseClicked(java.awt.event.MouseEvent evt) {
// TODO add your handling code here:
propertyChangeSupport.firePropertyChange("selectedIndex", -1, jList3.getSelectedIndex());
}
At any time you can retrive how many times certian item was clicked accessing clickCounter
I would suggest using an inner class which holds whatever object you are currently putting into the JList and adding a counter member variable as well as overriding the toString().
class MyListItem
{
int selectionCount;
Object listItem; //may consider generics here, but left them out cause they can be tricky
public MyListItem(Object item)
{
selectionCount=0;
listItem=item;
}
public void incrementSelectionCount()
{
selectionCount++;
}
public String toString()
{
return listItem.toString() + " has been clicked " + selectionCount + " times.");
}
}
Then in your action listener
private void jButton5ActionPerformed(java.awt.event.ActionEvent evt)
{
int[] selection = jList3.getSelectedIndices();
for (int selectedIndex : selection)
{
Object selString = jList3.getModel().getElementAt(selectedIndex);
if(selString instanceOf MyListItem)
{
MyListItem selItem = (MyListItem) selString;
selItem.incrementSelectionCount();
System.out.println(selString);
}
}
}
This should save time on look ups, boxing, etc. Also, this helps keep things sane as the project grows since MyListItem can be grown to deal with all types of actions you may want in the future in case you want different things to happen for things other than button presses. The basic idea here is that the MyListItem should keep track of everything you are interested in tracking so you don't need multiple lists and even worse, to remember to add an item to both a JList and a HashMap or any other data structure. This way it's either on every data structure it needs to be or not at all.