JavaFX8 - How to remove a TableCell which has a tooltip? - tooltip

I want to remove TableCells out of my TableView. Therefore I call this line:
table.getItems().remove(item);
The TableCell is removed correctly, but the ToolTip will be shown on the next TableCell.
For example: When I remove the first Cell, the ToolTip will be shown on the second Cell (which is now the first).
How do I avoid this issue?
My CellFactory looks like that:
column.setCellFactory(c -> {
TableCell<DataItem, DataItem> cell = new TableCell<DataItem, DataItem>() {
#Override
protected void updateItem(DataItem item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
setText(item.getName());
if (item.getDescription() != null && !item.getDescription().isEmpty()) {
setTooltip(new Tooltip(item.getDescription()));
}
}
}
};
return cell;
});

Handle the case where item is null. If you think in terms of "removing data from the table model", instead of "removing cells" (you're not removing any cells at all, you're just changing the data displayed by the existing cells), this should make sense.
column.setCellFactory(c -> {
TableCell<DataItem, DataItem> cell = new TableCell<DataItem, DataItem>() {
#Override
protected void updateItem(DataItem item, boolean empty) {
super.updateItem(item, empty);
if (item == null) {
setText(null);
setTooltip(null);
} else {
setText(item.getName());
if (item.getDescription() != null && !item.getDescription().isEmpty()) {
setTooltip(new Tooltip(item.getDescription()));
} else {
// may need something here, depending on your application logic...
}
}
}
};
return cell;
});

Related

How does one end a function in dart similar to in JS typing return

In Javascript when I want to end a function I usually write return, but in the dart, if I do that then the function asks for a return statement at the end of each branch which is messy.
Function createCategory(File image) {
String title = _categoryTitle.value;
if(image == null || title == null || title.length == 0) {
return null;
}
CategoryModel newCategory = new CategoryModel();
if(_categories.value == null) {
_categories.sink.add([newCategory]);
}
return null;
}
What is the correct way to do this in dart?
I think your confusion comes from that your method is valid Dart code but does not really do what I guess you think. Your method has the following signature:
Function createCategory(File image) {
This means your method is named createCategory, takes one argument of the type File and returns a Function. Since you have marked the method to return a Function, then Dart will tell you it is a problem if you just return; since this is properly not what you wanted.
If your method is not going to return any value, then you want to mark this with the return type of void like:
void createCategory(File image) {
String title = _categoryTitle.value;
if (image == null || title == null || title.length == 0) {
return;
}
CategoryModel newCategory = new CategoryModel();
if (_categories.value == null) {
_categories.sink.add([newCategory]);
}
return;
}
I should note, that the last return can be skipped since Dart will automatically add return; at the end of a function if it is missing.
you can do that like this:
void createCategory(File image) {
String title = _categoryTitle.value;
if (image != null && title.isNotEmpty && _categories.value == null) {
_categories.sink.add([CategoryModel()]);
}
}

How can I rebuild a widget (with a list) I can't access?

I can't update my debtlist after deleting one of the items.
I have a mainscreen with a bottomnavigationbar with two options. Check the list or a general info of all the items. index zero is the list, so its drawn by default.
https://i.imgur.com/6qOVPPE.png
In my main_screen.dart, I have a List debtList witch I get from a SQLite database. I pass this list into each constructor.
Widget _getTab(int currentIndex) {
switch (currentIndex) {
case 0:
return DebtList(debtList);
case 1:
return GeneralInfo(debtList);
break;
default:
return DebtList(debtList);
}
}
Now I tap on an item an access to that item info.
https://i.imgur.com/ikl4cEI.png
When I click on delete, it works. The item is no longer on the database, but the list is not updated.
dbHelper.deleteDebt(widget.debt.id);
Navigator.pop(context, **true**);
I've tried to return true so I can check it like this:
bool result = await Navigator.push(context, MaterialPageRoute(builder: (context) => DebtDetail(debt)));
if (result != null && result == true) {
...
But the method updateList() is in my main_screen.dart class and not in my debt_list.dart class.
What am I doing wrong? I can't update the list in my debt_list class because its final.
widget.debtList = debtList; //cant do this
What should I change?
Thank you for your time!
You need to notify the DebtList to know which list item Debt to remove. Since you have many actions on DebtDetail screen to update list like update, delete... so it's better to define a DTO (Data Transfer Object) class to pass from DebtDetail to DebtList.
class DebtActionResult {
int action; // 0: nothing, 1: update, 2: delete
int debtId;
Debt updateDebt;
DebtActionResult({this.action, this.debtId, this.updateDebt});
}
Now, on DebtDetail screen, we have to pass the result to DebtList
void _delete() {
DebtActionResult result = DebtActionResult(action: 2, debtId: widget.debt.id, null);
Navigator.pop(context, result);
}
void _update() {
DebtActionResult result = DebtActionResult(action: 1, debtId: widget.debt.id, newDebt); // handle this yourself, because you are adding `final` to the state. Remove the final or create a new `newDebt` state variable.
Navigator.pop(context, result);
}
So far so good, it's time to handle the result on DebtList screen.
Future<void> _navigateToDetail(Debt debt) async {
DebtActionResult result = await Navigator.push(context, MaterialPageRoute(builder: (context) => DebtDetail(debt)));
if (result == null) {
// Do nothing, no change
} else {
if (result.action == 2) {
// oh, it's a delete request
setState( () {
widget.debtList.removeWhere( (d) => d.id == result.debtId );
});
} else if (result.action == 1) {
// modify the debtList here .. write your code similar to delete above.
}
}
}

Doubly linked list java remove

I have a problem when deleting many nodes.
I can delete them if I select nodes like this:
But if I do something like this, I cannot delete them:
My Code:
public boolean remove(ProductNode<E> data) {
if (isEmpty()) {
throw new NoSuchElementException();
}
for (ProductNode<E> current = this.head; current != null; current = current.next) {
ProductNode<E> pre = current.prev;
ProductNode<E> next = current.next;
if (data != null) {
if (current.data.equals(data.data)) {
if (pre == null) {
head = next;
current.next = null;
} else {
if (next != null) {
next.prev = pre;
}
}
if (next == null) {
pre.next = null;
current.prev = null;
tail = pre;
} else {
if (pre != null) {
pre.next = next;
}
}
}
}
}
size--;
return false;
}
Search node
public ProductNode<E> search(E data) {
for (ProductNode<E> current = this.head; current != null; current = current.next) {
if (current.data.equals(data)) {
return current;
}
}
return null;
}
Remove
public void remove(E e) {
remove(search(e));
}
Delete:
for(Tab_Product p : remove_list){
List_Products.list_products.remove(p);
}
Your remove function (ProductNode data), is a bit complicated and may be affecting your code's ability to delete multiple nodes. In the case of this remove function you do not need traverse the whole data set. If you already have a reference to the node you can just directly modify the list with it.
public boolean remove(ProductNode<E> data) {
if (isEmpty()) {
throw new NoSuchElementException();
}
ProductNode<E> pre = data.prev;
ProductNode<E> next = data.next;
//First remove the nodes references to its neighbors.
data.prev = null;
data.next = null;
// Now check the neighbors and update their references
// to remove all references to the deleted node.
if (pre != null) pre.next = next;
if (next != null) next.prev = pre;
if (data == head) { //This checks the actual memory address.
head = next;
}
size--;
}
Since you already have the ProductNode, you do not need to search the list. your search() function is already doing that for you. since you already have the node you just need to make its references to its neighbors null then you just have to access the neighbors (if there are any) and make their old references skip over the deleted node.
I noticed a few reference errors where a deleted node was not getting completely removed from the list but i will not mention them because this delete function is rather complicated. Try simplifying the delete function and then see what your results are.
It also might be helpful if you show us the structure of the List_Products object.
Additionally you should verify that the data you select in the UI is getting passed correctly. This could be a UI bug.

tableView Filter , no input in the table

The goal is to filter the tableView .So, when I input something to filter it works just fine , but then when I hit backspace or remove the inputs on the textField Area to go back,the tableView shows no content in the table ,Then I have to restart the program to reload and show the data.The data is saved and loaded from an xml file.
Also, I put an ObservaleList of contacts on the Data Class to load and store the contactList ,But on the Controller I have a similar list for the filter then the controller extends the data class to getContacts from there and add the filtredList to it. I am pretty much sure that the problem comes from that
public Data() {
contacts = FXCollections.observableArrayList();
}
public ObservableList<Contact> getContacts() {
return contacts;
}
This is below the filter handle
public void filterContactList(String oldValue, String newValue) {
ObservableList<Contact> filteredList = FXCollections.observableArrayList();
if (filterInput == null || newValue.length() < oldValue.length() || newValue == null){
contactsTable.setItems(getContacts());
}else {
newValue = newValue.toUpperCase();
for (Contact contact: contactsTable.getItems()){
String filterFirstName = contact.getFirstName();
String filterLastName = contact.getFirstName();
if (filterFirstName.toUpperCase().contains(newValue) || filterLastName.toUpperCase().contains(newValue)){
filteredList.add(contact);
}
}
contactsTable.setItems(filteredList);
}
}
and this is the init listener
filterInput.textProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
filterContactList((String) oldValue, (String) newValue);
}
});
Do yourself a favor an use FilteredList for this:
private FilteredList<Contact> filteredContacts = new FilteredList<>(getContacts());
...
contactsTable.setItems(filteredList);
...
public void filterContactList(String oldValue, String newValue) {
if (newValue == null) {
filteredContacts.setPredicate(null);
} else {
final String lower = newValue.toLowerCase();
filteredContacts.setPredicte(contact -> contact.getFirstName().toLowerCase().contains(lower) || contact.getLastName().toLowerCase().contains(lower));
}
}
BTW: since this is called from a listener to filterInput's textProperty, I removed the check for null.

Vaadin can't get combo box field value at 0 position

I'm trying to set field at index 0 in Vaadin combo box to default value, so I could avoid error message if user doesen't select anything. So I would like that instead of blank field I have populated field at index 0.
I have tried to set it and managed it with this:
field.setNullSelectionAllowed(true);
field.setNullSelectionItemId(container.getIdByIndex(0));
So I don't have blank value at index 0, instead my previous value of index 1 is now at index 0. And that is exactly what I want and need and in combo box looks just as I want.
But, unfortunately, when I submit my form, value is not passed. Only values after index 0 are passed. It's so frustrating, can somebody help me? Value passed to setNullSelectionItemId exists 100%.
How can I grab value from index at place 0 in combo box?
p.s. here is my code:
public Field<?> buildAndBindComboBox(final String caption, final BeanItemContainer<?> container,
final Object propertyId, final String title, final ValueChangeListener listener, final boolean nullAllowed,
final boolean required, final boolean enabled, final boolean visible) {
#SuppressWarnings("serial")
ComboBox field = new ComboBox(caption, container) {
// http://dev.vaadin.com/ticket/10544
// - typing in ComboBox causes Internal Error
private boolean inFilterMode;
#Override
public void containerItemSetChange(com.vaadin.data.Container.ItemSetChangeEvent event) {
if (inFilterMode) {
super.containerItemSetChange(event);
}
}
#Override
protected List<?> getOptionsWithFilter(boolean needNullSelectOption) {
try {
inFilterMode = true;
return super.getOptionsWithFilter(needNullSelectOption);
} finally {
inFilterMode = false;
}
}
};
field.setStyleName("comboBox");
field.setInputPrompt("Select");
if(defaultValue == true){
field.setNullSelectionAllowed(false);
field.setNullSelectionItemId(container.getIdByIndex(0).toString());
//field.select(container.getIdByIndex(0));
//field.setValue(container.getIdByIndex(0));
//field.setRequired(false);
defaultValue = false;
} else {
field.setNullSelectionAllowed(nullAllowed);
field.setRequired(required);
}
field.setImmediate(true);
field.setNewItemsAllowed(false);
field.setFilteringMode(FilteringMode.CONTAINS);
if (title != null) {
field.setItemCaptionPropertyId(title);
}
//field.setNullSelectionAllowed(nullAllowed);
//field.setRequired(required);
field.setVisible(visible);
if (listener != null) {
field.addValueChangeListener(listener);
}
this.bind(field, propertyId);
field.setEnabled(enabled);
return field;
}
public void setDefaultValueFirstItem(boolean def){
defaultValue = def;
}
It is binded like this:
commitmentFeeBinder.setDefaultValueFirstItem(true);
commitmentFeeBinder.buildAndBindComboBox("No working day labels", noWorkingDays, "noWorkingDaysCF", "title", null, false, !transaCF, true, !transaCF);
If I understood your question correctly, Steffen Harbich is correct in suggesting that if you want the first item to be selected by default you should disable null selection and select the first item by default. E.g. this works:
ComboBox cb = new ComboBox("", Arrays.asList("First", "Second", "Third"));
cb.setNullSelectionAllowed(false);
cb.select("First");
Or alternatively with a BeanItemContainer:
List<MyBean> beans = Arrays.asList(new MyBean("First"), new MyBean("Second"), new MyBean("Third"));
BeanItemContainer<MyBean> bic = new BeanItemContainer<>(MyBean.class, beans);
ComboBox cb = new ComboBox("", bic);
cb.setNullSelectionAllowed(false);
cb.select(bic.getIdByIndex(0));
private void resetComboBoxToIndex(ComboBox combo, int index) {
BeanItemContainer<Bean_ComboBox> items_combo = (BeanItemContainer<Bean_ComboBox>)combo.getContainerDataSource();
if(items_combo != null && items_combo.size() > index) {
Bean_ComboBox primerItem = items_combo.getIdByIndex(index);
if(primerItem != null) {
combo.select(primerItem);
}
}
}

Resources