JavaFX ListCell enable horizontal Growth - java

I currently have a ListView that is resizable in Width and I use a custom CellFactory that returns my custom ListCell objects.
I already read this:
Customize ListView in JavaFX with FXML and I use a similar construct like the one mentioned:
public class ListViewCell extends ListCell<String>{
#Override
public void updateItem(String string, boolean empty){
super.updateItem(string,empty);
if(string != null) {
...
setGraphic(myComponent);
}
}
I want myComponent to take the full size that is available inside the ListCell, however it seems that the setGraphic method limits the size of the given Node.
I can provide all my code if it is necessary, however I am not sure which parts are relevant and I do not want to post a big wall of code.

Try setting prefWidth property of your control to Infinity either via CSS or via API so as to provide its maximal expansion whithin container:
myComponent.setStyle("-fx-pref-width: Infinity");

I solved my Problem now, here is how:
class MyListCell extends ListCell<MyObject>
{
private final AnchorPane _myComponent;
public MyListCell()
{
...
this.setPrefWidth(0);
myComponent.prefWidthProperty().bind(this.widthProperty());
}
...
#Override
protected void updateItem(MyObject item, boolean empty)
{
...
setGraphic(_myComponent);
...
}
}
If this.setPrefWdith(0) is ommited, myComponent will grow inside the ListCell, but the Cell won't shrink if I shrink my ListView.

Related

How to set cell's indentation in TreeView in Javafx

I am working on a TreeView which represents a robot controlling program, each TreeCell represents a statement, and a TreeCell can be nested in an other one. Like in programming, statements can be nested in if or for statements.
Here I have created a simple demo, filled with some random blocks.
Demo Screenshot
To customize the rendering of TreeCell, I have create a class extending TreeCell:
public class TreeDataCell extends TreeCell<TreeData> {
public void updateItem(TreeData item, boolean empty) {
super.updateItem(item, empty);
setText(null);
if (item == null || empty) {
setGraphic(null);
} else {
setGraphic(getCellGraphic(item));
}
}
private Group getCellGraphic(TreeData data) {
Group grp = new Group();
VBox vbox = new VBox();
vbox.setMinWidth(100);
vbox.setMaxWidth(200);
vbox.setBorder(new Border(new BorderStroke(
Color.LIGHTGRAY.darker(),
BorderStrokeStyle.SOLID,
new CornerRadii(10.0),
new BorderWidths(2.0))));
vbox.setBackground(new Background(new BackgroundFill(Color.LIGHTGRAY, new CornerRadii(10.0), null)));
vbox.setEffect(new DropShadow(2.0, 3.0, 3.0, Color.DIMGRAY));
Region header = new Region();
header.setPrefHeight(5.0);
Region footer = new Region();
footer.setPrefHeight(5.0);
Label labTitle = new Label();
labTitle.setFont(new Font("San Serif", 20));
labTitle.setText(data.getTitle());
Label labDesc = null;
if (data.getDescription() != null) {
labDesc = new Label();
labDesc.setWrapText(true);
labDesc.setText(data.getDescription());
}
vbox.getChildren().addAll(header, labTitle);
if (labDesc != null) {
vbox.getChildren().add(labDesc);
}
vbox.getChildren().add(footer);
grp.getChildren().add(vbox);
return grp;
}
}
The TreeData is a simple class containing 2 Strings:
public class TreeData {
private String title;
private String desc;
/* getters + setters */
}
As you can see, the indentation between two levels are too small, and we can barely see statement nesting.
I am hard coding all the styles in Java, since I haven't learnt FXML+CSS yet.
I'd like to know if it is possible to set the size of indentation in Java? I cannot find any API for this purpose. In addition, is it possible to draw lines between parent node and its children like JTree in Swing ?
Thank you.
Regarding having lines like in JTree, there is no built in way to do that as of JavaFX 11. There is a feature request (JDK-8090579) but there doesn't seem to be any plans to implement it. You may be able to implement it yourself but I'm not sure how.
As to modifying the indent of the TreeCells, the easiest way is by using CSS.
As documented in the JavaFX CSS Reference Guide, TreeCell has a CSS property named -fx-indent whose value is a <size>. You can set this property by using a stylesheet or inline it via the style property. An example using inline styles:
public class TreeDataCell extends TreeCell<TreeData> {
public TreeDataCell() {
setStyle("-fx-indent: <size>;");
}
}
However, since you are currently not using CSS or FXML, there is another option that is purely code: Modifying the indent property of TreeCellSkin. This class became public API in JavaFX 9. There may be equivalent internal API in JavaFX 8 but I'm not sure.
By default, the Skin of a TreeCell will be an instance of TreeCellSkin. This means you can get this skin and set the indent value as needed. You have to be careful, though, as the skin is lazily created; it won't necessarily be available until the TreeView is actually part of a showing window.
If you only want to set the property once, one way is to intercept the skin inside createDefaultSkin():
public class TreeDataCell extends TreeCell<TreeData> {
#Override
protected Skin<?> createDefaultSkin() {
TreeCellSkin<?> skin = (TreeCellSkin<?>) super.createDefaultSkin();
skin.setIndent(/* your value */);
return skin;
}
}
You could also extend TreeCellSkin and customize it. Just remember to override createDefaultSkin() and return you custom skin implementation.

Eclipse plugin: Properties information not shown correctly when treeview is part of a tabfolder/tabitem

I am developing an eclipse plug in with a tree viewer. Initially I had a single treeview of which I have displayed information of some elements in the standard eclipse properties tab. That worked without problems.
I have followed an example where I implement the IPropertySource and IAdapterFactory. In the method createPartControl() of the view I call
getSite().setSelectionProvider(searchViewer);
which registers the properties.
Now I have added an swt tabfolder item to the plug in. Now In every new tabitem a treeview is displayed. That works fine, but the information in the properties tab are not shown correctly anymore. There's a strange behaviour though. On the tree elements which are of interest I have also added a doubleclick listener to do other things. After I double click an entry and right after single click on another element, the properties are shown for the doubleclicked element?!
I guess the problem is with the SelectionProvider. But I was not able to figure out how to implement it correctly now
The properties view always shows the properties for the object that the selection provider says is the current selection.
If you have multiple tree views on several tabs you will have to write a custom selection provider (ISelectionProvider) that knows which tree is currently active and provides the appropriate selection.
For example, the following is a selection provider used by the JDT code for some things which you could use as a base:
public class SimpleSelectionProvider implements ISelectionProvider {
private final ListenerList<ISelectionChangedListener> fSelectionChangedListeners;
private ISelection fSelection;
public SimpleSelectionProvider() {
fSelectionChangedListeners = new ListenerList<>();
}
#Override
public ISelection getSelection() {
return fSelection;
}
#Override
public void setSelection(ISelection selection) {
fSelection= selection;
for (ISelectionChangedListener listener : fSelectionChangedListeners) {
listener.selectionChanged(new SelectionChangedEvent(this, selection));
}
}
#Override
public void removeSelectionChangedListener(ISelectionChangedListener listener) {
fSelectionChangedListeners.remove(listener);
}
#Override
public void addSelectionChangedListener(ISelectionChangedListener listener) {
fSelectionChangedListeners.add(listener);
}
}
(org.eclipse.jdt.internal.ui.actions.SimpleSelectionProvider)
You would have to make all your trees call the setSelection method when selections change.

Java FX: TableView - display simple HTML

I'd like to know, if it is possible to render simple HTML tags in JavaFX TableView (b, i, subscript, supscript). In my code snippet I used default cellValueFactory, but maybe someone could tell me if exists any cell factory which allow me to display html.
From code:
class Data{
private String row = "<b> Sample data</b>"
public String getRow(){
return row;
}
TableView<Data> tableView = new TableView();
TableColumn<Data,String> column = new TableColumn("Sample Column");
column.setCellValueFactory(new PropertyValueFactory<Data, String>("row"));
tableView.getColumns().addAll(column);
I wish I could see Sample Data in my table in bold. Thanks in advance!
--UPDATE
Code that allows me to see my HTML, but resizes table cell, WebView size is ignored and not wrapped tight
private class HTMLCell extends TableCell<Component, Component> {
#Override
protected void updateItem(Component item, boolean empty) {
super.updateItem(item, empty);
if (!empty) {
WebView webView = new WebView();
webView.setMaxWidth(200);
webView.setMaxHeight(50);
WebEngine engine = webView.getEngine();
// setGraphic(new Label("Test"));
setGraphic(webView);
String formula = item.getFormula();
engine.loadContent(formula);
}
}
}
TableColumn<Component, Component> formulaColumn = new TableColumn<>("Formula");
formulaColumn.setMinWidth(300);
formulaColumn.setCellFactory(new Callback<TableColumn<Component, Component>, TableCell<Component, Component>>() {
#Override
public TableCell<Component, Component> call(TableColumn<Component, Component> param) {
return new HTMLCell();
}
});
formulaColumn.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Component, Component>, ObservableValue<Component>>() {
#Override
public ObservableValue<Component> call(CellDataFeatures<Component, Component> param) {
return new SimpleObjectProperty<Component>(param.getValue());
}
});
HTML in a WebView in a TableCell
You have to make your own cell factory which returns a WebView node into which you load your HTML content.
On Correctly Sizing the WebView
In terms of establishing the preferred size of the WebView node, that is a little tricky. It would be simpler if RT-25005 Automatic preferred sizing of WebView were implemented.
I think the sample code from your question will work if you just replace the maxSize setting for the WebView with a webView.setPrefSize(prefX, prefY) call. You will just have to guess what the prefX and prefY values should be as I don't know a good way of determining programmatically.
I think your code should work by setting the max size for the WebView, but the WebView doesn't seem to respect the max size setting and just uses the pref size setting, which I think may be a bug in Java 8b129 (you could file that in the JavaFX Issue Tracker with a minimal, executable test case which reproduces it and a description of your test environment).
TextFlow Alternative
You might also consider using TextFlow component for representing your styled text. It is not HTML, but if all you want to do is some simple styling like making some text in the cell bold or italic, it might be a good option.
Use HTML tables in WebEngine/WebView rather than TableView.
Table examples

GWT-Platform revealing presenters together

Hey so I am just learning the gwtp framework and I have come across a bit of a dilemma. I have a LayoutPresenter at the top level that has a main content slot and menu content slot and I am trying to find a way to bind my presenters for each slot together if possible so when the main content is revealed it will automatically show the correct side menu. Currently I have a static boolean in the Menu's Presenter that get updated onReveal and onHide. I can then check if the menu is visible when the main content is revealed and if not I reveal it.
public class MenuPresenter extends Presenter<MenuPresenter.MyView, MenuPresenter.MyProxy> {
private static boolean hidden = true;
...
#Override
protected void revealInParent() {
RevealContentEvent.fire(this, LayoutPresenter.SIDE, this);
}
#Override
protected void onReveal(){
super.onReveal();
hidden = false;
}
#Override
protected void onHide(){
super.onHide();
hidden = true;
}
public static boolean isHidden(){
return hidden;
}
}
Then in The main content Presenter:
public class ContentPresenter extends
Presenter<ContentPresenter.MyView, ContentPresenter.MyProxy> {
...
private final DispatchAsync dispather;
private final PlaceManager placeManager;
#Inject
public PhoneCallPresenter(final EventBus eventBus, final MyView view, final MyProxy proxy, final DispatchAsync dispatcher, final PlaceManager placeManager) {
super(eventBus, view, proxy);
this.dispather = dispatcher;
this.placeManager = placeManager;
}
#Override
protected void revealInParent() {
RevealContentEvent.fire(this, LayoutPresenter.CONTENT, this);
}
#Override
protected void onReveal() {
super.onReveal();
if (MenuPresenter.isHidden()){
placeManager.revealPlace(new PlaceRequest(NameTokens.menu));
}
}
}
As far as I understood the question, you want to have different side-menus for different main contents.
In this case there are two solutions:
Treat the menu as a normal Presenter (you will probably have multiple of them for each main content type). You just need to annotate the corresponding MenuPresenter with the same history token as your main content Presenter. So for the above example you would have a PhoneCallMenuPresenter that is annotated with the same history token as your PhoneCallPresenter. When you navigate to /phonecall (or whatever your history token is), both PhoneCallPresenter and PhoneCallMenuPresenter will be revealed automatically . (you don't have to do anything).
In case you want to have only one MenuPresenter and put the logic what to display in the Presenter itself, I would recommend to use a PresenterWidget instead of a normal Presenter. The MenuPresenterWidget will be injected into the LayoutPresenter and will be added to the LayoutPresenter.SIDE slot. You can define a setter for the MenuPresenterWidget to specify which main content is currently displayed (the setter will be called from the LayoutPresenter or you can override the onReset() method and check the current place request and decide what to display in the menu.
For solution 1 you have to have one MenuPresenter for each main content Presenter and potentially many code lines will be redundant (you could create a base MenuPresenter and derive from it). So in case you have a lot of business logic in the side-menu which is quite different from main content to main content, I would go with solution 1. In case you only display different links the overhead of creating a MenuPresenter per main content Presenter might be to high and I would go with solution 2 and create only one MenuPresenterWidget for all main content types and always show it.

Set focus on a component with Apache Wicket?

How do you set focus on a component with Apache Wicket? Searching leads to very little information, mostly on setting the default field. I do not want to set a default field, rather I am looking to set focus when, for example, a specific radio button is selected.
I suggest using the native org.apache.wicket.ajax.AjaxRequestTarget#focusComponent(). For example:
/**
* Sets the focus in the browser to the given component. The markup id must be set. If
* the component is null the focus will not be set to any component.
*
* #param component
* The component to get the focus or null.
*/
org.apache.wicket.ajax.AjaxRequestTarget#focusComponent(Component component)
Once you create your behavior to set the focus, you should be able to add it to the component on any event, just make sure that component is part of the AjaxRequestTarget. I don't see why this wouldn't work...
myRadioButton.add(new AjaxEventBehavior("onchange") {
#Override
protected void onEvent(AjaxRequestTarget target) {
myOtherComponent.add(new DefaultFocusBehavior());
target.addComponent(myForm);
}
});
Here's a link that shows how to create the default focus behavior if you do not have one already:
http://javathoughts.capesugarbird.com/2009/01/wicket-and-default-focus-behavior.html
If you only want to setFocus through javascript and don't want to reload a form or a component, you can use the following code:
import org.apache.wicket.Component;
public class JavascriptUtils {
private JavascriptUtils() {
}
public static String getFocusScript(Component component) {
return "document.getElementById('" + component.getMarkupId() + "').focus();";
}
}
And then in any Ajax Method you can use:
target.appendJavascript(JavascriptUtils.getFocusScript(componentToFocus));
For a pop-up like modalWindow my workaround solution was to use the attribute "autofocus" on the first input tag.
An easy solution is to add it to the html directly.
<input ..... autofocus>
Another solution is to add it to the modalWindow itself:
#Override
public void show(AjaxRequestTarget target) {
super.show(target);
setUpFocus();
}
protected void setUpFocus() {
DeepChildFirstVisitor visitor = new DeepChildFirstVisitor() {
#Override
public void component(Component component, IVisit<Void> iVisit) {
if (isAutofocusable(component)) {
component.add(new AttributeAppender("autofocus", ""));
iVisit.stop();
}
}
#Override
public boolean preCheck(Component component) {
return false;
}
};
this.visitChildren(FormComponent.class, visitor);
}
protected boolean isAutofocusable(Component component) {
if (component instanceof TextArea ||
component instanceof DropDownChoice ||
// component instanceof RadioChoice ||
component instanceof AjaxCheckBox ||
component instanceof AjaxButton ||
component instanceof TextField) {
return true;
}
return false;
}
RadioChoice is commented out because this solution is not working on that. For RadioChoice i would recommend to implement a FocusedRadioChoice:
public class FocusedRadioChoice<T> extends RadioChoice<T> {
//constructors...
#Override
protected IValueMap getAdditionalAttributes(int index, T choice) {
super.getAdditionalAttributes(0, choice);
AttributeMap am = new AttributeMap();
am.put("autofocus", "");
return am;
}
}
Is there a way to achieve the same without JavaScript?
(I am implementing a form with a feedback-Panel that only comes up when Javascript is turned off, so it would not make sense to depend on JavaScript there...,-)
I could only find answers which use JS .focs()... maybe Wicket 1.5 will provide a method Component.setFocus()...
If you happen to be using an Ajax button, you can simply call target.focusComponent(myComponent); in the button's onSubmit method.
#martin-g 's solution was the only solution that got it working for my scenario - a modal/pop up.
Note:
I think autofocus embedded explicitly in HTML only works on page load, not modal load so any efforts to skillfully set the autofocus attribute in the HTML of a modal just fail miserably - always.
Here I lay out the steps for setting the focus on an input field called 'myInput' using the full power of Wicket (no JS!):
In onInitialize:
// Make sure the field has an ID in markup
myInput.setOutoutMarkupId(true);
Provide an overridden show method where you call the focusComponent method:
public void show(AjaxRequestTarget target)
{
// Make sure you call the super method first!
super.show(target);
target.focusComponent(myInput);
}
This does require that your component is an attribute of your modal content class so that you can access it in the show method. To avoid creating a class attribute for your input component you could blend this solution with the solution from BlondCode by replacing that solution's
component.add(new AttributeAppender("autofocus", ""));
with
target.focusComponent(component);
This also works!

Categories