I have a CheckListView which is displaying a list of custom objects. I am trying to implement a select all/ select none option however the list View is not changing. The checkboxes only change if clicked
pendingUsers_listView.setCellFactory(new Callback<ListView<User>, javafx.scene.control.ListCell<User>>() {
#Override
public ListCell<User> call(ListView<User> listView) {
return new PendingUserCell();
}
});
Custom Cell:
public class PendingUserCell extends CheckBoxListCell<User> {
PendingUserCell() {
this.setSelectedStateCallback(new Callback<User, ObservableValue<Boolean>>() {
#Override
public ObservableValue<Boolean> call(User param) {
return new SimpleBooleanProperty(param.isApproved());
}
});
}
#Override
public void updateItem(User u, boolean empty) {
super.updateItem(u, empty);
if (empty) {
this.setText(null);
} else {
this.setText(u.getFullName() + " ( " + u.getEmail() + " )");
}
}
}
These are the functions responsible for the action
public void handleSelectAll() {
this.pendingUsers_listView.getCheckModel().checkAll();
this.pendingUsers_listView.refresh();
}
public void handleSelectNone() {
this.pendingUsers_listView.getCheckModel().clearChecks();
this.pendingUsers_listView.refresh();
}
here is the solution:
I have a Model class, that holds the information about the items in the ListView, i put there a name, that is displayed in the lisview, and a boolean property that holds the checked/unchecked value like this:
public class Model {
private StringProperty name;
private BooleanProperty selected;
public Model(String name, Boolean selected) {
this.name = new SimpleStringProperty(name);
this.selected = new SimpleBooleanProperty(selected);
}
public String getName() {
return name.get();
}
public StringProperty nameProperty() {
return name;
}
public boolean isSelected() {
return selected.get();
}
public BooleanProperty selectedProperty() {
return selected;
}
}
Then I made a custom StringConverter to convert Model to String for displaying the text in listView like this:
public class ModelConverter extends StringConverter<Model> {
#Override public String toString(Model object) {
return object.getName();
}
#Override public Model fromString(String string) {
return null;
}
}
Then in the controller I added some items to the listView and i put as first element Select All, and a listener for it. So if you check it all items became checked, if you uncheck it you all became unchecked. Here is the code:
public class TestController implements Initializable {
#FXML
private ObservableList<Model> data = FXCollections.observableArrayList();
#FXML
private ListView<Model> listView;
#Override
public void initialize(URL location, ResourceBundle resources) {
listView.setItems(data);
listView.setCellFactory(factory -> new CustomListCell(Model::selectedProperty, new ModelConverter()));
data.addAll(new Model("Select All", false), new Model("Apple", false), new Model("Orange", false),
new Model("Peach", false));
data.get(0).selectedProperty().addListener(
(observable, oldValue, newValue) -> data.forEach(item -> item.selectedProperty().set(newValue)));
}
}
So I made as simple as it can be, by using one item from the listView, but you can use many ways to select all select none, for example defining two separate checkboxes outside of listView, or a togglebutton or something else that you want, the important is to add a listener to the respective component that you want to use it for select all select none, then everything became easy I think.
Related
I have used Combobox in editable mode and i have used filtered list to filter the list as the text change in the editor. The filtering works as i type the data in the editor. The problem occurs when i select member from the drop down list, the selected value disappear as soon i select a member from the drop down list.
When i run the same code in jdk 8 it is working but in jdk 19 the problem arises.
I have uploaded both the vodeos.
Program run with jdk 8
Program run with jdk 19 and javafx 19
The code is displayed as follows
public TextField _unit_type;
public TextField _symbol;
public TextField _formal_name;
public ComboBox<UnitQuantityCode> _unit_quantity_code;
public TextField _number_of_decimal_places;
private UnitSecondary unitSecondary;
private UnitCodeDao unitCodeDao;
private ObservableList<UnitQuantityCode> codes;
private FilteredList<UnitQuantityCode> filteredList;
#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
unitCodeDao = new UnitCodeDao();
unitSecondary = new UnitSecondary();
codes = FXCollections.observableArrayList();
filteredList = new FilteredList<>(codes);
codes.setAll(unitCodeDao.getAllUqc());
_unit_quantity_code.setItems(filteredList);
_unit_quantity_code.setCellFactory(new CodeCellFactory());
_unit_quantity_code.setConverter(new CodeStringConverter());
_unit_quantity_code.getEditor().focusedProperty().addListener(new UnitComboFocusListener());
_unit_quantity_code.getEditor().textProperty().addListener(new TextChangeListener());
}
private class CodeCellFactory implements Callback<ListView<UnitQuantityCode>, ListCell<UnitQuantityCode>>{
#Override
public ListCell<UnitQuantityCode> call(ListView<UnitQuantityCode> unitQuantityCodeListView) {
return new CodeCell();
}
}
private class CodeCell extends ListCell<UnitQuantityCode>{
#Override
protected void updateItem(UnitQuantityCode unitQuantityCode, boolean b) {
super.updateItem(unitQuantityCode, b);
if (unitQuantityCode == null || b){
setGraphic(null);
setText(null);
}else {
setGraphic(null);
setText(unitQuantityCode.getCode());
}
}
}
private class CodeStringConverter extends StringConverter<UnitQuantityCode>{
private UnitQuantityCode u;
#Override
public String toString(UnitQuantityCode unitQuantityCode) {
if (unitQuantityCode == null)
return null;
u = unitQuantityCode;
return unitQuantityCode.getCode();
}
#Override
public UnitQuantityCode fromString(String s) {
return u;
}
}
private class UnitComboFocusListener implements ChangeListener<Boolean>{
#Override
public void changed(ObservableValue<? extends Boolean> observableValue, Boolean aBoolean, Boolean t1) {
if (t1){
_unit_quantity_code.show();
}else{
_unit_quantity_code.hide();
}
}
}
private class TextChangeListener implements ChangeListener<String>{
#Override
public void changed(ObservableValue<? extends String> observableValue, String s, String t1) {
if (!t1.equals("")){
Platform.runLater(()->filteredList.setPredicate(
t->t.getCode().toLowerCase().contains(t1.toLowerCase())));
}else{
Platform.runLater(()->filteredList.setPredicate(null));
}
}
}
Kindly provide a solution.
I have a TableView where the last column is an "Action" column, containing a custom ActionBox object, with buttons for several actions. To add behaviour to this ActionBox, I need to pass a Data object to it. However, I don't know how to reference the object.
class TableViewWithActionColumn() {
#FXML TableColumn<Data, Void> actionColumn;
public TableViewWithActionColumn() {
// Code for loading custom component...
}
#FXML
public void initialize() {
populateActionColumn();
}
private void populateActionColumn() {
Callback<TableColumn<Data, Void>, TableCell<Data, Void>> cellFactory = new Callback<TableColumn<Data, Void>, TableCell<Data, Void>>() {
#Override
public TableCell<Data, Void> call(final TableColumn<Data, Void> param) {
return new TableCell<Data, Void>() {
private final ActionBox actionBox = new ActionBox();
#Override
public void updateItem(Void item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
} else {
setGraphic(actionBox);
}
}
};
}
};
actionColumn.setCellFactory(cellFactory);
}
}
I assumed that the reference to the object was in Void item, so I tried replacing all occurrences of Void with Data, and doing setGraphic(new ActionBox(item));, but this led to a NullPointerException, so I suppose that's not the right way to do it. So, how do I reference row's data in CellFactory context?
TableCell has a getTableRow() method, that gives you a reference to the TableRow that contains the cell. The TableRow is itself a cell implementation, so you can call its getItem() method to get the data represented by the row.
In context (and removing all the unnecessary boilerplate from your code):
private void populateActionColumn() {
actionColumn.setCellFactory(col -> new TableCell<Data, Void>() {
private final ActionBox actionBox = new ActionBox();
#Override
public void updateItem(Void item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
} else {
Data rowData = getTableRow().getItem();
// ... something like: actionBox.setData(rowData) ;
setGraphic(actionBox);
}
}
});
}
The ComboBox control has a setConverter method, see JavaFX ComboBox - Display text but return ID on selection for an example. I am trying to adapt the accepted answer from that question to work with a ListView control. I don't see a setConverter method for the ListView class in any documentation.
#FXML private ListView<RowlvPqAttributes> lvPqAttributes;
//...
class RowlvPqAttributes {
private String ID;
private String text;
public RowlvPqAttributes(String ID, String text) {
setID(ID);
setText(text);
}
public String getID() {
return ID;
}
public void setID(String iD) {
ID = iD;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
private void initlvPqAttributes() {
lvPqAttributes.setConverter(new StringConverter<RowlvPqAttributes>() {
#Override
public String toString(RowlvPqAttributes object) {
return object.getText();
}
#Override
public RowlvPqAttributes fromString(String string) {
return lvPqAttributes.getItems().stream().filter(ap ->
ap.getText().equals(string)).findFirst().orElse(null);
}
});
If I accept the suggested fix it doesn't help:
They do not work in the same way, for the ListView you configure the display using setCellFactory method
lvPqAttributes.setCellFactory(lv -> new ListCell<RowlvPqAttributes>() {
#Override
public void updateItem(RowlvPqAttributes row, boolean empty) {
super.updateItem(row, empty) ;
setText(empty ? null : row.getText());
}
}
For getting data from selected item:
RowlvPqAttributes selected = lvPqAttributes.getSelectionModel().getSelectedItem();
String selectedID = selected.getID();
String selectedText = selected.getText();
I wish to disable the native contextual menu that is shown when you select some text, the one with the select all, copy, share and search buttons. I do not however want to disable selections themselves. Ideally I would wish to extend the menu actually, but honestly, I am more than perfectly fine with just disabling it. With textfields and the like it tends to be relatively simple from the documentation I found, but I just can't figure out a way to make this work with XWalkView/CordovaWebView. Might be that I am just searching in entirely the wrong corner though.
I have a workaround.
For WebView there is a solution, but it doesn't work for XWalkView:
WebView selection menu workaround
My gradle includes compile 'org.xwalk:xwalk_core_library:14.43.343.17'
My solution, the main idea in the onAttachedToWindow method:
public class XWalkWebView extends XWalkView {
public XWalkWebView(Context context, AttributeSet attrs) {
super(context, attrs);
}
private ActionMode.Callback mOriginalCallback;
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
try {
View innerChild = ((ViewGroup) getChildAt(0)).getChildAt(0);
Field contentViewField = innerChild.getClass().getDeclaredField("mContentView");
contentViewField.setAccessible(true);
XWalkContentView xWalkContentView = (XWalkContentView) contentViewField.get(innerChild);
Field contentViewCoreField = xWalkContentView.getClass().getSuperclass().getDeclaredField("mContentViewCore");
contentViewCoreField.setAccessible(true);
ContentViewCore viewCore = (ContentViewCore) contentViewCoreField.get(xWalkContentView);
viewCore.setContainerView(this);
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
#Override
public ActionMode startActionMode(ActionMode.Callback callback) {
mOriginalCallback = callback;
ActionMode.Callback c = new // your callback...
return super.startActionMode(c);
}
}
I try Warabei's solution but it not work on 15.44.384.13. I improve to find ContentViewCore cross versions:
public class XWalkWebView extends XWalkView {
...
private Field getFields(Class clazz){
for(Field field:clazz.getDeclaredFields()){
if(ContentViewCore.class == field.getType()){
return field;
}
}
clazz = clazz.getSuperclass();
if(clazz!=null && clazz!=Object.class){
Field field = getFields(clazz);
if(field!=null)return field;
}
return null;
}
private void inject(View view){
Field field = getFields(view.getClass());
if(field!=null){
field.setAccessible(true);
try {
ContentViewCore viewCore = (ContentViewCore) field.get(view);
viewCore.setContainerView(this);
return;
}catch(Exception e){
}
}
if(view instanceof ViewGroup){
ViewGroup viewGroup = (ViewGroup)view;
int count = viewGroup.getChildCount();
for(int i = 0;i<count;i++){
inject(viewGroup.getChildAt(i));
}
}
}
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
inject(this);
}
...
To disable contextual selection menu:
#Override
public ActionMode startActionMode(ActionMode.Callback callback) {
return new ActionMode() {
#Override
public void setTitle(CharSequence charSequence) {
}
#Override
public void setTitle(int i) {
}
#Override
public void setSubtitle(CharSequence charSequence) {
}
#Override
public void setSubtitle(int i) {
}
#Override
public void setCustomView(View view) {
}
#Override
public void invalidate() {
}
#Override
public void finish() {
}
#Override
public Menu getMenu() {
return null;
}
#Override
public CharSequence getTitle() {
return null;
}
#Override
public CharSequence getSubtitle() {
return null;
}
#Override
public View getCustomView() {
return null;
}
#Override
public MenuInflater getMenuInflater() {
return null;
}
};
}
It is an old post but I haven't been able to find another solution.
A simple workaround to disable context options in crosswalk view..
Go to your crosswalk project into res/menu/select_action_menu.xml
Delete or comment on the item you don't want to show
Save, build and run
This CSS should prevent context menus in both Android and IOS, as given in the cordova template
* {
-webkit-tap-highlight-color: rgba(0,0,0,0); /* make transparent link selection, adjust last value opacity 0 to 1.0 */
}
body {
-webkit-touch-callout: none; /* prevent callout to copy image, etc when tap to hold */
-webkit-text-size-adjust: none; /* prevent webkit from resizing text to fit */
-webkit-user-select: none; /* prevent copy paste, to allow, change 'none' to 'text' */
}
I have created a cellList :
I want to add a clickhandler when user clicks on button "Send"
Please Help. FieldUpdater should work if user clicks on "Send" button.
Here is the code :
final String imageHtml =AbstractImagePrototype.create(images.contact()).getHTML();
// first make a list of HasCell type - MyClass is the type of object being displayed in the CellList (could be String for simple labels)
List<HasCell<contactinfo, ?>> hasCells = new ArrayList<HasCell<contactinfo, ?>>();
hasCells.add(new HasCell<contactinfo, String>()
{
public ButtonCell cell = new ButtonCell();
public Cell<String> getCell()
{
return cell;
}
#Override
public String getValue(contactinfo object)
{
return "Send";
}
#Override
public FieldUpdater<contactinfo, String> getFieldUpdater() {
FieldUpdater< contactinfo, String > updater= new FieldUpdater<contactinfo, String>() {
#Override
public void update(int index, contactinfo object, String value) {
Window.alert("You clicked "+object.getName());
}
};
return updater;
}
}
);
// now construct the actual composite cell using the list (hasCells)
Cell<contactinfo> myClassCell = new CompositeCell<contactinfo>(hasCells)
{
#Override
public void render(Context context, contactinfo value, SafeHtmlBuilder sb)
{
sb.appendHtmlConstant("<table><tbody><tr>");
super.render(context, value, sb);
sb.appendHtmlConstant("</tr></tbody></table>");
}
#Override
protected Element getContainerElement(Element parent)
{
// Return the first TR element in the table.
return parent.getFirstChildElement().getFirstChildElement();
}
#Override
protected <X> void render(Context context, contactinfo contactinfo, SafeHtmlBuilder sb, HasCell<contactinfo, X> hasCell)
{
this renders each of the cells inside the composite cell in a new table cell
// Value can be null, so do a null check..
if (contactinfo == null) {
return;
}
sb.appendHtmlConstant("<table>");
// Add the contact image.
sb.appendHtmlConstant("<tr><td rowspan='3'>");
sb.appendHtmlConstant(imageHtml);
sb.appendHtmlConstant("</td>");
// Add the name and address.
sb.appendHtmlConstant("<td style='font-size:95%;'>");
if(contactinfo.getName()!=null)
sb.appendEscaped(contactinfo.getName());
sb.appendHtmlConstant("</td></tr><tr><td>");
if(contactinfo.getAddress()!=null)
sb.appendEscaped(contactinfo.getRemarks());
sb.appendHtmlConstant("</td>");
Cell<X> cell = hasCell.getCell();
sb.appendHtmlConstant("<td>");
cell.render(context, hasCell.getValue(contactinfo), sb);
sb.appendHtmlConstant("</td></tr></table>");
}
};
// then make the actual cellList, passing the composite cell
cellList =new CellList<contactinfo>(myClassCell,KEY_PROVIDER);
// Add a selection model so we m select cells.
singleselectionModel = new SingleSelectionModel<contactinfo>(
KEY_PROVIDER);
cellList.setSelectionModel(singleselectionModel);
singleselectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
#Override
public void onSelectionChange(SelectionChangeEvent event) {
}
});
Also, I do not see in code any piece that handles event. Did you read through http://www.gwtproject.org/doc/latest/DevGuideUiCustomCells.html#cell-onBrowserEvent
Have you tried the code sample provided by GWT - http://gwt.googleusercontent.com/samples/Showcase/Showcase.html#!CwCellSampler . Browse the "Source Code" !!!
If you have not read already then you should start here # DevGuideUiCustomCells