I have made a TreeView, represented by a custom cellFactory where each cell is represented by an HBox looking like this.
How can I access the checkbox so that if you check it, a private boolean field in the corresponding EventTreeItem changes it's value?
Code:
public class EventTreeItem extends TreeItem<String>{
SimpleStringProperty item;
boolean important = true;
public EventTreeItem(boolean important, int id){
this.noNode = noNode;
super.setValue(id);
}
public EventTreeItem(){
}
public void setImportant(Boolean important){
this.important = important;
}
}
CellFactory:
public final class CustomTreeCellFactory extends TreeCell<String>{
private TextField textField;
private HBox hBox;
private HBox hBoxLeaf;
public CustomTreeCellFactory(){
try {
hBox = (HBox) FXMLLoader.load(getClass().getResource("/Views/TreCell.fxml"));
} catch (IOException e) {
System.out.println("This didn't work");
e.printStackTrace();
}
try {
hBoxLeaf = (HBox) FXMLLoader.load(getClass().getResource("/Views/TreCellLowestLevel.fxml"));
} catch (IOException e) {
System.out.println("This didn't work");
e.printStackTrace();
}
hBox.setAlignment(Pos.CENTER_LEFT);
hBoxLeaf.setAlignment(Pos.CENTER_LEFT);
}
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
EventTreeItem eventTreeItem = (EventTreeItem) getTreeItem();
if (getTreeView().getTreeItemLevel(getTreeItem())==1) {
setGraphic(this.hBox);
((CheckBox) ((HBox)getGraphic()).getChildren().get(3)).setSelected(((EventTreeItem) getTreeItem()).important);
((Label) hBox.getChildren().get(0)).setText(eventTreeItem.noNode.getEntryNumber() + " " + eventTreeItem.noNode.getClass().getName().split("\\.")[3]);
((Label) hBox.getChildren().get(1)).setText(eventTreeItem.noNode.getDate().toString());
}else if (getTreeView().getTreeItemLevel(getTreeItem())==2){
setGraphic(this.hBoxLeaf);
}
} else {
setGraphic(null);
}
}
}
NodeTreeView
public class NodeTreeView implements ChartView{
private FilteredListModel filteredListModel;
TreeItem<String> root;
AnchorPane parent;
TreeView treeView;
public NodeTreeView(FilteredListModel filteredListModel, TabPane tabPane) throws IOException {
this.filteredListModel = filteredListModel;
parent = (AnchorPane) FXMLLoader.load(getClass().getResource("/Views/TryTreeViewInAnchorPane.fxml"));
parent.setVisible(true);
generateTree();
}
private void generateTree() {
this.root = new EventTreeItem();
root.setExpanded(true);
filteredListModel.makeEventNodeArrays().forEach(node->{
EventTreeItem item = new EventTreeItem((EventNoNode) node);
EventTreeItem item2 = new EventTreeItem();
root.getChildren().add(item);
item.getChildren().add(item2);
});
treeView = (TreeView) parent.getChildren().get(0);
treeView.setRoot(root);
treeView.setShowRoot(false);
treeView.setEditable(true);
treeView.setCellFactory(new Callback<TreeView<String>, TreeCell<String>>() {
#Override
public TreeCell<String> call(TreeView<String> param) {
return new CustomTreeCellFactory();
}
});
}
}
You can add a listener to checkbox's selectedProperty in your CustomTreeCellFactory constructor (which is not a factory, btw; you should call it CustomTreeCell instead):
public CustomTreeCellFactory() {
// ...
CheckBox checkbox = ...;
checkbox.selectedProperty().addListener((obs, wasSelected, isSelected) -> {
((EventTreeItem) getTreeItem()).important = isSelected;
});
}
Btw, it is probably a better idea to make the "important" flag be part of the item, i.e. instead of TreeView<String>, you would have TreeView<MyItem> where MyItem is
class MyItem {
String item;
boolean important;
MyItem(String item, boolean important) {
this.item = item;
this.important = important;
}
}
Related
I have a RecyclerView list of CardViews. Each CardView has a CheckBox that the user can select/de-select. The initial selection launches a Contextual Action Bar. An ArrayList of Integers is used to hold the checkbox state (selected or un-selected). Scrolling and the checkbox views appear to be working correctly. However, when I click a checkbox to de-select it, it remains checked and another checkbox on a different CardView is de-selected? What am I missing here?
Please note that I do not want to set up a ClickListener in onBindViewHolder.
MainActivity.java
public class MainActivity extends AppCompatActivity implements
RecyclerItemClickListener {
private ArrayList<ListItem> allList;
boolean isMultiSelect = false; // for the Contextual Action Bar status
private ActionMode mActionMode;
ArrayList<ListItem> multiselect_list = new ArrayList<>();
private ArrayList<Integer> checkedListItems = new ArrayList<>();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
...
// method from the Adapter, the ItemHolder's onClick()
public void onCheckBoxClick(View view, int position) {
if (!isMultiSelect) {
multiselect_list = new ArrayList<>();
isMultiSelect = true;
if (mActionMode == null) {
mActionMode = startSupportActionMode(actionModeCallback);
}
}
multi_select(position);
}
public void multi_select(int position) {
if (mActionMode != null) {
// If a CardView with a CheckBox already selected is clicked on, then the
// Checkbox is unselected, the position is removed from the multiselect_list
// and the size of the list is decremented by +1.
if (multiselect_list.contains(allList.get(position))) {
multiselect_list.remove(allList.get(position));
}
else {
// If an empty CheckBox on a CardView is clicked on, then the position is added to the
// multiselect_list and the size of the list is incremented by +1.
multiselect_list.add(allList.get(position));
}
if (multiselect_list.size() == 1) {
mActionMode.setTitle("1 selected");
}
else if (multiselect_list.size() >= 2) {
mActionMode.setTitle(multiselect_list.size() + " selected");
}
else if (multiselect_list.size() == 0) {
mActionMode.finish();
}
refreshAdapter();
}
}
public void refreshAdapter() {
adapter.selectedItemsList = multiselect_list;
adapter.mListItems = allList;
adapter.notifyDataSetChanged();
}
private ActionMode.Callback actionModeCallback = new ActionMode.Callback() {
Menu context_menu;
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.menu_action_mode, menu);
context_menu = menu;
return true;
}
...
}
Adapter.java
public class MyRecylerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public ArrayList<ListItem> mListItems;
private Context mContext;
private RecyclerItemClickListener recyclerItemClickListener;
public ArrayList<ListItem> selectedItemsList = new ArrayList<>();
public MyRecylerAdapter(Context context, ArrayList<ListItem> listItems, ArrayList<ListItem> selectedList) {
this.mContext = context;
this.mListItems = listItems;
this.selectedItemsList = selectedList;
}
private class ItemHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private CheckBox chkSelected;
private ItemHolder(final View itemView) {
super(itemView);
chkSelected = (CheckBox) itemView.findViewById(R.id.chkSelected);
chkSelected.setOnClickListener(this);
}
public void onClick(View v) {
int adapterPos = getAdapterPosition();
// send data to MainActivity() for starting CAB.
if (recyclerItemClickListener !=null) {
recyclerItemClickListener.onCheckBoxClick(v, adapterPos);
}
if (((CheckBox)v).isChecked()) {
checkedListItems.add(adapterPos);
}
else {
checkedListItems.remove(adapterPos);
}
}
void bind(int position) {
if (checkedListItems.contains(position)) {
chkSelected.setChecked(true);
}
else {
chkSelected.setChecked(false);
}
}
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_contact_item, parent, false);
final ItemHolder itemHolder = new ItemHolder(view);
...
return itemHolder;
}
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
final ListItem listItem = mListItems.get(position);
final ItemHolder itemHolder = (ItemHolder) holder;
itemHolder.bind(position);
...
}
In Adpater declare an ArrayList of integers
ArrayList<Integer> checkedItems = new ArrayList();
And in bind function
void bind(int position) {
if (checkedItems.contains(position)) {
chkSelected.setChecked(true);
}
else {
chkSelected.setChecked(false);
}
}
In OnBindviewholder add below code
CompoundButton.OnCheckedChangeListener onCheckedChangeListener = new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
int adapterPos = getAdapterPosition();
if(isChecked) {
checkedItems.add(Integer.valueOf(adapterPos));
}else {
checkedItems.remove(Integer.valueOf(adapterPos));
}
}
}
I have 1 issue in my project.
I'd like to have a tableColum built with comboBox, and for this i use:
tableColumn.setCellFactory(ComboBoxTableCell.forTableColumn(cbValues));
it works but like DOC says:
By default, the ComboBoxTableCell is rendered as a Label when not being edited, and as a ComboBox when in editing mode.
but i want to see the comboBox every time, so i build this code
tableColumn.setCellFactory(new Callback<TableColumn<Ambientale, Integer>, TableCell<Ambientale, Integer>>() {
#Override
public TableCell<Ambientale, Integer> call(TableColumn<Ambientale, Integer> param) {
return new ComboBoxCell(cbValues);
}
});
and my ComboBoxCell is:
class ComboBoxCell extends TableCell<Ambientale, Integer> implements Callback<Object, Object>{
private ComboBox combo;
public ComboBoxCell() {
combo = new ComboBox();
}
public ComboBoxCell(ObservableList items) {
combo = new ComboBox();
combo.setItems(items);
combo.setOnAction(new EventHandler() {
#Override
public void handle(Event event) {
System.out.println(" it's works");
commitEdit((Integer)combo.getSelectionModel().getSelectedItem());
}
});
}
#Override
public void updateItem(Integer item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
combo.getSelectionModel().select(item);
setGraphic(combo);
setContentDisplay(ContentDisplay.CENTER);
}
}
#Override
public Object call(Object param) {
return new ComboBoxCell();
}
}
the issue is here!
class ComboBoxCell extends TableCell<Ambientale, Integer> implements Callback<Object, Object>{
private ComboBox combo;
public ComboBoxCell() {
combo = new ComboBox();
}
public ComboBoxCell(ObservableList items) {
combo = new ComboBox();
combo.setItems(items);
combo.setOnAction(new EventHandler() {
#Override
public void handle(Event event) {
System.out.println(" it's works");
commitEdit((Integer)combo.getSelectionModel().getSelectedItem());
}
});
}
#Override
public void updateItem(Integer item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
combo.getSelectionModel().select(item);
setGraphic(combo);
setContentDisplay(ContentDisplay.CENTER);
}
}
#Override
public Object call(Object param) {
return new ComboBoxCell();
}
}
commitEdit(...) doesn't call:
tableColumn.setOnEditCommit(new EventHandler<TableColumn.CellEditEvent<Ambientale, Integer>>() {
#Override
public void handle(TableColumn.CellEditEvent<Ambientale, Integer> t) { //aggiornare database cella singola
System.out.println("not called");
//other stuffs
}
});
Can you help me please.
It works, i don't know why but it works.
i've added this on my ComboBoxCell
combo.focusedProperty().addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
if (newValue) {
getTableView().edit(getIndex(), getTableColumn());
} else {
commitEdit((Integer)combo.getSelectionModel().getSelectedItem());
}
}
});
i need help about settings the combobox buttonCell.
I use a combobox that show data from an observable list that contains data from a table with two columns, "Step" and "NextStep" (NextStep contains one item inserted in column Step); what i need to do is to show the combobox listcell with the list of "Step" and the buttoncell with the relative "NextStep". Now, i can see the listcell correctly but my buttoncell is always empty.
The code:
// SET THE VALUE STEP TO THE LISTCELL
comboStatoSuccessivo.setCellFactory(new Callback<ListView<StatoEsiti>, ListCell<StatoEsiti>>() {
#Override public ListCell<StatoEsiti> call(ListView<StatoEsiti> p) {
return new ListCell<StatoEsiti>() {
#Override
protected void updateItem(StatoEsiti t, boolean bln) {
super.updateItem(t, bln);
if(t != null){
setText(t.statoProperty().getValue());
System.out.println("SET PROPERTY " + t.statoProperty().getValue());
} else {
setText(null);
}
}
};
}
});
// SET THE VALUE NEXTSTEP TO THE BUTTONCELL
comboStatoSuccessivo.setButtonCell(new ListCell<StatoEsiti>() {
#Override
protected void updateItem(StatoEsiti t, boolean bln) {
super.updateItem(t, bln);
if (t != null) { <<<<<<<<<<<<<<-------------ALWAYS NULL----WHY??????
setText(t.statoSuccessivoProperty().getValue());
System.out.println("SET PROPERTY BUTTONCELL " + t.statoSuccessivoProperty().getValue());
} else {
setText(null);
System.out.println("SET PROPERTY BUTTONCELL NULL");
}
}
});
Thanks in advance.
I have looked into your use case with the following demo SSCCE code.
It is working as expected, like as when the item is selected from the combobox's dropmenu the buttoncell is updated with related "nextStep":
public class ComboDemo extends Application {
#Override
public void start(Stage primaryStage) {
List<Person> list = new ArrayList<Person>();
list.add(new Person("step 1212", 12));
list.add(new Person("step 4545", 45));
list.add(new Person("step 5656", 56));
list.add(new Person("step 9090", 90));
ComboBox<Person> comboBox = new ComboBox<>(FXCollections.observableList(list));
comboBox.setCellFactory(new Callback<ListView<Person>, ListCell<Person>>() {
#Override
public ListCell<Person> call(ListView<Person> p) {
return new ListCell<Person>() {
#Override
protected void updateItem(Person t, boolean bln) {
super.updateItem(t, bln);
if (t != null) {
setText(t.getStepProperty().getValue());
System.out.println("SET PROPERTY " + t.getStepProperty().getValue());
} else {
setText(null);
}
}
};
}
});
// SET THE VALUE NEXTSTEP TO THE BUTTONCELL
comboBox.setButtonCell(new ListCell<Person>() {
#Override
protected void updateItem(Person t, boolean bln) {
super.updateItem(t, bln);
if (t != null) {
setText(t.getNextStepProperty().getValue().toString());
System.out.println("SET PROPERTY BUTTONCELL " + t.getNextStepProperty().getValue());
} else {
setText(null);
System.out.println("SET PROPERTY BUTTONCELL NULL");
}
}
});
StackPane root = new StackPane();
root.getChildren().add(comboBox);
Scene scene = new Scene(root, 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
}
public static class Person {
private StringProperty stepProperty = new SimpleStringProperty();
private IntegerProperty nextStepProperty = new SimpleIntegerProperty();
public Person(String step, Integer nextStep) {
this.stepProperty.setValue(step);
this.nextStepProperty.setValue(nextStep);
}
public StringProperty getStepProperty() {
return stepProperty;
}
public void setStepProperty(StringProperty stepProperty) {
this.stepProperty = stepProperty;
}
public IntegerProperty getNextStepProperty() {
return nextStepProperty;
}
public void setNextStepProperty(IntegerProperty nextStepProperty) {
this.nextStepProperty = nextStepProperty;
}
}
public static void main(String[] args) {
launch(args);
}
}
Compare it with yours.
I have a combobox which shows list of User objects. I have coded a custom cell factory for the combobox:
#FXML ComboBox<User> cmbUserIds;
cmbUserIds.setCellFactory(new Callback<ListView<User>,ListCell<User>>(){
#Override
public ListCell<User> call(ListView<User> l){
return new ListCell<User>(){
#Override
protected void updateItem(Useritem, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setGraphic(null);
} else {
setText(item.getId()+" "+item.getName());
}
}
} ;
}
});
ListView is showing a string(id+name), but when I select an item from listview, Combobox is showing toString() method return value i.e address of object.
I can't override toString() method, because the User domain object should be same as the one at server.
How to display id in combobox? Please suggest
EDIT1
I tried below code. Now combo box shows id when I select a value from the listview.
cmbUserIds.setConverter(new StringConverter<User>() {
#Override
public String toString(User user) {
if (user== null){
return null;
} else {
return user.getId();
}
}
#Override
public User fromString(String id) {
return null;
}
});
The selected value in combo box is cleared when control focus is lost. How to fix this?
EDIT2:
#FXML AnchorPane root;
#FXML ComboBox<UserDTO> cmbUsers;
List<UserDTO> users;
public class GateInController implements Initializable {
#Override
public void initialize(URL location, ResourceBundle resources) {
users = UserService.getListOfUsers();
cmbUsers.setItems(FXCollections.observableList(users));
cmbUsers.getSelectionModel().selectFirst();
// list of values showed in combo box drop down
cmbUsers.setCellFactory(new Callback<ListView<UserDTO>,ListCell<UserDTO>>(){
#Override
public ListCell<UserDTO> call(ListView<UserDTO> l){
return new ListCell<UserDTO>(){
#Override
protected void updateItem(UserDTO item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setGraphic(null);
} else {
setText(item.getUserId()+" "+item.getUserNm());
}
}
} ;
}
});
//selected value showed in combo box
cmbUsers.setConverter(new StringConverter<UserDTO>() {
#Override
public String toString(UserDTO user) {
if (user == null){
return null;
} else {
return user.getUserId();
}
}
#Override
public UserDTO fromString(String userId) {
return null;
}
});
}
}
Just create and set a CallBack like follows:
#FXML ComboBox<User> cmbUserIds;
Callback<ListView<User>, ListCell<User>> cellFactory = new Callback<ListView<User>, ListCell<User>>() {
#Override
public ListCell<User> call(ListView<User> l) {
return new ListCell<User>() {
#Override
protected void updateItem(User item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setGraphic(null);
} else {
setText(item.getId() + " " + item.getName());
}
}
} ;
}
}
// Just set the button cell here:
cmbUserIds.setButtonCell(cellFactory.call(null));
cmbUserIds.setCellFactory(cellFactory);
You need to provide a functional fromString() Method within the Converter!
I had the same problem as you have and as I implemented the fromString() with working code, the ComboBox behaves as expected.
This class provides a few of my objects, for dev-test purposes:
public class DevCatProvider {
public static final CategoryObject c1;
public static final CategoryObject c2;
public static final CategoryObject c3;
static {
// Init objects
}
public static CategoryObject getCatForName(final String name) {
switch (name) {
case "Kategorie 1":
return c1;
case "Cat 2":
return c2;
case "Steuer":
return c3;
default:
return c1;
}
}
}
The converter object:
public class CategoryChooserConverter<T> extends StringConverter<CategoryObject> {
#Override
public CategoryObject fromString(final String catName) {
//This is the important code!
return Dev_CatProvider.getCatForName(catName);
}
#Override
public String toString(final CategoryObject categoryObject) {
if (categoryObject == null) {
return null;
}
return categoryObject.getName();
}
}
Can someone show me how to disable some item of my combobox (With FXML or Java code)? here is my ComboBox:
<ComboBox fx:id="cBox">
<items>
<FXCollections fx:factory="observableArrayList">
<String fx:value="Easy" />
<String fx:value="Normal" />
<String fx:value="Hard" />
</FXCollections>
</items>
</ComboBox>
Thanks!
i didn't found any methods that can inactive ComboBox items. You can try this work around , below code is to display sublist of items dynamically(use this idea to solve your problem).
private final ObservableList<String> allOptions =
FXCollections.observableArrayList("Easy","Normal","Hard");
// method which returns sublist we need
private ObservableList<String> getSubList(int start,int end) {
final ObservableList<String> toBeDisplayedList = FXCollections
.<String> observableArrayList();
toBeDisplayedList.addAll(allOptions.subList(start, end));
return toBeDisplayedList;
}
// now main logic
if(displayAll) {
comboBox.setItems(allOptions);
}
if(display only easy and normal) {
comboBox.setItems(getSublist(0,2));
} ...
I was trying to achieve this and I came up with a custom ComboBox that disables the items I don't want the user to select. Below code shows the custom ComboBox class and how to use it.
public class CustomComboBox<T> extends ComboBox<T> {
private ArrayList<T> disabledItems = new ArrayList<T>();
public CustomComboBox() {
super();
setup();
}
public CustomComboBox(ObservableList<T> list) {
super(list);
setup();
}
private void setup() {
SingleSelectionModel<T> model = new SingleSelectionModel<T>() {
#Override
public void select(T item) {
if (disabledItems.contains(item)) {
return;
}
super.select(item);
}
#Override
public void select(int index) {
T item = getItems().get(index);
if (disabledItems.contains(item)) {
return;
}
super.select(index);
}
#Override
protected int getItemCount() {
return getItems().size();
}
#Override
protected T getModelItem(int index) {
return getItems().get(index);
}
};
Callback<ListView<T>, ListCell<T>> callback = new Callback<ListView<T>, ListCell<T>>() {
#Override
public ListCell<T> call(ListView<T> param) {
final ListCell<T> cell = new ListCell<T>() {
#Override
public void updateItem(T item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
setText(item.toString());
if (disabledItems.contains(item)) {
setTextFill(Color.LIGHTGRAY);
setDisable(true);
}
} else {
setText(null);
}
}
};
return cell;
}
};
setSelectionModel(model);
setCellFactory(callback);
}
public void setDisabledItems(T... items) {
for (int i = 0; i < items.length; i++) {
disabledItems.add(items[i]);
}
}
}
Then add the items to disable to the ComboBox:
#FXML private CustomComboBox<String> customComboBox;
...
customComboBox.setDisabledItems("Item 2", "Item 3");
And change the class in the fxml file:
<views.custom.CustomComboBox ... />
I had the same issue and I think that the best solution to this problem is to use the
setCellFactory(Callback,ListCell> value) method of ComboBox:
cBox.setCellFactory(new Callback<ListView<String>, ListCell<String>>() {
#Override
public ListCell<String> call(ListView<String> param)
{
return new ListCell<String>() {
#Override
protected void updateItem(String item, boolean empty)
{
super.updateItem(item, empty);
if (item != null || !empty)
{
this.setText(item);
this.setDisable(true); //or false
}
}
};
}
});
and if you want a custon ButtonCel you need to use the setButtonCell(ListCell value) Method:
cBox.setButtonCell(new ListCell<String>() {
#Override
protected void updateItem(Stringitem, boolean empty)
{
super.updateItem(item, empty);
if (item != null || !empty)
{
this.setText(item);
this.setDisable(true); //or false
}
}
});
comboBox.setItems(FXCollections.observableArrayList(EnumValues.values()));
comboTipoOperacoes.getItems().remove(4); // remove the item 4 of Enums.