How to display rows into accordion - java

I have this JavaFX accordion which displays images:
public class Navigation {
private static final Image BLUE_FISH = new Image("/Blue-Fish-icon.png");
private static final Image RED_FISH = new Image("/Red-Fish-icon.png");
private static final Image YELLOW_FISH = new Image("/Yellow-Fish-icon.png");
private static final Image GREEN_FISH = new Image("/Green-Fish-icon.png");
public void initNavigation(Stage primaryStage, Group root, Scene scene) {
VBox stackedTitledPanes = createStackedTitledPanes();
ScrollPane scroll = makeScrollable(stackedTitledPanes);
scroll.getStyleClass().add("stacked-titled-panes-scroll-pane");
scroll.setPrefSize(395, 580);
scroll.setLayoutX(5);
scroll.setLayoutY(32);
//scene = new Scene(scroll);
root.getChildren().add(scroll);
}
private VBox createStackedTitledPanes() {
final VBox stackedTitledPanes = new VBox();
stackedTitledPanes.getChildren().setAll(
createTitledPane("Connections", GREEN_FISH),
createTitledPane("Tables", YELLOW_FISH),
createTitledPane("Description", RED_FISH),
createTitledPane("Blue Fish", BLUE_FISH));
((TitledPane) stackedTitledPanes.getChildren().get(0)).setExpanded(true);
stackedTitledPanes.getStyleClass().add("stacked-titled-panes");
return stackedTitledPanes;
}
public TitledPane createTitledPane(String title, Image... images) {
FlowPane content = new FlowPane();
for (Image image : images) {
ImageView imageView = new ImageView(image);
content.getChildren().add(imageView);
FlowPane.setMargin(imageView, new Insets(10));
}
content.setAlignment(Pos.TOP_CENTER);
TitledPane pane = new TitledPane(title, content);
pane.getStyleClass().add("stacked-titled-pane");
pane.setExpanded(false);
return pane;
}
private ScrollPane makeScrollable(final VBox node) {
final ScrollPane scroll = new ScrollPane();
scroll.setContent(node);
scroll.viewportBoundsProperty().addListener(new ChangeListener<Bounds>() {
#Override
public void changed(ObservableValue<? extends Bounds> ov, Bounds oldBounds, Bounds bounds) {
node.setPrefWidth(bounds.getWidth());
}
});
return scroll;
}
}
I'm interested is it possible to display rows of data where the images are placed. Something like this:
P.S case example. I have a java object which will be used as list:
public List<dataObj> list = new ArrayList<>();
public class dataObj {
private int connectionId;
private String conenctionname;
private String connectionDescription;
public dataObj() {
}
....................
}
When I insert some data into the Java Array list I want to display it into the accordion based on the above requirement.
P.S 2 In my case what is the proper way to insert text into FlowPane? I tested this:
public TitledPane createTitledPane(String title, Image... images) {
FlowPane content = new FlowPane();
for (Image image : images) {
ImageView imageView = new ImageView(image);
content.getChildren().add(imageView);
FlowPane.setMargin(imageView, new Insets(10));
}
content.setAlignment(Pos.TOP_CENTER);
content.setText("This part will be the first line.\n This part the second.");
TitledPane pane = new TitledPane(title, content);
pane.getStyleClass().add("stacked-titled-pane");
pane.setExpanded(false);
return pane;
}
I get error that inserting text using setText is not correct. What is the proper way?

If you use "\n" the output String will be separated into multiple lines of text.
For example:
component.setText("This part will be the first line.\n This part the second.");
From your update, assuming you have getters and setters:
component.setText(String.valueOf(dataObj.getConnectionId()) + "\n" + dataObj.getConnectionname() + "\n" + dataObj.getConnectionDescription());

You can simply use a ListView:
private void hello() {
ListView<Object> lv = new ListView<>();
// yourList is you List<Object> list
lv.itemsProperty().set(yourList);
lv.setCellFactory(new Callback<ListView<Object>, ListCell<Object>>() {
#Override
public ListCell<Object> call(ListView<Object> p) {
return new youCellFactory();
}
});
AnchorPane content = new AnchorPane();
content.getChildren().add(lv);
// add to TitelPane
TitledPane pane = new TitledPane(title, content);
}
static class youCellFactory extends ListCell<Object> {
#Override
public void updateItem(Object item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
setText(item.getConenctionname());
}
}
}
I have not tested this code but it should work.
Here is an nice Example too, but without object:
ListViewSample.java

Related

javafx cannot access button in custom listcell

The core of the problem is that I cannot refresh or change the content of a node of a scene (here TablesMain) from another class (here NamePriceCell).
I am building and application with a main StackPane (TableMainController extends StackPane) that contains other nodes, some of which are ListViews. In a specific ListView (say 'readitemslistview') I have created a custom ListCell (public class NamePriceCell extends ListCell) and this NamePriceCell listcell contains a button (plusbtn). When a user clicks on the plusbtn, an arraylist (say 'chosenitemslist') gets filled up with the item displayed in the particular cell and at the same time another listview in the stackpane (say 'ordereditemslist') should be triggered to display the content of the 'chosenitemslist' arraylist.
I haven't found a way to reference the plusbtn of the NamePriceCell from the main controller. Moreover this post
Get ListCell via ListView
Unfortunately right now there is no API to get List Cell by index or
to get All children's(listcells) for ListView.
has turned me away from such an attempt (I haven't been able to understand if the solution provided there is suitable for my needs, as I don't want a refresh of the same listview but from another in the same scene).
So the only way I have found to get a mouse click action from the plusbtn is with an EventHandler in the same class (NamePriceCell). And even though I can get an arraylist filled according to the clicks on the NamePriceCell buttons (the NamePriceCell calls a static method in another class with a static arraylist in it) and I can get the result in my orderedlistview by letting the user click on another button node of the TableMain StackPane, I cannot find a way to do that when the user clicks on the NamePriceCell button.
Among the things I tried is setting a static method in the TablesMainController that I can access it from the NamePriceCell EventHandler (but then I have to make the holder node of the ordereditemslist static, and even so, it hasn't worked),
writing a separate fxml for the VBox containing the ordereditemslist with a corresponding separate controller so that I can have a method there to create the ordereditemslist and set the cellFactory (but even though the fxml file displays correctly and calling the method from the EventHandler of NamePriceCell works - a System.out gets displayed - it won't affect anything on the screen not the ordereditemslist, not even a label I tested.
I am relatively a java newbie and even so more when it comes to javafx. Your help is greatly needed and appreciated.
The code of my last approach is below:
VboxList.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.layout.VBox?>
<VBox>
<Label text="Label" id="label1"/>
<Label text="Label" id="label2"/>
<Label text="sdfsdf" id="label3"/>
<ListView nodeOrientation="LEFT_TO_RIGHT" id="orderedlist" prefHeight="200.0" prefWidth="200.0" />
</VBox>
VboxListController.java
public class VboxListController extends VBox{
FXMLLoader fxmlLoader;
#FXML
private Label label1;
#FXML
private Label label2;
#FXML
private ListView<OrderItem> orderedlist;
public VboxListController() {
fxmlLoader = new FXMLLoader(getClass().getResource("fxml/VboxList.fxml"));
//fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
public void getorderedlist(ArrayList<OrderItem> chosenitems){
ObservableList<OrderItem> myObservableList = FXCollections.observableList(chosenitems);
this.getChildren().remove(orderedlist);
orderedlist = new ListView<>();
orderedlist.setItems(myObservableList);
orderedlist.setCellFactory(new Callback<ListView<OrderItem>, ListCell<OrderItem>>() {
#Override
public ListCell<OrderItem> call(ListView<OrderItem> p) {
ListCell<OrderItem> cell = new ListCell<OrderItem>() {
#Override
protected void updateItem(OrderItem dataobj, boolean bln) {
super.updateItem(dataobj, bln);
if (dataobj != null) {
setText(dataobj.read_item_name);
}
}
};
return cell;
}
});
this.getChildren().add(orderedlist);
orderedlist.setItems(null);
orderedlist.setItems(myObservableList);
label1 = null;
this.getChildren().remove(label1);
label1 = new Label();
label1.setText("oooops!");
System.out.println("sdf");
this.getChildren().add(label1);
}
}
NamePriceCell.java
public class NamePriceCell extends ListCell<ReadItemChoiceObj> {
int count=0;
#FXML
Label namelbl;
#FXML
Label pricelbl;
#FXML
Button plusbtn;
#FXML
Region spacer;
#FXML
HBox cellHbox;
FXMLLoader mLLoader;
ReadItemChoiceObj readitem;
ArrayList<ReadItemChoiceObj> chosenreaditems;
#Override
protected void updateItem(ReadItemChoiceObj readitem, boolean empty) {
super.updateItem(readitem, empty);
chosenreaditems = new ArrayList<>();
if(empty || readitem == null) {
setText(null);
setGraphic(null);
} else {
this.readitem = readitem;
if (mLLoader == null) {
mLLoader = new FXMLLoader(getClass().getResource("fxml/NamePriceCell.fxml"));
mLLoader.setController(this);
try {
mLLoader.load();
} catch (IOException e) {
e.printStackTrace();
}
}
namelbl.setText(readitem.getname());
namelbl.setMaxWidth(500);
pricelbl.setText(String.format("%.2f", readitem.getprice()));
pricelbl.setStyle("-fx-font: 8pt \"Arial\";");
pricelbl.setMaxWidth(40);
spacer.setMaxWidth(10);
spacer.setMinWidth(10);
plusbtn.setMaxWidth(20);
cellHbox.setHgrow(namelbl, Priority.ALWAYS);
cellHbox.setAlignment(Pos.BASELINE_LEFT);
setText(null);
setGraphic(cellHbox);
plusbtn.setOnMouseClicked(whattodohandler);
}
}
EventHandler<MouseEvent> whattodohandler = new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
ChosenItemsStat.getplusbtnclicked(readitem);
ChosenItemsStat chos = new ChosenItemsStat();
count+=1;
plusbtn.setText(String.valueOf(count));
new VboxListController().getorderedlist(chos.sendchosenlist());
}
};
}
and a part of TablesMain.java
#FXML
Label label1;
#FXML
BorderPane borderpane;
#FXML
Pane tablepane;
#FXML
ListView<DataObj> tabcatlist;
#FXML
VBox VboxList;
#FXML
VboxListController vboxListController;
/* #FXML
ListView<OrderItem> orderedlist;*/
#FXML
VBox leftVbox;
public TablesMain(Order order) {
this.order = order;
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("fxml/tablesmain.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
ObservableList<DataObj> myObservableList = FXCollections.observableList(gettable_categories());
tabcatlist.setItems(myObservableList);
tabcatlist.setCellFactory(new Callback<ListView<DataObj>, ListCell<DataObj>>() {
#Override
public ListCell<DataObj> call(ListView<DataObj> p) {
ListCell<DataObj> cell = new ListCell<DataObj>() {
#Override
protected void updateItem(DataObj dataobj, boolean bln) {
super.updateItem(dataobj, bln);
if (dataobj != null) {
setText(dataobj.getname());
}
}
};
return cell;
}
});
if (table_categoryID == 0) table_categoryID = tablecategories.get(0).getid();
gettables(table_categoryID);
}
private void make_readitemlist(int itemcategoryID) {
readitems = new ArrayList<>();
.... the readitems arraylist gets filled up...
ObservableList<ReadItemChoiceObj> myObservableList = FXCollections.observableList(readitems);
readitemlist.setItems(myObservableList);
readitemlist.setCellFactory(new Callback<ListView<ReadItemChoiceObj>,
ListCell<ReadItemChoiceObj>>() {
#Override
public ListCell<ReadItemChoiceObj> call(ListView<ReadItemChoiceObj> list) {
readitemlistcell = new NamePriceCell();
return readitemlistcell;
}
}
);
readitemlist.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
ReadItemChoiceObj dataobj = (ReadItemChoiceObj) readitemlist.getSelectionModel().getSelectedItem();
System.out.println(String.valueOf(dataobj.getid()));
// showorderedlist(new ChosenItemsStat().sendchosenlist());
}
});
System.out.println(readitemlist.cellFactoryProperty().getClass().toString());
}
...
}
Since it's been almost 5 months without another contribution, i would like to post my solution as an answer. It's not mine but inspired (or copied) by the post mentioned in my question (or another one, now I don't remember, please excuse my possible misplacement of credits).
More precisely I created a static StringProperty in TableMain file (the main Controller class). Every time the plusbtn (NamePriceCell class that extends ListCell) is clicked a random number turned to string is forced in the static StringProperty of the TableMain controller class. Inside this class the StringProperty has a ChangeListener added which in its turn triggers (from inside of the main controller now - that was the clue) the refreshing of the orderedlist (the listview that had to be refreshed with the added items).
NamePriceCell.java
public class NamePriceCell extends ListCell<ReadItemChoiceObj> {
#FXML
Label namelbl;
#FXML
Label pricelbl;
#FXML
Button plusbtn;
#FXML
Region spacer;
#FXML
HBox cellHbox;
FXMLLoader mLLoader;
ReadItemChoiceObj readitem;
#Override
protected void updateItem(ReadItemChoiceObj readitem, boolean empty) {
super.updateItem(readitem, empty);
if(empty || readitem == null) {
setText(null);
setGraphic(null);
} else {
this.readitem = readitem;
if (mLLoader == null) {
mLLoader = new FXMLLoader(getClass().getResource("fxml/NamePriceCell.fxml"));
mLLoader.setController(this);
try {
mLLoader.load();
} catch (IOException e) {
e.printStackTrace();
}
}
namelbl.setText(readitem.getname());
namelbl.setMaxWidth(500);
pricelbl.setText(String.format("%.2f", readitem.getprice()));
pricelbl.setStyle("-fx-font: 8pt \"Arial\";");
pricelbl.setMaxWidth(40);
spacer.setMaxWidth(10);
spacer.setMinWidth(10);
plusbtn.setMaxWidth(20);
cellHbox.setHgrow(namelbl, Priority.ALWAYS);
cellHbox.setAlignment(Pos.BASELINE_LEFT);
setText(null);
setGraphic(cellHbox);
plusbtn.setOnMouseClicked(whattodohandler);
}
}
EventHandler<MouseEvent> whattodohandler = new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
OrderItem orderitem = new OrderItem();
orderitem.read_item_name = readitem.getname();
orderitem.read_item_price=readitem.getprice();
orderitem.read_itemID=readitem.getid();
orderitem.choice_name_list = new ArrayList<String>();
orderitem.choice_price_list = new ArrayList<Float>();
orderitem.choice_id_list = new ArrayList<Integer>();
ChosenItemsStat.getplusbtnclicked(orderitem);
Random rand = new Random();
TablesMain.stringProperty.setValue(String.valueOf(rand));
}
};
}
ChosenItemsStat.java (a static class receiving the additions to the list)
public class ChosenItemsStat {
static ArrayList<OrderItem> chosenorderitemsstat = new ArrayList<>();
static void getplusbtnclicked(OrderItem orderitem){
chosenorderitemsstat.add(orderitem);
}
}
I didn't use the VboxList.fxml or the VboxListController.java as I included this in the TablesMain.java (see below)
TablesMain.java (as in the question but with this addition)
stringProperty = new SimpleStringProperty();
stringProperty.setValue("");
tablelbl.setText(stringProperty.getValue());
stringProperty.addListener(new ChangeListener(){
#Override
public void changed(ObservableValue observable, Object oldValue, Object newValue) {
showselectedlist();
}
});
while the showselectedlist() that is being called by the change of the StringProperty value is the one below (in this method the cell is being contructed as in the removed class (VboxListController)
private void showselectedlist(){
orderitems.addAll(ChosenItemsStat.chosenorderitemsstat);
ChosenItemsStat.chosenorderitemsstat.clear();
ListView<OrderItem> selectedlist = new ListView<>();
ObservableList<OrderItem> myObservableList = FXCollections.observableList(orderitems);
selectedlist.setItems(myObservableList);
selectedlist.setMaxWidth(220);
selectedlist.setCellFactory(new Callback<ListView<OrderItem>, ListCell<OrderItem>>() {
#Override
public ListCell<OrderItem> call(ListView<OrderItem> p) {
ListCell<OrderItem> cell = new ListCell<OrderItem>(){
OrderedCell ordcell= new OrderedCell();
#Override
protected void updateItem(OrderItem orderitem, boolean bln) {
super.updateItem(orderitem, bln);
if (orderitem != null) {
Float price = ordcell.getitemTempPrice(orderitem,orderitem.read_item_price);
HBox namepriceHbox = new HBox();
Label lblprice= new Label(String.format("%.2f",price));
Region betweenregion = new Region();
Label lblname = new Label();
lblname.setText(orderitem.read_item_name );
lblname.setStyle("-fx-font: 10pt \"Arial\";-fx-font-weight:bold");
namepriceHbox.setHgrow(betweenregion, Priority.ALWAYS);
namepriceHbox.getChildren().addAll(lblname,betweenregion,lblprice);
VBox allVbox = new VBox();
Text lblchoices = new Text();
String choices = ordcell.choicestostring(orderitem);
lblchoices.setText(choices);
lblchoices.setWrappingWidth(listpane.getLayoutBounds().getWidth());
if (choices.equals("")) allVbox.getChildren().addAll(namepriceHbox);
else allVbox.getChildren().addAll(namepriceHbox, lblchoices);
double namepricewidth = listpane.getLayoutBounds().getWidth();
System.out.println("namepricewidth is "+String.valueOf(namepricewidth));
//allVbox.setPadding(new Insets(10,0,10,0));
setGraphic(allVbox);
}
}
};
return cell;
}
});
listpane.getChildren().add(selectedlist);
}

Implement tags bar in JavaFX

Demonstration of answer:(answered May 29 at 3:10 am)
**10/7/2016** you can find the code on GitHub
Actual Question before answered:(asked May 22 at 19:53)
The title might be not too great but what I want to do is something like this in JavaFX:
Examples
YouTube:
StackOverFlow(which has and autocomplete):
Question:
I don't require to write me the code for that. Instead I want to know how I can achieve that using JavaFX and some ideas.
For the tags you can use a custom styled HBox containing a Text (the tag name) node an a Button (the deletion button (X)). By playing around with the background and the border you can achieve the desired look of the tags.
The onAction handler of the button should remove the tag from it's parent...
For the whole tag bar you can use another HBox. Use the appropriate border for the correct look. In addition to the tags add a TextField with no background as last element and set the Hgrow property of that TextField to Priotity.ALWAYS to cover the rest of the available space.
The onAction handler of this TextField adds new tags and clears the content of the TextField.
You could e.g. use ControlsFX's autocompletion features with the TextField or implement it on your own for a custom look...
public class TagBar extends HBox {
private final ObservableList<String> tags;
private final TextField inputTextField;
public ObservableList<String> getTags() {
return tags;
}
public TagBar() {
getStyleClass().setAll("tag-bar");
getStylesheets().add(getClass().getResource("style.css").toExternalForm());
tags = FXCollections.observableArrayList();
inputTextField = new TextField();
inputTextField.setOnAction(evt -> {
String text = inputTextField.getText();
if (!text.isEmpty() && !tags.contains(text)) {
tags.add(text);
inputTextField.clear();
}
});
inputTextField.prefHeightProperty().bind(this.heightProperty());
HBox.setHgrow(inputTextField, Priority.ALWAYS);
inputTextField.setBackground(null);
tags.addListener((ListChangeListener.Change<? extends String> change) -> {
while (change.next()) {
if (change.wasPermutated()) {
ArrayList<Node> newSublist = new ArrayList<>(change.getTo() - change.getFrom());
for (int i = change.getFrom(), end = change.getTo(); i < end; i++) {
newSublist.add(null);
}
for (int i = change.getFrom(), end = change.getTo(); i < end; i++) {
newSublist.set(change.getPermutation(i), getChildren().get(i));
}
getChildren().subList(change.getFrom(), change.getTo()).clear();
getChildren().addAll(change.getFrom(), newSublist);
} else {
if (change.wasRemoved()) {
getChildren().subList(change.getFrom(), change.getFrom() + change.getRemovedSize()).clear();
}
if (change.wasAdded()) {
getChildren().addAll(change.getFrom(), change.getAddedSubList().stream().map(Tag::new).collect(Collectors.toList()));
}
}
}
});
getChildren().add(inputTextField);
}
private class Tag extends HBox {
public Tag(String tag) {
getStyleClass().setAll("tag");
Button removeButton = new Button("X");
removeButton.setOnAction((evt) -> tags.remove(tag));
Text text = new Text(tag);
HBox.setMargin(text, new Insets(0, 0, 0, 5));
getChildren().addAll(text, removeButton);
}
}
}
style.css
.tag-bar {
-fx-border-color: blue;
-fx-spacing: 3;
-fx-padding: 3;
-fx-max-height: 30;
}
.tag-bar .tag {
-fx-background-color: lightblue;
-fx-alignment: center;
}
.tag-bar .tag .button {
-fx-background-color: transparent;
}
#Override
public void start(Stage primaryStage) {
Button btn = new Button("Sort");
StackPane.setAlignment(btn, Pos.BOTTOM_CENTER);
TagBar tagBar = new TagBar();
btn.setOnAction((ActionEvent event) -> {
FXCollections.sort(tagBar.getTags());
});
Button btn2 = new Button("add \"42\"");
btn2.setOnAction(evt -> {
if (!tagBar.getTags().contains("42")) {
tagBar.getTags().add("42");
}
});
VBox root = new VBox();
root.getChildren().addAll(tagBar, btn, btn2);
root.setPrefSize(300, 400);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
Simple implementation of this code!
import ....
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
BorderPane root = new BorderPane();
HBox tagsPane = new HBox(10);
tagsPane.setStyle("-fx-border-color: #F1F1F1;" +
" -fx-border-width: 1px;" +
" -fx-border-radius: 10;" +
" -fx-border-insets: 5");
root.setBottom(tagsPane);
TextField textField = new TextField();
textField.setPromptText("Tag name - ENTER to add");
textField.setOnKeyPressed(event -> {
if (event.getCode() == KeyCode.ENTER) {
tagButton(tagsPane, textField.getText());
textField.clear();
}
});
root.setTop(textField);
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root, 450, 275));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
//little image as 15x15 for example
Image toUse = new Image("sample/delete.png");
//box is the pane where this buttons will be placed
public void tagButton(HBox box,String tag){
ImageView closeImg = new ImageView(toUse);
Button result = new Button(tag,closeImg);
result.setPrefHeight(20);
result.setContentDisplay(ContentDisplay.RIGHT);
result.setOnAction(event -> box.getChildren().remove(result));
box.getChildren().add(result);
}
}
Also if u need different events for click on tag and click on "X" you can implement tagButton like this :
public void tagButton(HBox box,String tag){
ImageView closeImg = new ImageView(toUse);
HBox button = new HBox();
button.setStyle("-fx-padding:4;" +
" -fx-border-width: 2;" +
" -fx-border-color: black;" +
" -fx-border-radius: 4;" +
" -fx-background-color: f1f1f1;" +
" -fx-border-insets: 5;");
button.setPrefHeight(20);
button.getChildren().addAll(new Label(tag),closeImg);
closeImg.setOnMouseClicked(event ->
box.getChildren().remove(button)
);
button.setOnMouseClicked(event -> {
//doSomethig
});
box.getChildren().add(button);
}
This is my version too
The whole Main class
its somehow long that's why.
But to sum up. You need a
1: FlowPane for the container, and you do not have to worry about wrapping,it will wrap itself, both vertical or horizontal.
2: Label of course for your Text, which has a GraphicProperty
3: Path - well you could use Button, and add a Shape or Image to it, but that will be a lot of Nodes, so i used Path and i drew a X red button.
The rest is styling to your preferred color
EDIT
something like this?
you can style it to get that output
setFont(Font.font("Serif Regular", FontWeight.SEMI_BOLD,12));
use this line on the TextField
Here is a basic example of a tag bar (I wrote some code, because I think it's easier to follow). For the additional AutoComplete function you could use e.g. ControlsFx, as fabian already mentioned.
public class CloseTag extends HBox implements Comparable<CloseTag> {
private Label label;
private Label closeIcon;
public CloseTag(String text) {
setStyle("-fx-padding:8;");
Text icon = GlyphsDude.createIcon(FontAwesomeIcon.TIMES_CIRCLE);
closeIcon = new Label(null, icon);
label = new Label(text, new StackPane(closeIcon));
label.setContentDisplay(ContentDisplay.RIGHT);
getChildren().add(label);
}
public void setOnCloseAction(EventHandler<? super MouseEvent> action) {
closeIcon.setOnMouseClicked(action);
}
public String getText() {
return label.getText();
}
#Override
public int compareTo(CloseTag other) {
return getText().compareTo(other.getText());
}
}
public class TagPane extends FlowPane {
private TextField textField;
public TagPane() {
setStyle("-fx-padding:8;" + "-fx-hgap:10;");
setOnMouseClicked(evt -> onMouseClickedd(evt));
textField = new TextField();
textField.setOnKeyPressed(evt -> onKeyPressed(evt, textField));
}
private void onMouseClickedd(MouseEvent mouseEvent) {
if (mouseEvent.getTarget() != this || textField.getParent() != null ) {
return;
}
getChildren().add(textField);
textField.requestFocus();
}
private void onKeyPressed(KeyEvent evt, TextField textField) {
if (evt.getCode() == KeyCode.ENTER || evt.getCode() == KeyCode.TAB) {
createTag(textField.getText());
textField.clear();
}
}
private void createTag(String text) {
CloseTag tag = new CloseTag(text);
tag.setOnCloseAction(evt -> removeTag(tag));
getChildren().remove(textField);
getChildren().add(tag);
}
private void removeTag(CloseTag tag) {
getChildren().remove(tag);
}
}

How to use theme Selected style for Component in ListCellRenderer if isSelected

I have a custom ListCellRenderer in which I would like to have the currently selected item highlighted with a background gradient.
It seems like I should be able to define the Selected style for the rendered component in the Codenameone Designer under theme and set that UIID for the component to achieve this.
I can't figure out how to pass the selected state of the list item to the Label component being rendered though, so I resort to changing the style manually as you can see in my code below. Can I accomplish the same behaviour with my theme Resources somehow?
public class PlanetListRenderer extends Container implements ListCellRenderer<Hashtable<String, String>> {
private Label planetLabel = new Label();
private Resources theme;
public PlanetListRenderer(Resources theme) {
this.theme = theme;
BoxLayout bl = new BoxLayout(BoxLayout.Y_AXIS);
setLayout(bl);
planetLabel.setUIID("PlanetListItem");
planetLabel.setTextPosition(Label.BOTTOM);
addComponent(planetLabel);
}
public Component getListFocusComponent(List list) {
return planetLabel;
}
public Component getListCellRendererComponent(List list,
Hashtable<String, String> value, int index, boolean isSelected) {
planetLabel.setIcon(theme.getImage("icon" + value.get("value") + ".png"));
planetLabel.setText(value.get("value"));
if ( isSelected ) {
planetLabel.getStyle().setBackgroundGradientStartColor(255255255);
planetLabel.getStyle().setBackgroundGradientRelativeY(0.2f);
planetLabel.getStyle().setBackgroundGradientRelativeSize(1.0f);
planetLabel.getStyle().setBackgroundType(Style.BACKGROUND_GRADIENT_RADIAL);
} else {
planetLabel.getStyle().setBackgroundType(Style.BACKGROUND_NONE);
}
return this;
}
}
Below is a ListCellRenderer which changes the selected item. Not sure if it does what you're looking for, but you can see it for real from Google Play (or App Store) by searching for "Torquepower Diesel Cummins Engine" app. When you select any list item you'll see the backgound change.
public class FaultCodesListCellRenderer extends Container implements ListCellRenderer {
Label focus;
Label code;
Label effect;
Image warning;
Image emergency;
public FaultCodesListCellRenderer(Resources res) {
// get images for warning lights
emergency = res.getImage("emergency.png");
warning = res.getImage("warning.png");
setLayout(new BorderLayout());
setUIID("Underline");
code = new Label();
code.setUIID("BoldLabel");
code.setTextPosition(RIGHT);
code.getStyle().setMargin(Component.RIGHT, 6);
effect = new Label();
effect.setTickerEnabled(false);
addComponent(BorderLayout.WEST, code);
addComponent(BorderLayout.CENTER, effect);
int h = Display.getInstance().convertToPixels(8, false);
setPreferredH(code.getPreferredH() < h ? h : code.getPreferredH());
focus = new Label("");
focus.setUIID("UnderlineSelected");
}
public Component getListCellRendererComponent(List list, Object value, int index, boolean isSelected) {
Diagnostic diagnostic = (Diagnostic) value;
if (diagnostic.light.equals("R")) {
code.setIcon(emergency);
} else {
code.setIcon(warning);
}
code.setText(diagnostic.code);
effect.setText(diagnostic.effect);
return this;
}
public Component getListFocusComponent(List list) {
return focus;
}
I suggest using background images/borders instead of gradients which aren't as performant.
By default touch UI's don't show selection permanently. If you use getAllStyles instead of getStyle e.g.:
Form hi = new Form("Renderer Demo", new BorderLayout());
ArrayList<Map<String, String>> al = new ArrayList<>();
for(int iter = 0 ; iter < 100 ; iter++) {
HashMap<String, String> data = new HashMap<String, String>();
data.put("key1", "Data " + iter);
data.put("key2", "Different Data " + iter);
al.add(data);
}
DefaultListModel<Map<String, String>> listModel = new DefaultListModel<>(al);
List<Map<String, String>> l = new List<>(listModel);
l.setRenderer(new ListCellRenderer() {
private Container container;
private Label cover;
private TextArea item;
{
item = new TextArea(2, 80);
cover = new Label();
container = BorderLayout.center(item).add(BorderLayout.EAST, cover);
container.setCellRenderer(true);
cover.setCellRenderer(true);
item.setCellRenderer(true);
}
#Override
public Component getListCellRendererComponent(List list, Object value, int index, boolean isSelected) {
Map<String, String> val = (Map<String, String>)value;
item.setText(val.get("key1"));
cover.setText(val.get("key2"));
Style itemStyle = item.getAllStyles();
Style coverStyle = cover.getAllStyles();
Style containerStyle = container.getAllStyles();
itemStyle.setBgTransparency(255);
coverStyle.setBgTransparency(255);
containerStyle.setBgTransparency(255);
if (isSelected) {
itemStyle.setFgColor(0xff0000);
itemStyle.setBgColor(0x000000);
coverStyle.setBgColor(0xff0000);
containerStyle.setBgColor(0x000000);
} else {
itemStyle.setFgColor(0x000000);
itemStyle.setBgColor(0xffffff);
coverStyle.setBgColor(0x000000);
containerStyle.setBgColor(0xffffff);
}
return container;
}
#Override
public Component getListFocusComponent(List list) {
return null;
}
});
hi.add(BorderLayout.CENTER, l);
hi.show();

JavaFX: ComboBox cells disappear when clicked

I'am working on a java project using javafx multiple input types.but i am having a strangle ComboBox behaviours since i use Labels with images(ImageView) on it.
1- Combobox looks in white! but i need it in black.
2- and every time i choose an item.
3- it disappear!!!
Here is my code:
...
import javafx.scene.control.ComboBox;
import javafx.scene.image.ImageView;
ImageView img_tun = new ImageView("images/icones/flag/Tunisia.png");
Label lbl_tun=new Label("1",img_tun);
ImageView img_fr = new ImageView("images/icones/flag/France.png");
Label lbl_fr=new Label("2",img_fr);
ImageView img_aut = new ImageView("images/icones/flag/World.png");
Label lbl_aut=new Label("3",img_aut);
optionsnat=FXCollections.observableArrayList(lbl_tun,lbl_fr,lbl_aut);
#FXML
ComboBox<Label> cb_nat = new ComboBox<Label>();
private String nat="1";
...
#Override
public void initialize(URL location, ResourceBundle resources) {
...
cb_nat.getSelectionModel().selectedIndexProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observableValue, Number number, Number number2) {
if(cb_nb.getItems().get((Integer) number2)=="1"){setNat("1");}
else if(cb_nb.getItems().get((Integer) number2)=="2"){setNat("2");}
else if(cb_nb.getItems().get((Integer) number2)=="3"){setNat("3");}
else{System.err.println("Erreur lors de changement de nation..");}
}
});
}
...
and code.fxml
<ComboBox fx:id="cb_nat" layoutX="40.0" layoutY="265.0" prefWidth="150.0" />
EDIT:
After reading this Article i know that my approach is tottaly wrong and strongly not recommended.. if anyone have another ideas to put bnation flags in ComboBox please help!!
thanks..(Sorry for my bad english)
What is causing this problem is that when you choose a ListCell, its item (Label in our situation) is being moved by the ComboBox from the ListCell (Items observableList) to the ButtonCell, the ButtonCell is the small box that is empty by default. However, we all know that any Node object cannot be placed twice anywhere inside the same scene, and since there is no clone function for the ListCell class, javafx removes it from its last place to the new place which is the ButtonCell.
The solution is to add strings
items in the list and provide a cell factory to create the label node inside the cell factory. Create a class called "StringImageCell" and do the following:
You need to set the cellFactory property:
cb_nat.setCellFactory(listview -> new StringImageCell());
You need to set the buttonCell property: cb_nat.setButtonCell(new StringImageCell());
Here is an example:
public class ComboBoxCellFactory extends Application {
#Override
public void start(Stage stage) throws Exception {
ComboBox<String> comboBox = new ComboBox<>();
comboBox.getItems().addAll("1", "2", "3");
//Set the cellFactory property
comboBox.setCellFactory(listview -> new StringImageCell());
// Set the buttonCell property
comboBox.setButtonCell(new StringImageCell());
BorderPane root = new BorderPane();
root.setCenter(comboBox);
Scene scene = new Scene(root, 600, 600);
stage.setScene(scene);
stage.show();
}
//A Custom ListCell that displays an image and string
static class StringImageCell extends ListCell<String> {
Label label;
static HashMap<String, Image> pictures = new HashMap<>();
#Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setItem(null);
setGraphic(null);
} else {
setText(item);
ImageView image = getImageView(item);
label = new Label("",image);
setGraphic(label);
}
}
}
private static ImageView getImageView(String imageName) {
ImageView imageView = null;
switch (imageName) {
case "1":
case "2":
case "3":
if (!pictures.containsKey(imageName)) {
pictures.put(imageName, new Image(imageName + ".png"));
}
imageView = new ImageView(pictures.get(imageName));
break;
default:
imageName = null;
}
return imageView;
}
public static void main(String[] args) {
launch(args);
}
}

Formatting issues in View - Vaadin

I have created a view as below:
The menu Layout or the left vertical layout does not have the entire Layout filled in Blue color. Its only Blue till the respective Buttons are present.
I need to have the entire Menu Layout in Blue Color and retain the Buttons in same position as it is now. So, to achieve it I uncommented the below code in the view
menuLayout.setSizeFull();
But the entire menu layout becomes very bad to look as below. please see the below snapshot
Could someone please help on this?
The code used is as below:
public class AppointmentView extends CustomComponent implements View,Button.ClickListener {
private static final long serialVersionUID = 1L;
public static final String NAME = "Appointment";
private VerticalLayout mainLayout = new VerticalLayout();
private VerticalLayout upperSection = new VerticalLayout();
private HorizontalSplitPanel lowerSection = new HorizontalSplitPanel();
private VerticalLayout menuLayout = new VerticalLayout();
private VerticalLayout contentLayout = new VerticalLayout();
private Button newContact = new NativeButton("Add contact");
private Button search = new NativeButton("Search");
private Button share = new NativeButton("Share");
private Button help = new NativeButton("Help");
private NavigationTree tree = new NavigationTree();
public AppointmentView() {
setSizeFull();
upperSection.addComponent(new Label(""));
menuLayout.addComponent(new Label(""));
contentLayout.addComponent(new Label(""));
menuLayout.setSpacing(true);
//menuLayout.setSizeFull();
menuLayout.setStyleName(Reindeer.LAYOUT_BLUE);
lowerSection.addComponent(menuLayout);
lowerSection.addComponent(contentLayout);
lowerSection.setSizeFull();
upperSection.setStyleName(Reindeer.LAYOUT_BLUE);
upperSection.addComponent(createToolbar());
lowerSection.setSplitPosition(30);
menuLayout.addComponent(createVerticalToolbar());
mainLayout.addComponent(upperSection);
mainLayout.addComponent(lowerSection);
mainLayout.setSizeFull();
mainLayout.setExpandRatio(lowerSection, 1);
setCompositionRoot(mainLayout);
}
private Component createToolbar() {
HorizontalLayout layout = new HorizontalLayout();
Embedded em = new Embedded("", new ClassResource("../../com/image/logo.png"));
layout.addComponent(em);
layout.setComponentAlignment(em, Alignment.MIDDLE_RIGHT);
layout.setExpandRatio(em, 1);
layout.setStyleName("toolbar");
layout.setMargin(true);
layout.setSpacing(true);
layout.setWidth("100%");
return layout;
}
#SuppressWarnings("deprecation")
private Component createVerticalToolbar() {
VerticalLayout lo = new VerticalLayout();
newContact.setStyleName("img");
newContact.setWidth("100%");
newContact.setIcon(new ClassResource("../../com/image/document-add.png"));
newContact.addListener((Button.ClickListener) this);
lo.addComponent(newContact);
search.setIcon(new ClassResource("../../com/image/folder-add.png"));
search.addListener((Button.ClickListener) this);
search.setWidth("100%");
lo.addComponent(search);
share.setIcon(new ClassResource("../../com/image/users.png"));
share.addListener((Button.ClickListener) this);
share.setWidth("100%");
lo.addComponent(share);
help.setIcon(new ClassResource("../../com/image/help.png"));
help.addListener((Button.ClickListener) this);
help.setWidth("100%");
lo.addComponent(help);
lo.setMargin(true);
lo.setSpacing(true);
lo.setWidth("100%");
lo.setSizeFull();
return lo;
}
public void buttonClick(ClickEvent event) {
final Button source = event.getButton();
if (source == search) {
Notification.show("Search hit");
} else if (source == newContact) {
Notification.show("New contact");
} else if (source == help) {
Notification.show("Help");
} else if (source == share) {
Notification.show("Share");
}
}
#Override
public void enter(ViewChangeEvent event) {
// TODO Auto-generated method stub
}
}
You nested two VerticalLayouts for the left menu.
When you wish to fill the whole height, then setting the height to 100% is the correct way to do it.
A VerticalLayout usually distributes the space between the components.
If you don't wish this, then you can set expansionratios to tell it which component should use how much space.
In the constructor change the line calling the createVerticalToolbar to this:
.....
createVerticalToolbar(menuLayout);
.....
private void createVerticalToolbar(VerticalLayout lo) {
newContact.setStyleName("img");
newContact.setWidth("100%");
newContact.setIcon(new ClassResource("../../com/image/document-add.png"));
newContact.addListener((Button.ClickListener) this);
lo.addComponent(newContact);
search.setIcon(new ClassResource("../../com/image/folder-add.png"));
search.addListener((Button.ClickListener) this);
search.setWidth("100%");
lo.addComponent(search);
share.setIcon(new ClassResource("../../com/image/users.png"));
share.addListener((Button.ClickListener) this);
share.setWidth("100%");
lo.addComponent(share);
help.setIcon(new ClassResource("../../com/image/help.png"));
help.addListener((Button.ClickListener) this);
help.setWidth("100%");
lo.addComponent(help);
// Add new component which uses up the remaining space
Label lbl= new Label("About");
lo.addComponent(lbl);
lo.setExpandRatio(help, 20);
lo.setMargin(true);
lo.setSpacing(true);
lo.setWidth("100%");
lo.setSizeFull();
return lo;
}

Categories

Resources