I made a note card program that can help you study with JavaFX. It saves the class through XML and on boot up, it finds the XML files and adds them to an ArrayList called allProjects of type NoteCardSet, an ArrayList of NoteCards. With this, I made a dynamic amount of buttons that puts them 4 columns wide. Here is the code for that:
int amountPerRow = 4;
int current = 0;
int row = 0;
for (NoteCardSet noteCardSet : allProjects) {
Button b = new Button(noteCardSet.getName());
GridPane.setConstraints(b, current, row);
centerMenu.getChildren().add(b);
b.setOnAction(e -> {
border.setCenter(noteCardSetLayout(noteCardSet));
});
if (current < amountPerRow - 1)
{
current++;
}
else if (current >= amountPerRow - 1)
{
current = 0;
row++;
}
}
Obviously this is creatable in JavaFX but is it possible to created this in FXML?
No you cannot do this in FXML. There is no way to write a LOOP in fxml. If you are just considered about a Button, then you may use SceneBuilder and drag-drop multiple buttons.
Though, if you are considered about a more complex UI and want to repeat them, you can create a separate FXML and include it as many time as you need using <fx:include>.
You can also load the same fxml multiple times using a loop and put all the concerned data inside the initialize(), but this might not be the best solution you are looking for.
Related
I got 3 types of items I want to add to my RecyclerView, a button (item with a button inside of it), a dummy (item with empty display), a normal item (item with some stuff inside of it).
I'm going to write a scenario that describes the adding/remove process when it should work but it isn't for some reason.
Scenario:
-add a button + dummy to RecyclerView, they get displayed just fine.
WidgetItem dummy = new WidgetItem(true);
arrayList.add(0, dummy);
ca.notifyItemInserted(0);//ca is my adapter
WidgetItem btnHolder = new WidgetItem();
btnHolder.setButton(true);
arrayList.add(0, btnHolder);
ca.notifyItemInserted(0);
-add another normal item + 2 dummies -->fine
if (nbrItems % 3 == 0) {
for (int i = 0; i < 2; i++) {
WidgetItem dummy = new WidgetItem(true);
dummy.setTilte("dummy" + i);
arrayList.add(0, dummy);
ca.notifyItemInserted(0);
}
}
arrayList.add(0, wItem);
ca.notifyItemInserted(0);
-remove 1 dummy + add a normal item -->fine
if ((nbrDummy == 3)||(nbrDummy == 2))
for (int i = 0; !foundDummy; i++) {
if (cii.get(i).getDummy()) {
arrayList.remove(i);
ca.notifyItemRemoved(i);
foundDummy = true;
}
}
arrayList.add(0, wItem);
ca.notifyItemInserted(0);
-remove 1 dummy + add a normal item (the same as above) -->not fine
This's when the problem happens and instead of getting a 3rd 'normal item' i get another dummy instead in the display.
What confused me was that the "onCreateViewHolder" method in my custom adapter didn't even get called at this step while it got called just fine in the previous ones.
Even if the item that just got displayed was a dummy the "onCreateViewHolder" method should execute at least like how it should.
But the code just skipped right to the "onBindViewHolder" method.
I'm suspecting that maybe something happened after the deletion of that dummy but then again why it worked fine in the code above.
I tried "notifyItemRangeChanged" after deleting the dummy but the whole recyclerView got messed up.
So yeah, what's going on here?
My problem was due to how RecyclerView works I suppose.
After I delete an item from the list and create another, the same old back item that I deleted come back instead.
So after trying a couple of things i found out that putting recyclerView.getRecycledViewPool().clear(); between the items deletion and the creation code solved my problem.
In my game there's raining meteorites of differnet sizes. I've tried to make it so that if you touch a bigger meteorite, it will be removed (from an array), and a smaller meteorite object will take it's place on the same place as the bigger was removed.
The problem I have is that if you touch a bigger meteorite, it will get removed and go through all other meteorite types until it gets to the smallest one and completely dissapears... all in the same touch. I obviously don't want that. Not sure how to solve this problem either.
Here's the code that handles input:
private void handleInput() {
Iterator<FallingItem> iter = items.meteorites.iterator();
while (iter.hasNext()) {
FallingItem item = iter.next();
if (Gdx.input.justTouched()) {
gameCam.unproject(touchPoint.set(Gdx.input.getX(), Gdx.input.getY(), 0));
if (item.getClass() == SmallMeteorite.class && item.getBounds().contains(touchPoint.x, touchPoint.y)) {
meteoriteDestroyed.play(0.5f); //play sound
iter.remove(); //removes item from array when it's no longer needed
item.dispose(); //dispose meteorite texture to clear up memory
score += 20; //add to score
} else if (item.getClass() == MediumMeteorite.class && item.getBounds().contains(touchPoint.x, touchPoint.y)) {
meteoriteDestroyed.play(0.5f);
iter.remove();
item.dispose();
score += 10;
items.meteorites.add(new SmallMeteorite(item.getBounds().getX(), item.getBounds().getY()));
} else if (item.getClass() == LargeMeteorite.class && item.getBounds().contains(touchPoint.x, touchPoint.y)) {
meteoriteDestroyed.play(0.5f);
iter.remove();
item.dispose();
score += 10;
items.meteorites.add(new MediumMeteorite(item.getBounds().getX(), item.getBounds().getY()));
}
}
}
}
You're adding the items to the array so they still get iterated on. Instead, you need to mark them somehow so they can be changed after the iteration. There are a few ways to do this.
One way would be to keep a separate List. Clear it before doing this loop, and then add items that need to be replaced with smaller ones to the separate list. When the loop is done on the main list, then you can iterate the separate list to add the smaller versions to the main list.
But LibGDX has an even easier way. Instead of using a List to store your meteorites, use LibGDX's SnapshotArray class. It lets you iterate on a copy of the list, so your changes to the array don't take effect until you're done with iterating:
FallingItem[] array = snapshotArray.begin();
for (int i=0; i<snapshotArray.size; i++){ //important to use snapshotArray.size, not array.length
FallingItem item = array[i];
//...
//if (something) {snapshotArray.removeIndex(i, true); snapshotArray.add(new Something());}
}
array.end();
But before you even try that, think about whether you actually need separate classes for SmallMeteorite, MediumMeteorite, etc. There is definitely such as thing as over-encapsulation. If these objects all behave the same but simply have different parameters, they should probably be a single class whose parameters are modified to represent the different sizes. Then, instead of removing and replacing them in the array, you would only need to change their parameters.
Side note: it's wasteful that you check justTouched and do the unproject inside the loop instead of outside it. A lot of redundant repetition there.
Looking for a GWT DataGrid component which implements infinite scroll, BUT also makes sure to discard the results no longer visible on the screen : such as the previously loaded results that are not shown anymore.
This is to avoid a memory hog.
I've been trying to find this on Google, but no luck so far.
Please note : I could take a JS library and adapt it to what I need, but I don't think it would work good with GWT's DataGrid component.
Edit: I am interested specifically in an infinite scroll which ALSO discards/releases the topmost results that are not visible (and loads them up as appropriate).
Any ideas ?
As a matter of fact the showcase example has an infinite scrolling CellList. (you can find the code there).
Although this was done with a CellList the same principles should also apply to a DataGrid.
Check out the ShowMorePagerPanel.java file.
Update:
The onScroll function of ShowMorePagerPanel.java will add the new records at the bottom. However you can easily change the behavior:
Something along the lines (not tested tough):
HasRows display = getDisplay();
if (display == null) {
return;
}
boolean loadData = false;
// If scrolling up, change newStart
int oldScrollPos = lastScrollPos;
lastScrollPos = scrollable.getVerticalScrollPosition();
// get the current visible Range
Range currentRange = display.getVisibleRange();
if (oldScrollPos >= lastScrollPos) {
int newStart = Math.max(
currentRange.getStart() - incrementSize,0);
loadData = true;
}
int maxScrollTop = scrollable.getWidget().getOffsetHeight()
- scrollable.getOffsetHeight();
if (lastScrollPos >= maxScrollTop) {
// We are near the end, so increase the page size.
int newPageSize = Math.min(
display.getVisibleRange().getLength() + incrementSize,
display.getRowCount());
loadData = true;
}
if (loadData) {
display.setVisibleRange(newStart, newPageSize);
}
This is the first time I've ever tried using a Java Swing JTable, so I'm probably doing something silly.
I'm trying to dynamically update a JTable within a JFrame on a GUI, this is the code I've currently written:
private void updateGUI(String input, DefaultTableModel model, int elements) { //3 elements
try {
Object[] cellData = input.split("!\\*");
Iterator it = Arrays.asList(cellData).iterator();
int rowCount = cellData.length / numberOfElements;
model.setRowCount(rowCount);
for (int i = 0; i < rowCount; i++) {
for (int j = 0; j < numberOfElements; j++) {
model.setValueAt(it.next(), i, j);
}
}
} catch (Exception uhoh) {
System.out.println("Couldn't add new string to gui");
uhoh.printStackTrace();
}
}
Essentially, I pass the updateGUI function a String containing elements, separated by !*. At the moment the data looks like this:
firstName!*123456!*lastName
This then gets split up into the Object[], and I'm currently using an iterator to put it into the table cells.
However, I keep getting ArrayIndexOutOfBoundsException: 27 >=27 being thrown, so it looks I'm doing something wrong with the cell generation/population.
I'm sure there is a much better way of doing this, but after reading through a few examples, I'm still a bit puzzled.
Any suggestions or advice would be greatly appreciated.
Thanks!
The easiest way I found to do this is to write a custom TableModel. I've written many of them and they not that difficult when you get your head around them. Given the code you posted you've have this message.
Derive your TableModel class from AbstractTableModel. This will handle the registration of any model listeners (one of which will be your JTable). Then on insert you need to call fireXXX() to notify all the listeners that there is new data. From your example code where you are replacing all the data this would be fireTableDataChanged().
Have a look at the Glazedlists project: http://www.glazedlists.com/
It solves this and a lot more in a very easy to use way. Documentation on your specific case can be found at http://www.glazedlists.com/propaganda/features#TOC-Easy-TableModels
I have a 6 JCheckBoxes in the UI and based one some user operations, I have to change the state of the JCheckBoxes, like enabling,selecting and making it invisible. So, instead of having the code as separate for each JCheckBox, I have used the following code,
Object[] checkBoxCollection = null;
checkBoxCollection = new Object[]{qualityChkBox1, qualityChkBox2, qualityChkBox3, qualityChkBox4, qualityChkBox5, qualityChkBox6};
for (int i = 0; i < checkBoxCollection.length; i++) {
JCheckBox checkBox = (JCheckBox) checkBoxCollection[i];
if (checkBox.getText().equals("Name") || checkBox.getText().equals("RollNo")) {
checkBox.setSelected(true);
} else {
checkBox.setSelected(false);
}
}
Similarly, I have some places in code, where I am keep on changing the state like setSelected(false) and setSelected(true).
Is there any way that I can do more better than this ?
Thanks in advance.
As shown here, you may be able to use EnumSet to define sets that represent coherent states of your model. Then your check boxes can share a common Action that conditions each JCheckBox according to that defined state.