Show Tooltip on disabled Control in JavaFX - java

It is possible to show a Tooltip on a disabled Control?
I have the following code and this doesn't work:
txt_searchText.setDisable(true);
txt.searchText.setTooltip(new Tooltip("Message"));
Has anyone a solution for that problem?
Thx

The answer is no. Currently you cannot show a tooltip on disabled Node, for the simple reason that disabled Nodes do not receive any MouseEvents.
You can see the issue being raised in the official issue tracler here (require login) : https://javafx-jira.kenai.com/browse/RT-28850
One solution to your problem could be to wrap your Control into something else.
For example, put your control into another Control, like a SplitPane or a Label. Then you could apply your tooltip to that wrapper and disable your first control.

Not directly but you can warp your button into another control and while your button could be disable or not, the control will answer to mouse movements.
Button button = new Button("Click me"); //create a button
button.setDisable(true); //disable button in some way
SplitPane splitPane = new SplitPane(button); //warp it into a splitPane
splitPane.setTooltip(new Tooltip("I'm the Tooltip Massage")); //Crete a tooltip
Node that SplitPane extends "Controls" not Region and not pane.
so it's a Control and best for our case (warping buttons).
you must always use a Control to warp another control. other way you will not have access to setTooltip() method.

Here's a workaround using the CustomMenuItem class:
customMenuItem.getContent().setOnMouseEntered(e -> {
if (customMenuItem.isDisable()) {
Tooltip.install(customMenuItem.getContent(), tooltip);
} else {
Tooltip.uninstall(customMenuItem.getContent(), tooltip);
}
});

Another solution is to filter mouse events on the parent and display a tooltip on the disabled items. A typical example is a toolbar:
toolBar.addEventFilter(MouseEvent.MOUSE_MOVED, e -> {
var node = toolBar.getItems().stream()
.filter(Node::isDisabled)
.filter(n -> n.contains(n.parentToLocal(e.getX(), e.getY()))).findFirst();
if (node.isPresent() && node.get() instanceof Control control) {
toolBar.setTooltip(control.getTooltip());
} else {
toolBar.setTooltip(null);
}
});

Related

JavaFX: How to set a listener to the TabPane header onClick event

This is a weird question so I'll make my best to explain myself properly.
What I'd like is to trigger an event when a Tab in a TabPane get clicked, and by "clicked" I mean just clicked, not necessarily selected.
I already tried using the selectedProperty of the Tab, but that does call the event only if the Tab is clicked when it's not selected, not even if it's clicked when it's already selected.
The reason why I'm doing this is that I'm trying to make a collapsible tab pane that hides the content of the TabPane if you click again on the opened tab, I've already wrote the code for collapsing the TabPane and that works but... I have no idea on how to get a click event from the tab header.
I've even looked into TabPane source code too hoping that I could find the tab header container but I didn't find it there.
No need for a completely new skin - we can access the header nodes by lookup. Beware: implies relying on implementation details, which might change across versions.
The (undocumented!) style id to look for is ".tab-container" - that's the only child of the TabHeaderSkin (== region for a single tab header). It contains the label, the close button (if any) and the focus marker. This "skin" keeps a reference to its tab in its properties (undocumented, of course ;)
So the basic approach is to
lookup all tab-containers after the skin is installed
for each, register an appropriate mouse handler on its parent
on the respective mouseEvent, do whatever is needed
Note that the listeners have to be removed/added when the list of tabs is modified (not included in the snippet below).
In example code:
/**
* looks up the styled part of tab header and installs a mouseHandler
* which calls the work load method.
*
* #param tabPane
*/
private void installTabHandlers(TabPane tabPane) {
Set<Node> headers = tabPane.lookupAll(".tab-container");
headers.forEach(node -> {
// implementation detail: header of tabContainer is the TabHeaderSkin
Parent parent = node.getParent();
parent.setOnMouseClicked(ev -> handleHeader(parent));
});
}
/**
* Workload for tab.
* #param tabHeaderSkin
*/
private void handleHeader(Node tabHeaderSkin) {
// implementation detail: skin keeps reference to associated Tab
Tab tab = (Tab) tabHeaderSkin.getProperties().get(Tab.class);
System.out.println("do stuff for tab: " + tab.getText());
}

How to have a click on component in a grid cell in Vaadin 8 Grid to select cells row?

When clicking a cell in a Vaadin 8 Grid that contains component like VerticalLayout row does not get selected (using Vaadin 8.1.5).
If the component does not fill the whole cell then clicking the unused area in cell makes the row selected.
I have been researching how could the click on component be forwarded to the cell click listener but have not get any grip yet on that. Guess it is even not the best way to do it.
What would be the solution?
I provide my own current solution as an answer to not mess the question and for separate possible comments. This particular one is not perfect - for example multiselect is not handled correctly - but it is just meant to give the idea how i decided to handle this.
Idea is to extend a value provider so that it holds a reference to the grid for which it generates values. Beforementioned - in addition to that it generates grid column components - adds click listener to the component.
In this package is handled click on a component and there are references to the grid and row item so select/unselect is quite easy.
#RequiredArgsConstructor // i like lombok
private static class GridCallbackValueProvider
implements ValueProvider<GridEntity, Layout> {
private final Grid<GridEntity> grid;
#Override
public Layout apply(GridEntity source) {
AbsoluteLayout al = new AbsoluteLayout();
al.setWidth("100px");
al.setHeight("30px");
al.addStyleName(((source.isValid()) ? "green" : "red" ));
al.addLayoutClickListener( clickEvent -> {
if(grid.getSelectedItems().contains(source))
grid.deselect(source);
else
grid.select(source);
});
return al;
}
}
In case somebody is interested: in this test code GridEntity.isValid() simply returns random boolean value and it is used to choose from styles below:
.green { background-color: green; }
.red { background-color: red; }
And adding to the grid goes like:
grid.addComponentColumn(new GridCallbackValueProvider(grid) )
.setCaption("status").setId("status").setWidth(140);
see the following issue https://github.com/vaadin/framework/issues/10425.
as tsuoanttila said the solution is to invoke column.setWidgetEventsAllowed(true); so you do not need an AbstractLayout wrapper nor a LayoutClickListener.

Disable clickable slider from Sencha GXT

I am trying to add a slider as per (http://www.sencha.com/examples/#ExamplePlace:slider).
At the moment i use GWT 2.6 and Sencha GXT 3.1 Beta
The slider works, but i am able to change the value by just clicking somewhere on the slider. This in turn can mess up the value when i go to retrieve it.
TextField firstName = new TextField();
final Slider slider = new Slider();
slider.setMinValue(0);
slider.setMaxValue(10);
slider.setIncrement(1);
slider.setValue(5);
slider.addValueChangeHandler(new ValueChangeHandler<Integer>() {
#Override
public void onValueChange(ValueChangeEvent<Integer> event) {
firstName.setText(slider.getValue().toString());
}
});
I want to be able to update the field when the value is changed on the Slider. But the slider value should not be changed without dragging the "arrow". If you click somewhere on the slider should/could update the arrowhead to the chosen position though.
Anyone knows if its possible to disable clickable on the slider or do this in a better way? Or at least update the slider "arrow" to where someone clicked?
It is working in my scenario.
public void onValueChange(ValueChangeEvent<Integer> event)
sliderDetail.setValue(event.getValue());
sliderDetail.redraw();
firstName.setText(slider.getValue().toString());

How to create controls dynamically in JFace Wizard

I have a jFace wizard, I am using this to create a new project type eclipse plugin. As you can see from image below, I have one treeviewer on left side, and a SWT group on right side. What I want is when ever user selects one of the item from treeviewer, I should be able to create dynamic controls on right side SWT Group. Say user selects Test One, one right side I should be able to create few controls like label, text and few radio buttons on right side, similarly if user selects Test Two I should be able to create dynamic controls on right side.
Currently I tried below code:
tree.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
for (int i = 0; i < selection.length; i++) {
String tempStr = selection[i].toString();
tempStr = tempStr.replaceAll("TreeItem \\{", "");
String finalStr = tempStr.replaceAll("\\}", "");
if (finalStr.equals("Test One")) {
Button btn = new Button(g2, SWT.NONE); //g2 is right side group
btn.setText("Blaaaa");
btn.setVisible(true);
container.redraw();
}
}
But when I run, I see no changes on right group. Can anyone guide me what I am doing wrong? Any pointers would be very appreciated, since I am new to Eclipse development and SWT.
You probably didn't set a layout on the g2 group. This is the common cause for controls not showing up. You can also try using g2.layout() to ensure that the new controls are correctly laid out after you create them.
Additionally you could look at using a StackLayout so that once you create a set of controls you can just hide them all at once instead of destroying when the selection changes. This is often useful so that if the user comes back to a previous selection, they will find the data they entered in the same state when they switched the selection. Here is an example.

Expand and select node in Ext GWT 3.0 Tree

I've added an accordion layout container with a tree in its first content pane to my layout. No, a requirement calls to expand and select one node when the application is loaded (it's a mockup).
Then I've added this to the constructor of the class, that corresponds with the uibinder layout:
widget = uiBinder.createAndBindUi(this); // everything's bound
accordionLayoutContainer.setActiveWidget(firstPanel); // OK, expands first pane
tree.getSelectionModel().select(mynode, true); // no visible effect
tree.setExpanded(mynode, false); // no visible effect
What's missing here? Do I have to force the layout of "something" after setting the states or is it the wrong place to select and expand nodes?
Found the solution. The call to setExpand has to be deferred until the tree has been attached. So I added an AttachEvent.Handler to a parent widget - adding it to directly to the tree doesn't work, because the handler is called to early, before the models are registered.
widget = uiBinder.createAndBindUi(this); // everything's bound
accordionLayoutContainer.setActiveWidget(firstPanel); // OK, expands first pane
accordionLayoutContainer.addAttachHandler(new AttachEvent.Handler() {
#Override
public void onAttachOrDetach(AttachEvent event) {
clientsTree.getSelectionModel().select(mynode, true);
clientsTree.setExpanded(mynode, true);
}
});

Categories

Resources