In javaFX 2.0 there is ChoiceBox control it is practically made of 2 items, one is label and other on is ContextMenu. Somewhere I saw somebody said something like “use ChoiceBox with low amount of data and ListView for high amount of data” but he did not said why. I was curious why not is there some limit or what, so i tried what would happened if I insert at least 100 items in Choice Box.
Lets try code example:
<br /> ChoiceBox<String> cb = new ChoiceBox<String>(FXCollections.observableArrayList(Font.getFamilies())); // just add to scene root
I need nice ChoiceBox with font list in application that am currently developing so I decided to take a little test.
When I saw result i know why someone said use it only with low data 10-20 items maximum. You can see result by yourself or on down image.
That really disappointed me i need ChoiceBox with more then 150 fonts (all system fonts + custom fonts) and i don’t want to show big ListView or huge context menu because it looks ugly. After little bit of digging testing and experimenting. I have decided to create my own ComboBox.
Some nice features of ComboBox that i want to see:
- having scrolling ListView (we all know that ListView can have CellFactory) that is great because i want to see font preview in list
- some nice animation when showing or hiding ListView
- setting size of visible ListView
- getting selectedItem from ComboBox
- …
<br /> package playground.control;</p> <p>import java.util.List;<br /> import javafx.beans.property.BooleanProperty;<br /> import javafx.beans.property.DoubleProperty;<br /> import javafx.beans.value.InvalidationListener;<br /> import javafx.beans.value.ObservableValue;<br /> import javafx.collections.ObservableList;<br /> import javafx.scene.control.Control;<br /> import javafx.scene.control.ListCell;<br /> import javafx.scene.control.ListView;<br /> import javafx.scene.control.MultipleSelectionModel;<br /> import javafx.util.Callback;</p> <p>/**<br /> *<br /> * @author jojorabbit<br /> *<br /> */<br /> public class ListComboBox<T> extends Control {</p> <p> private static final String LIST_COMBO_BOX_STYLE_CLASS = "list-combo-box";<br /> protected static final String PSEUDO_CLASS_SHOWING = "showing";<br /> protected ListView<T> listView;<br /> protected DoubleProperty visibleHeight = new DoubleProperty(0.0d);<br /> private BooleanProperty showing = new BooleanProperty() {</p> <p> @Override<br /> protected void invalidated() {<br /> ListComboBox.this.impl_pseudoClassStateChanged(PSEUDO_CLASS_SHOWING);<br /> }<br /> };</p> <p> public ListComboBox() {<br /> init();<br /> initListeners();<br /> visibleHeight.set(200.0d); // set default height to 200.0<br /> }</p> <p> public boolean isShowing() {<br /> return showing.get();<br /> }</p> <p> public BooleanProperty showingProperty() {<br /> return showing;<br /> }</p> <p> @Override<br /> public void impl_getPseudoClassState(List<String> list) {<br /> super.impl_getPseudoClassState(list);<br /> if(isShowing()) {<br /> list.add(PSEUDO_CLASS_SHOWING);<br /> }<br /> }</p> <p> private void init() {<br /> getStyleClass().add(LIST_COMBO_BOX_STYLE_CLASS);<br /> listView = new ListView<T>();<br /> listView.getStyleClass().add("list");<br /> }</p> <p> public void setItems(ObservableList<T> items) {<br /> listView.setItems(items);<br /> }</p> <p> /**<br /> * Sets visible size of wrapped ListView<br /> * @param value<br /> */<br /> public void setVisibleHeight(double value) {<br /> visibleHeight.set(value);<br /> }</p> <p> /**<br /> * Add cell factory to listView<br /> * @param value cellFactory<br /> */<br /> public void setCellFactory(Callback<ListView<T>, ListCell<T>> value) {<br /> listView.setCellFactory(value);<br /> }</p> <p> /**<br /> * Get listView selections Model<br /> * @return selection model<br /> */<br /> public MultipleSelectionModel<T> getSelectionModel() {<br /> return listView.getSelectionModel();<br /> }</p> <p> /**<br /> * Get selected item<br /> * @return selected item<br /> */<br /> public T getSelectedItem() { return listView.getSelectionModel().getSelectedItem(); } /** * Get selected index * @return selected index */ public int getSelectedIndex() { return listView.getSelectionModel().getSelectedIndex(); } private void initListeners() { visibleHeight.addListener(new InvalidationListener<Number>() { @Override public void invalidated(ObservableValue<? extends Number> observable) { listView.setPrefHeight(visibleHeight.get()); listView.setMinHeight(visibleHeight.get()); listView.setMaxHeight(visibleHeight.get()); } }); } }
<br /> private ListView<T> listView;<br /> private Timeline timeline; // timeline for some animations<br /> private Label selectedLabel; // label<br /> private StackPane arrow; // "holder" for arrow shape<br /> private StackPane line; // "holder" for line shape<br /> private static final Duration ANIMATION_DURATION = Duration.valueOf(300.0d); // default animation duration<br />
EDIT: 28.06.2011.
<br /> .list-combo-box .arrow-container {<br /> -fx-background-color: -fx-shadow-highlight-color, -fx-outer-border, -fx-inner-border, -fx-body-color; -fx-background-insets: 0 0 0 0, 0, 1, 2;<br /> -fx-background-radius: 0 5 5 0, 0 5 5 0, 0 4 4 0, 0 3 3 0; /* top right and bottom right corners are rounded*/ -fx-alignment: CENTER;<br /> -fx-padding: 10;<br /> }<br />
Some of changes in source :
<br /> StackPane arrow = new StackPane();<br /> arrow.getStyleClass().add("arrow");</p> <p> arrowContainer = new StackPane();<br /> arrowContainer.getStyleClass().add("arrow-container");<br /> arrowContainer.getChildren().add(arrow);
Pingback: JavaFX links of the week, June 27 // JavaFX News, Demos and Insight // FX Experience
Pingback: Java desktop links of the week, June 27 | Jonathan Giles
Nice post. Do you also plan to update the sources in github with your most recent changes?
Michael
Hi,
thanks. Yes am planning to update it as soon as possible, i guess in few days with some new controls just need to finish them.
Pingback: JavaFX links of the week, July 11 // JavaFX News, Demos and Insight // FX Experience
Thanks for the update. This is a very useful new control. Just two more questions: Would it be possible to provide a default cell factory, so that you do not have to set it explicitly if you do not need any special item display? At the moment you get an NPE if you do not set a cell factory. Would it also be possible to make the speed of the animation configurable? I would like to speed it up a little.
Many thanks
Michael
Yes you are right i forgot to make default cell Factory, thanks for pointing that out.
It is possible to make animations duration configurable, it is in TODO list. I was even thinking with different animations too but don’t have so much time to test it out.
I will post new comment when i update it and will write changes to comment.
New version of Control is in git.
Changes :
– added animation duration property
– added default cellFactory
– added focus traversing (TAB, SHIFT+TAB, …)
Thanks again for the update. I have a little problem with the code though. When I run the ListComboBoxTest unmodified it works in principle but very often the list display seems to hang, or just shows up and disappears immediately or just shows an empty border without content when I repeatedly click on the arrow. I found out that this depends on the setting of the animation time. The setting in the example is 10ms. If I set that to 100ms the nasty effects disappear. If I set it to 0ms the list appears but never goes away again. So there seems to be something wrong with the animation when the duration is getting small.
Thanks again
Michael
No problem. I did not have much time to play a lot with it, i will see what is problem with effect, if nothing else would not work I will limit animation duration to some value.
Hi jojorabbit4,
Just downloaded listcombobox stuff, and tried to run it after doing a clean and build on my test machine. This is what I get:
Deleting: C:\Users\Mark\Documents\NetBeansProjects\ListComboBoxTest\build\built-jar.properties
deps-jar:
Updating property file: C:\Users\Mark\Documents\NetBeansProjects\ListComboBoxTest\build\built-jar.properties
Copying 1 file to C:\Users\Mark\Documents\NetBeansProjects\ListComboBoxTest\build\classes
compile:
run:
fonts: 295
WARNING: com.sun.javafx.css.StyleManager$2 run Resource “null” not found.
WARNING: com.sun.javafx.css.StyleManager$2 run Resource “null” not found.
SEVERE: javafx.scene.control.Control impl_processCSS The -fx-skin property has not been defined in CSS for ListComboBox@32007142[styleClass=list-combo-box]
SEVERE: javafx.scene.control.Control impl_processCSS The -fx-skin property has not been defined in CSS for ListComboBox@3b0bbdb3[styleClass=list-combo-box]
SEVERE: javafx.scene.control.Control impl_processCSS The -fx-skin property has not been defined in CSS for ListComboBox@7fd3510d[styleClass=list-combo-box]
SEVERE: javafx.scene.control.Control impl_processCSS The -fx-skin property has not been defined in CSS for ListComboBox@32007142[styleClass=list-combo-box]
SEVERE: javafx.scene.control.Control impl_processCSS The -fx-skin property has not been defined in CSS for ListComboBox@3b0bbdb3[styleClass=list-combo-box]
SEVERE: javafx.scene.control.Control impl_processCSS The -fx-skin property has not been defined in CSS for ListComboBox@7fd3510d[styleClass=list-combo-box]
BUILD SUCCESSFUL (total time: 3 second)
Eventhough I have insured that I have everything set up the same way you have it defined on github.
That is really old code now, i need to update github with newest code. Or you can go to jfxtras home page and run it through jfxtras it also has builder now so you can use it with FXML.
Hey, jojorabbit4! You wrote great article can you do it again for the 2.0.2 javafx ? ^))) Please! 🙂
Will see what i can do i have a lot of code to update. Will post comment when i will have something updated.
Cya soon.
Many Thanks !
Great blog.
Thanks 🙂
please reply to the following post
Thanks in advance 🙂
disabled combobox shows a blurred text, can we increase the brightness of the text? I have tried the opacity but i can not achieve full brightness in displayed text.
Hello I am so thrilled I found your weblog, I really found you by mistake, while I was looking
on Digg for something else, Anyhow I am here now and would just like to say thank
you for a fantastic post and a all round entertaining blog (I also love
the theme/design), I don’t have time to go through it all at the minute but I have book-marked it and also included your RSS feeds, so when I have time I will be back to read more, Please do keep up the fantastic job.
can anyone reply my question please??