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);
}
});
Related
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());
}
If I change the view from my main menu to another page and then return to my main menu somehow everything on my main menu page shifts to the top left by a about one centimeter. I dont know if I'm missing something?
This is the constructor for my main menu:
public MainMenuView() {
lHeader.setWidth(null);
addButton.setWidth("100px");
addButton.setHeight("100px");
searchButton.setWidth("100px");
searchButton.setHeight("100px");
editButton.setWidth("100px");
editButton.setHeight("100px");
vLayout.addComponent(buttons);
this.setCompositionRoot(vLayout);
buttons.setComponentAlignment(lHeader, Alignment.MIDDLE_CENTER);
addMerchant.setStyleName("mystyle");
showMerchants.setStyleName("mystyle");
merchantSearch.setStyleName("mystyle");
lHeader.addStyleName("mylabelstyle");
addButton.setStyleName("addButtonStyle");
searchButton.addStyleName("searchButtonStyle");
editButton.addStyleName("editButtonStyle");
addLabel.addStyleName("add");
searchLabel.addStyleName("search");
editLabel.addStyleName("edit");
addButton.addClickListener(e -> addMerchant());
editButton.addClickListener(e -> showMerchants());
searchButton.addClickListener(e -> merchantSearch());
}
It is occurred when some styles are duplicated in your first and second pages.
/you need to check them./
You need to check Scope type of your components. /Maybe it will occur when you use any UI component that annotated #SessionScope
How you managed routing between these 2 pages.
I have a parent Window which displays people i.e:
FirsName:John
LastName:Brown
Age:18
I click the Edit button, child window opens, change first name and then click accept, child window closes, the changes are in mysql database saved but the parent window still shows the old values. I do have a refresh method which works, but how can I call it from the child window or set it to be called after closing the child window?
Both Parent and Child Windows have controller and fxml. Any help would be appreciated.
James_D's Answer (better)
Thanks to #James_D, you should use setOnHidden instead of setOnCloseRequest, that way you can again just call .close() and the EventHandler will be called.
My Answer
You could make use of setOnCloseRequest:
childStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
public void handle(WindowEvent we) {
// Refresh the parent window here
}
});
To invoke this close request on a child form you can do:
childStage.getOnCloseRequest().handle(new WindowEvent(childStage, WindowEvent.WINDOW_CLOSE_REQUEST));
// or
childStage.fireEvent(new WindowEvent(childStage, WindowEvent.WINDOW_CLOSE_REQUEST));
So you could implement the close button on the child stage like so:
Button closeButton = new Button("Close");
closeButton.setOnAction(event -> childStage.fireEvent(new WindowEvent(childStage, WindowEvent.WINDOW_CLOSE_REQUEST)));
I think the best way to have automatic field updates in JavaFX is by the use of properties. If the name field in the parent window is bound to a SimpleStringProperty you only need to set the property's value when the child window is closed to notify the parent window of the update.
I made a small parent / child example to test the concept and the relevant piece of code is this, placed on the child creation method:
FXMLLoader loader = new FXMLLoader(getClass().getResource("Child.fxml"));
Parent root = loader.load();
ChildController controller = loader.getController();
name.textProperty().bind(controller.name.textProperty());
The field name is a Label in the parent and a TextField in the child. Any change in the child's text is immediately reflected in the parent.
This is an interesting topic. I will make a full example and post ir in my 'a cup of java' blog as soon as possible.
If you use popup, you can set the method to showandwait instead of just show from the Stage object, and after run the method that update the GUI. Because showandwait method pause the main frame while the popup is running, once the popup closes it will run your update code.
stage.showAndWait();
updateGUI();
we think we have two stage(window),1-parent stage,2-child window(pop up window)
first send the stage object of parent stage to child stage
in child stage set :
childStage.setOnHidden(event->{
Parent root=FXMLLoader.load(getClass().getResource(parent fxml));
Scene scene=new Scene(root);
parentStage.SetScene(scene);
parentStage.show();
`
I have an Eclipse RCP with a view whose Control is a CheckboxTableViewer.
I'd like to use the WorkbenchPage's SelectionService (for reasons of loose coupling) to react to check/uncheck actions within the view in an editor.
So I do getSite().setSelectionProvider(myTableViewer); in the view's createPartControl() method.
Also, I create a listener field in the editor:
private ISelectionListener mylistener = new ISelectionListener() {
public void selectionChanged(IWorkbenchPart sourcepart, ISelection selection) {
System.out.println(((IStructuredSelection) selection).size());
}
};
Unfortunately, I only get the number of rows that are selected printed out in the console, not the number of checked elements. I'm trying to pass myTableViewer.getCheckedElements() to the SelectionProvider somehow, but cannot find an access point :(.
You could write your own implementation of ISelectionProvider which returns the checked elements instead of using the default provider implemented by TableViewer which returns the selected elements.
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);
}
});