right click menu option in the tree root node - treeview

I want right click menu option in the tree root node(JavaFX). Could any one help me on this.
TreeItem<String> root = new TreeItem<>(""+selectedDirectory);
root.setExpanded(true);
locationTreeView.setRoot(root);
root.getChildren().addAll(
new TreeItem<>("Item 1"),
new TreeItem<>("Item 2"),
new TreeItem<>("Item 3")
);

You can perform the desired behaviour in two steps:
Defining a custom TreeCell factory on your TreeView;
Attaching a context menu on the TreeCell of the root tree item.
The following code defines the custom TreeCell factory:
// defines a custom tree cell factory for the tree view
tree.setCellFactory(new Callback<TreeView<String>, TreeCell<String>>() {
#Override
public TreeCell<String> call(TreeView<String> arg0) {
// custom tree cell that defines a context menu for the root tree item
return new MyTreeCell();
}
});
And, here is the implementation of a custom tree cell that attaches a context menu for the root tree item:
class MyTreeCell extends TextFieldTreeCell<String> {
private ContextMenu rootContextMenu;
public MyTreeCell() {
// instantiate the root context menu
rootContextMenu =
ContextMenuBuilder.create()
.items(
MenuItemBuilder.create()
.text("Menu Item")
.onAction(
new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent arg0) {
System.out.println("Menu Item Clicked!");
}
}
)
.build()
)
.build();
}
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
// if the item is not empty and is a root...
if (!empty && getTreeItem().getParent() == null) {
setContextMenu(rootContextMenu);
}
}
}
The following example ilustrates the use of both, cell factory and custom cell, together:
public class TreeViewWithContextMenuOnRoot extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Tree with context menu on root");
TreeItem<String> rootItem = new TreeItem<String> ("Tree root");
rootItem.setExpanded(true);
for (int i = 1; i < 3; i++) {
TreeItem<String> item = new TreeItem<String> ("item" + i);
rootItem.getChildren().add(item);
}
final TreeView<String> tree = new TreeView<String> ();
tree.setRoot(rootItem);
// defines a custom tree cell factory for the tree view
tree.setCellFactory(new Callback<TreeView<String>, TreeCell<String>>() {
#Override
public TreeCell<String> call(TreeView<String> arg0) {
// custom tree cell that defines a context menu for the root tree item
return new MyTreeCell();
}
});
StackPane root = new StackPane();
root.getChildren().add(tree);
primaryStage.setScene(new Scene(root, 200, 100));
primaryStage.show();
}
private static class MyTreeCell extends TextFieldTreeCell<String> {
private ContextMenu rootContextMenu;
public MyTreeCell() {
// instantiate the root context menu
rootContextMenu =
ContextMenuBuilder.create()
.items(
MenuItemBuilder.create()
.text("Menu Item")
.onAction(
new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent arg0) {
System.out.println("Menu Item Clicked!");
}
}
)
.build()
)
.build();
}
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
// if the item is not empty and is a root...
if (!empty && getTreeItem().getParent() == null) {
setContextMenu(rootContextMenu);
}
}
}
}
You can take a look at the TreeView tutorial to see other uses and examples related to this JavaFX control.

Related

Best approach to use DiffUtil with LIveData + Room Database?

I am using Room Database with LiveData , but my Local Database is updating too fast as per our requirement and at the same time i have to reload my recycler view .instead of calling notifyDataSetChanged() to adapter , i am trying to use DiffUtil , but is crashing or not reloading properly , this is uncertain .
i am following this tutorial :
Tutorials Link here
MyAdapter :
public class SwitchGridAdapter extends RecyclerView.Adapter<SwitchGridAdapter.ViewHolder> {
private List<Object> allItemsList;
private LayoutInflater mInflater;
private OnItemClickListener mClickListener;
private Context context;
private Queue<List<Object>> pendingUpdates =
new ArrayDeque<>();
// data is passed into the constructor
public SwitchGridAdapter(Context context,List<Appliance> applianceList,List<ZmoteRemote> zmoteRemoteList) {
this.mInflater = LayoutInflater.from(context);
this.context = context;
allItemsList = new ArrayList<>();
if (applianceList!=null) allItemsList.addAll(applianceList);
if (zmoteRemoteList!=null)allItemsList.addAll(zmoteRemoteList);
}
// inflates the cell layout from xml when needed
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R .layout.switch_grid_item, parent, false);
return new ViewHolder(view);
}
// binds the data to the textview in each cell
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
// Doing some update with UI Elements
}
// total number of cells
#Override
public int getItemCount() {
return allItemsList.size();
}
// stores and recycles views as they are scrolled off screen
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener,View.OnLongClickListener {
TextView myTextView;
ImageView imgSwitch;
ViewHolder(View itemView) {
super(itemView);
myTextView = (TextView) itemView.findViewById(R.id.txtSwitchName);
imgSwitch = (ImageView) itemView.findViewById(R.id.imgSwitchStatus);
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
}
#Override
public void onClick(View view) {
// handling click
}
#Override
public boolean onLongClick(View view) {
return true;
}
// convenience method for getting data at click position
Object getItem(int id) {
return allItemsList.get(id);
}
// allows clicks events to be caught
public void setClickListener(OnItemClickListener itemClickListener) {
this.mClickListener = itemClickListener;
}
// parent activity will implement this method to respond to click events
public interface OnItemClickListener {
void onItemClick(View view, int position);
void onItemLongPressListner(View view, int position);
}
// ✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅
// From This Line Reloading with Diff Util is Done .
//✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅
public void setApplianceList( List<Appliance> applianceList,List<ZmoteRemote> zmoteRemoteList)
{
if (allItemsList == null)
allItemsList = new ArrayList<>();
List<Object> newAppliances = new ArrayList<>();
if (applianceList!=null) newAppliances.addAll(applianceList);
updateItems(newAppliances);
}
// when new data becomes available
public void updateItems(final List<Object> newItems) {
pendingUpdates.add(newItems);
if (pendingUpdates.size() > 1) {
return;
}
updateItemsInternal(newItems);
}
// This method does the heavy lifting of
// pushing the work to the background thread
void updateItemsInternal(final List<Object> newItems) {
final List<Object> oldItems = new ArrayList<>(this.allItemsList);
final Handler handler = new Handler();
new Thread(new Runnable() {
#Override
public void run() {
final DiffUtil.DiffResult diffResult =
DiffUtil.calculateDiff(new DiffUtilHelper(oldItems, newItems));
handler.post(new Runnable() {
#Override
public void run() {
applyDiffResult(newItems, diffResult);
}
});
}
}).start();
}
// This method is called when the background work is done
protected void applyDiffResult(List<Object> newItems,
DiffUtil.DiffResult diffResult) {
dispatchUpdates(newItems, diffResult);
}
// This method does the work of actually updating
// the backing data and notifying the adapter
protected void dispatchUpdates(List<Object> newItems,
DiffUtil.DiffResult diffResult) {
// ❌❌❌❌❌❌ Next Line is Crashing the app ❌❌❌❌❌
pendingUpdates.remove();
dispatchUpdates(newItems, diffResult);
if (pendingUpdates.size() > 0) {
updateItemsInternal(pendingUpdates.peek());
}
}
}
Observing LiveData
public void setUpAppliancesListLiveData()
{
if (applianceObserver!=null)
{
applianceObserver = null;
}
Log.e("Appliance Fetch","RoomName:"+this.roomName);
applianceObserver = new Observer<List<Appliance>>() {
#Override
public void onChanged(#Nullable List<Appliance> applianceEntities) {
// Log.e("Appliance Result","Appliance List \n\n:"+applianceEntities.toString());
new Thread(new Runnable() {
#Override
public void run() {
List<Appliance> applianceListTemp = applianceEntities;
zmoteRemoteList = new ArrayList<>(); //appDelegate.getDatabase().zmoteRemoteDao().getRemoteList(roomName);
// Sort according to name
Collections.sort(applianceListTemp, new Comparator<Appliance>() {
#Override
public int compare(Appliance item, Appliance t1) {
String s1 = item.getSwitchName();
String s2 = t1.getSwitchName();
return s1.compareToIgnoreCase(s2);
}
});
if(getActivity()!=null) {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
applianceList = applianceListTemp;
mRecyclerView.getRecycledViewPool().clear();
adapter.setApplianceList(applianceList,zmoteRemoteList);
}
});
}
}
}).start();
}
};
appDelegate.getDatabase().applianceDao().getApplinaceListByRoomName(this.roomName).observe(this, applianceObserver);
}

Detect if object is over pane during transition

I'm trying to detect if an elements that I move using PathTransition are entering the space of Pane.
This is my code:
public class Demo extends Application {
private void init(Stage primaryStage) {
Group root = new Group();
primaryStage.setResizable(false);
primaryStage.setScene(new Scene(root, 800, 600));
Rectangle rect = new Rectangle(5, 5, Color.BLACK);
root.getChildren().add(rect);
Path path = new Path();
path.getElements().add (new MoveTo (0, 350));
path.getElements().add (new LineTo(400, 350));
PathTransition pathTransition = new PathTransition();
pathTransition.setDuration(Duration.millis(5000));
pathTransition.setPath(path);
pathTransition.setNode(rect);
pathTransition.setAutoReverse(false);
AnchorPane pane = new AnchorPane();
pane.setPrefSize(250, 200);
pane.relocate(300, 300);
pane.setStyle("-fx-border-color: #000000;");
root.getChildren().add(pane);
pathTransition.play();
}
#Override
public void start(Stage primaryStage) throws Exception {
init(primaryStage);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Is there a way to bind an event to the pane object and when the rect goes over, it will detect it?
Try
BooleanBinding intersects = new BooleanBinding() {
{
this.bind(pane.boundsInParentProperty(), rect.boundsInParentProperty());
}
#Override
protected boolean computeValue() {
return pane.getBoundsInParent().intersects(rect.getBoundsInParent());
}
};
intersects.addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> observable,
Boolean oldValue, Boolean newValue) {
if (newValue) {
System.out.println("Intersecting");
} else {
System.out.println("Not intersecting");
}
}
});
If you are still using old (pre-Java 8) versions of Java, you will need to declare pane and rect as final.

JavaFX: Radio Button + CheckBox TreeView

in reference to my earlier question here, I did the code below.
I am trying to make a treeview which shows a radio button for leafs, and checkboxes for non-leaf items. The code below does not show anything. I am sure I am doing something extremely wrong somewhere (or everywhere). Any help is much appreciated.
Thanks
public class RadioCheckBoxTreeView extends TreeView {
public RadioCheckBoxTreeView() {
setCellFactory(new Callback<TreeView<Object>, TreeCell<Object>>() {
#Override
public TreeCell<Object> call(TreeView<Object> param) {
return new RadioCheckBoxCellImpl();
}
});
}
private static class RadioCheckBoxCellImpl extends TreeCell<Object> {
private final CheckBox check = new CheckBox();
private final RadioButton radio = new RadioButton();
private Property<Boolean> prevRadioProp;
public RadioCheckBoxCellImpl() {
}
{
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
#Override
public void updateItem(Object item, boolean empty) {
if (prevRadioProp != null) {
radio.selectedProperty().unbindBidirectional(prevRadioProp);
prevRadioProp = null;
}
check.selectedProperty().unbind();
if (!empty && item != null) {
Property<Boolean> selectedProp = prevRadioProp;
if (getTreeItem().isLeaf()) // display radio button
{
radio.setText("radio");
radio.selectedProperty().bindBidirectional(selectedProp);
prevRadioProp = selectedProp;
setGraphic(radio);
} else // display checkbox
{
check.setText("check");
check.selectedProperty().bind(selectedProp);
setGraphic(check);
}
} else {
setGraphic(null);
setText(null);
}
}
}
this is what my start method looks like
public void start(Stage primaryStage) {
AnchorPane pane = new AnchorPane();
Scene scene = new Scene(pane);
MyTreeView tv = new MyTreeView();
tv.setRoot(new TreeItem());
TreeItem child1 = new TreeItem();
child1.setValue("1");
TreeItem child2 = new TreeItem();
child2.setValue("2");
TreeItem child3 = new TreeItem();
child3.setValue("3");
tv.getRoot().getChildren().add(child1);
tv.getRoot().getChildren().add(child2);
child2.getChildren().add(child3);
pane.getChildren().add(tv);
primaryStage.setScene(scene);
primaryStage.show();
}
Ok I managed to get this far. I also changed the graphic to change based on its type.
#Override
public void updateItem(Object item, boolean empty) {
if (prevRadioProp != null) {
radio.selectedProperty().unbindBidirectional(prevRadioProp);
prevRadioProp.setValue(true);
}
check.selectedProperty().unbind();
if (!empty && item != null) {
SimpleBooleanProperty selectedProp = prevRadioProp;
if (item.getClass().getName().contains("Option")) // display radio button
{
radio.setText("Option");
radio.selectedProperty().bindBidirectional(selectedProp);
prevRadioProp = selectedProp;
setGraphic(radio);
} else // display checkbox
{
check.setText("Feature");
check.selectedProperty().bind(selectedProp);
setGraphic(check);
}
} else {
setGraphic(null);
setText(null);
}
super.updateItem(item, empty);
}
How do I set the selection logic? Based on the code it gives a "CheckBox.selected : A bound value cannot be set." error.

Using one event handler for multiple actions

I was doing some homework today and I've accomplished all of the goals of the assignment, which I'm sure will get me full points.
In an earlier class, however, we used the same Event Handler for more than one action (in this example, you either type a color in the text field, or click a button to change the background color of the box).
I can't figure out how I would do that in this case... do I have to choose a Type in the constructor? If the first parameter could be a button or a textfield then I think that would help.
I'm just trying to figure out how to apply DRY (Don't Repeat Yourself), where ever I can.
public class ColorChooserApplication extends Application
{
#Override
public void start(Stage stage)
{
// Create all UI components
VBox backgroundBox = new VBox(10);
backgroundBox.setPadding(new Insets(10));
HBox topBox = new HBox(10);
HBox bottomBox = new HBox(10);
TextField colorPrompt = new TextField();
colorPrompt.setOnAction(new ColorHandler(colorPrompt, backgroundBox));
Button redButton = new Button("Red");
redButton.setOnAction(new ButtonHandler(redButton, backgroundBox));
Button whiteButton = new Button("White");
whiteButton.setOnAction(new ButtonHandler(whiteButton, backgroundBox));
Button blueButton = new Button("Blue");
blueButton.setOnAction(new ButtonHandler(blueButton, backgroundBox));
// Assemble
topBox.getChildren().add(colorPrompt);
bottomBox.getChildren().addAll(redButton, whiteButton, blueButton);
backgroundBox.getChildren().addAll(topBox, bottomBox);
backgroundBox.setAlignment(Pos.CENTER);
topBox.setAlignment(Pos.CENTER);
bottomBox.setAlignment(Pos.CENTER);
// Set scene and show
stage.setScene(new Scene(backgroundBox));
stage.show();
}
class ColorHandler implements EventHandler<ActionEvent>
{
TextField colorTf;
VBox bgVbox;
public ColorHandler(TextField colorTf, VBox bgVbox)
{
this.colorTf = colorTf;
this.bgVbox = bgVbox;
}
#Override
public void handle(ActionEvent event)
{
String color = colorTf.getText();
bgVbox.setStyle("-fx-background-color:" + color);
}
}
class ButtonHandler implements EventHandler<ActionEvent>
{
Button colorButton;
VBox bgVbox;
public ButtonHandler(Button colorButton, VBox bgVbox)
{
this.colorButton = colorButton;
this.bgVbox = bgVbox;
}
#Override
public void handle(ActionEvent event)
{
String color = colorButton.getText();
bgVbox.setStyle("-fx-background-color:" + color);
}
}
public static void main(String[] args)
{
launch(args);
}
}
If you're using Java 8, you can do
class ColorHandler implements EventHandler<ActionEvent> {
Supplier<String> colorSupplier ;
VBox bgVbox ;
public ColorHandler(Supplier<String> colorSupplier, VBox bgVbox) {
this.colorSupplier = colorSupplier ;
this.bgVbox = bgVbox ;
}
#Override
public void handle(ActionEvent event) {
String color = colorSupplier.get();
bgVbox.setStyle("-fx-background-color: "+color);
}
}
and then
colorPrompt.setOnAction(new ColorHandler(colorPrompt::getText, backgroundBox));
redButton.setOnAction(new ColorHandler(redButton::getText, backgroundBox));
Note that all you need to provide for the first parameter is some function that returns the correct string for use in the css. So you can do things like
whiteButton.setOnAction(new ColorHandler(() -> "#ffffff", backgroundBox));
blueButton.setOnAction(new ColorHandler(() -> "cornflowerblue", backgroundBox));
etc.

JavaFX TreeItem string not appearing

After hours of trying i finally somewhat managed to figure out how to hook a listener to TreeItems in a TreeView, it probably isn't at all the right way to do so but hey it works so far.
Although one thing isn't, that is the "label" or better said text in the TreeItems isn't showing up anymore.
Can anyone look at my code and tell me, if i'm either doing it completely wrong or why the text isn't showing up anymore?
Thanks in advance.
Code:
TreeView<String> tree = new TreeView<>();
TreeItem<String> treeRoot = new TreeItem<>(Login.name + " - " + Login.accountType);
treeRoot.getChildren().addAll(new TreeItem<>("Branches"),
new TreeItem<>("Planning"), new TreeItem<>("Courses"),
new TreeItem<>("Add new item"));
treeRoot.getChildren().get(1).getChildren().addAll(
new TreeItem<>("2014 - Q1"), new TreeItem<>("2014 - Q2"),
new TreeItem<>("2014 - Q3"), new TreeItem<>("2014 - Q4"));
treeRoot.getChildren().get(3).getChildren().addAll(
new TreeItem<>("Branch"), new TreeItem<>("Course"));
for(String str : loadBranchData()) {
treeRoot.getChildren().get(0).getChildren().add(
new TreeItem<>(str));
}
for(String str : loadCourseData()) {
treeRoot.getChildren().get(2).getChildren().add(
new TreeItem<>(str));
}
for(int c = 0; c <= 2; c++) {
treeRoot.getChildren().get(c).setExpanded(true);
}
treeRoot.setExpanded(true);
tree.setPrefWidth(PREFWIDTH);
tree.setRoot(treeRoot);
tree.setShowRoot(true);
tree.setCellFactory(new Callback<TreeView<String>,TreeCell<String>>(){
#Override
public TreeCell<String> call(TreeView<String> p) {
return new EpicTreeCell();
}
});
...
private final class EpicTreeCell extends TreeCell<String> {
#SuppressWarnings("unchecked")
super.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent evt) {
System.out.println("TEST?");
}
});
}
When the custom cell is defined, the setText() method should be called in its overridden updateItem() method.
private final class EpicTreeCell extends TreeCell<String> {
public EpicTreeCell() {
setOnMouseClicked (
new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent evt) {
System.out.println("TEST?");
}
}
);
}
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
} else {
setText(getItem() == null ? "" : getItem().toString());
}
setGraphic(null);
}
}
See the "Custom Java-fx cellfactory messes up the setCellValueFactory" for more information.

Resources