I have a ListView that I am working to add a ContextMenu to. I have the ContextMenu working find but have another issue.
My setCellFactory code, used to setup the context menus:
lvAppetites.setCellFactory(lv -> {
ListCell<Appetite> cell = new ListCell<>();
ContextMenu contextMenu = new ContextMenu();
MenuItem editAppetiteMenu = new MenuItem();
editAppetiteMenu.textProperty().bind(Bindings.format("Edit ..."));
editAppetiteMenu.setOnAction(event -> {
// Code to load the editor window
editAppetite(cell.getItem());
});
contextMenu.getItems().add(editAppetiteMenu);
MenuItem deleteAppetiteMenu = new MenuItem();
deleteAppetiteMenu.textProperty().bind(Bindings.format("Delete ..."));
deleteAppetiteMenu.setOnAction(event -> {
// Code to delete the appetite
});
contextMenu.getItems().add(deleteAppetiteMenu);
contextMenu.getItems().add(new SeparatorMenuItem());
MenuItem addAppetiteMenu = new MenuItem();
addAppetiteMenu.textProperty().bind(Bindings.format("Add New ..."));
addAppetiteMenu.setOnAction(event -> {
// Code to delete the appetite
});
contextMenu.getItems().add(addAppetiteMenu);
cell.textProperty().bind(cell.itemProperty().asString());
// If nothing selected, remove the context menu
cell.emptyProperty().addListener((obs, wasEmpty, isNowEmpty) -> {
if (isNowEmpty) {
cell.setContextMenu(null);
} else {
cell.setContextMenu(contextMenu);
}
});
return cell;
});
My ListView is searchable through a TextField with a listener; the listener filters the items in the ListView as the user types.
The problem now, is that as the list is filtered, any empty cells now display null.
From reading another question, I'm fairly confident that the ListView is still displaying a graphic for the removed cells. I know how to handle that within the ListView by overriding the updateItem method, but how would I handle this from within my setCellFactory method instead?
Is that even possible or will I need to refactor my entire ListView?
Thank you, as always, for all your help!
The problem arises from the line
cell.textProperty().bind(cell.itemProperty().asString());
When the cell is empty, the item will be null, so the binding will (I believe) evaluate to the string "null".
Try something that tests for the cell being empty or the item being null, e.g.
cell.textProperty().bind(Bindings
.when(cell.emptyProperty())
.then("")
.otherwise(cell.itemProperty().asString()));
or (thanks to #fabian for refining this version)
cell.textProperty().bind(Bindings.createStringBinding(
() -> Objects.toString(cell.getItem(), ""),
cell.itemProperty()));
Related
I'm making a button that when i click on him the visibility of a checkbox withing a listView will change. however it appears that the code run as expected but the visibailty is not udpateing. is there a way to update the item's visabilty?
mButtonEdit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
for(int i = 0 ; i<calanders.size();i++){
View view = mListView.getAdapter().getView(i,null,mListView);
if(mButtonEdit.isSelected()){
print("button is selected");
CheckBox checkBox = view.findViewById(R.id.clockproperties_checkBox);
checkBox.setVisibility(View.GONE);
}else{
print("button is not selected");
CheckBox checkBox = view.findViewById(R.id.clockproperties_checkBox);
checkBox.setVisibility(View.VISIBLE);
}
}
mListView.getAdapter().
if(mButtonEdit.isSelected()){
mButtonEdit.setSelected(false);
}else{
mButtonEdit.setSelected(true);
}
}
});
You should never call the ListAdapter's getView() method. It is only supposed to be called by the system when scrolling though the ListView. Instead you need to update the list by calling mListView.getAdapter().notifyDataSetChanged().
Add a boolean field in the adapter and update its value when the button is clicked.
You can create a model/data class based on your data and keep a Boolean variable for checkbox visibility. So default make it false and on button click get the position of list-view item and update Boolean variable to true, and do adapter.notifyDataSetChanged().
You can also try with :
((YourAdapter) yourListView.getAdapter()).notifyDataSetChanged();
I want the context menu items of my natTable to change, depending on the selected row. How can I achieve this ?
UPDATE: this works so far, i have A and B showing on even/uneven lines. My next question is: does this mean that I have to call these methods for every menu item groups ?
myPopupMenuBuilder.withMenuItemProvider("A", new IMenuItemProvider() {
#Override
public void addMenuItem(NatTable paramNatTable, Menu paramMenu) {
MenuItem row = new MenuItem(paramMenu, SWT.PUSH);
row.setText("A");
}
}).withMenuItemProvider("B", new IMenuItemProvider() {
#Override
public void addMenuItem(NatTable paramNatTable, Menu paramMenu) {
MenuItem row = new MenuItem(paramMenu, SWT.PUSH);
row.setText("B");
}
}).withVisibleState("A", new IMenuItemState() {
#Override
public boolean isActive(NatEventData paramNatEventData) {
return paramNatEventData.getRowPosition() % 2 == 0;
}
}).withVisibleState("B", new IMenuItemState() {
#Override
public boolean isActive(NatEventData paramNatEventData) {
return paramNatEventData.getRowPosition() % 2 == 1;
}
});
It depends on how you implement the context menu. If you use the NatTable way of registering a context menu (which I typically suggest) you can use PopupMenuBuilder#withEnabledState() or PopupMenuBuilder#withVisibleState(). Inside the implementation of IMenuItemState you get the position where the click was performed, which then can be used to get the underlying data.
More information can be found in my blog post about that topic: NatTable context menus with Eclipse menus
If you want to use E4 menus, you will have to implement some additional logic to extract the necessary information from the click with regards to the NatTable.
I load a listview with a list (a).
In response to a toggle change, I switch the listview content to another list (b).
If list (a) is longer than list (b), then the excess items remain displayed in the listview even though it is no longer selectable.
For instance, buyList = {'100532','100533'} and saleList = {'100000'}. If I start with radioBuy selected, the list will show '100532' and '100533'. Switching the toggle from radioBuy to radioSale will cause the list to display '100000' and '100533'. '100533' is not selectable, but it remains visible.
The observable lists themselves have been shown to be the correct size and contain the correct items. It's just that the ListView display shows some old data.
Things I've tried:
1. ticketListView.getItems().clear() and then rebuilding a new list before the list switch.
2. Using ticketListView.getItems().removeAll(0, ticketListView.getItems().size())
3. Using a loop to remove each item individually.
4. Using ticketListView.refresh() in combination with all the above.
My toggle ChangeListener:
typeGroup.selectedToggleProperty().addListener(new ChangeListener<Toggle>() {
public void changed(ObservableValue<? extends Toggle> observable, Toggle oldValue, Toggle newValue) {
if (typeGroup.getSelectedToggle().equals(radioBuy))
ticketListView.setItems(buyList);
if (typeGroup.getSelectedToggle().equals(radioTransfer))
ticketListView.setItems(transList);
if (typeGroup.getSelectedToggle().equals(radioSale))
ticketListView.setItems(saleList);
}
});
How do I get my listview to blank itself before it switches content?
Sorry for wasting everyone's time. It turns out I was indeed using a custom cell factory:
ticketListView.setCellFactory(new Callback<ListView<Header>,
ListCell<Header>>() {
public ListCell<Header> call(ListView<Header> headerListView) {
return new ListCell<Header>() {
#Override
protected void updateItem(Header item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
setText(item.getTicket());
}
}
};
}
}
);
Removing this code and doing as I mentioned earlier, overriding toString, solved the problem. Obviously I need to study cell factories a little more...
if (item != null) {
setText(item.getTicket());
} else {
setText(null);
}
You should add this code to clear empty cells.
Working on this app on which have some SwipeMenuListViews.
One of those has an edit menu item like this.
Now as you can imagine on Edit click should make the item editable.
And this is not working out at all.
Tried a lot and on what I found was that I needed to use an EditText view and so I did. The problem I've got by using them is that these are blocking the parent swipe menu.
I need the SwipeMenu (where the EditViews are child from)to have some sort of priority (not sure if this possible) OR enable all listeners on the EditText views.
ListView with swipe menus - ContactsFragment.java
SwipeMenuListView listView = (SwipeMenuListView) inflatedView.findViewById(R.id.contacts_list_view);
contactAdapter = new ContactAdapter(getContext(), contacts);
listView.setSelector(R.drawable.list_selector);
listView.setAdapter(contactAdapter);
SwipeMenuCreator swipeMenu = new SwipeMenuCreator() {
#Override
public void create(SwipeMenu menu) {
SwipeMenuItem editItem = new SwipeMenuItem(getActivity().getApplicationContext());
editItem.setBackground(new ColorDrawable(Color.rgb(0xC9, 0xC9, 0xCE)));
editItem.setWidth(Dimension.dpTopx(getActivity(), 90));
editItem.setTitle("Edit");
editItem.setTitleSize(18);
editItem.setTitleColor(Color.WHITE);
menu.addMenuItem(editItem);
SwipeMenuItem deleteItem = new SwipeMenuItem(getActivity().getApplicationContext());
deleteItem.setBackground(new ColorDrawable(Color.rgb(0xF9, 0x3F, 0x25)));
deleteItem.setWidth(Dimension.dpTopx(getActivity(), 90));
deleteItem.setIcon(R.drawable.ic_delete);
menu.addMenuItem(deleteItem);
}
};
I already tried these on each EditText - ContactAdapter.java
contactEmail.setFocusableInTouchMode(false);
contactEmail.setEnabled(false);
contactEmail.setOnClickListener(null);
contactEmail.setFocusable(false);
And after spending some hours searching my creativity is emptied and that's why I need some help from here.
Is there anyway to add an image to a JavaFX ListView?
This is how I am currently setting the list view items.
private ListView<String> friends;
private ObservableList<String> items;
items = FXCollections.observableArrayList(getFriends);
friends.setItems(items);
I'm also using the list view value as an id to know which was selected.
Implement a ListCell that displays the image and set a cellFactory on the ListView. The standard oracle tutorial has an example of a custom list cell implementation.
You would do something along the following lines:
friends.setCellFactory(listView -> new ListCell<String>() {
private ImageView imageView = new ImageView();
#Override
public void updateItem(String friend, boolean empty) {
super.updateItem(friend, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
Image image = getImageForFriend(friend);
imageView.setImage(image);
setText(friend);
setGraphic(imageView);
}
}
});
The updateItem(...) method can be called quite often, so it is probably better to preload the images and make them available to the cell, rather than creating them every time updateItem(...) is called.
remember to refresh or load your Listview
with myListViewWithPath.setItems(myObserverFilledWithImages);
#FXML
private void browseButton(ActionEvent event) throws Exception {
System.out.println("browseButton");
DirectoryChooser chooser = new DirectoryChooser();
File file = chooser.showDialog(myStage);
file = new File("E:\\FOLDER\\Imagen_File");
if (file != null) {
directoryField.setText(file.toString());
oImage.setAll(load(file.toPath()));
}
imageFilesList.setItems(oImage); //this one load or refresh the ListView
}