JavaFX: set fullscreen exclusive mode (FSEM) in non-mouse/keyboard-handler - javafx

my application consists of a TabPane named tabPane with, lets say, two Tabs: firstTab and secondTab. Whenever firstTab is selected, I want the application to be in FSEM (full-screen exclusive mode, see documentation); otherwise it should be in normal windowed mode.
My usual way of being notified about which Tab is active is either
BooleanBinding isFirstTabActive = tabPane.getSelectionModel().
selectedItemProperty().isEqualTo(firstTab);
or
tabPane.getSelectionModel.selectedItemProperty().addListener(...);
Since stage.fullScreenProperty() is read-only and therefore cannot be binded (as stated in docs), I can not use my first method and do, lets say,
stage.fullScreenProperty().bind(isFirstTabActive) //not working.
Since I am not planning on sigining the application for now and, as the docs state:
Applications can only enter FSEM in response to user input. More specifically, entering is allowed from mouse (Node.mousePressed/mouseReleased/mouseClicked) or keyboard (Node.keyPressed/keyReleased/keyTyped) event handlers.
I can not use the second method either, by doing
tabPane.getSelectionModel.selectedItemProperty().addListener(new ChangeListener<Tab>() {
#Override
public void changed(ObservableValue<? extends Tab> observable, Tab oldValue, Tab newValue) {
stage.setFullScreen(newValue == firstTab);
}
);
because this way the application does not enter FSEM but only emulated fullscreen mode.
I do know that I can enter FSEM by creating EventHandlers which listen to tabPane events. But this way I had to add two EventHandlers for both MouseEvent.MOUSE_CLICKED and KeyEvent.KEY_TYPED, and the EventHandlers would have to explicitly find out whats going on ignoring their Event, like:
tabPane.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
stage.setFullScreen(tabPane.getSelectionModel().getSelectedItem() == firstTab);
}
});
So is this really the way to go here? Or can I do some workaround with the Bindings? Any suggestions here? Thanks.

Related

How does one call a method on the changing of a Tab in JavaFx?

Ok so here is what i am trying to do: I have a page called 'SettingsPage'. Now, in this page i Have a tabPane with 3 tabs; users, buttons, and sales. Buttons and Users both have tables which need to be populated with data before they are viewed by the user. When I was first making the program I just used a 'initialize' method to populate the user table on the opening of 'SettingsPage'. However, now that I am beginning to try and populate the buttons table, I am encountering a memory error because now there is too much data to be loaded at once together.
So, I though a good solution to this would be to make an Event method that is called whenever a certain tab is opened. I am using SceneBuilder atm, and what seemed to be the equivalent of this was onSelectionChanged, however I can't seem to use this as you would use 'methodEg(ActionEvent event)...'. So my question is, how can ensure that a method will be called on the opening of a certain tab.
For example, when 'buttonTab' is clicked, the 'populateButtonTable' method is called.
The answer to this was this code:
And if anyone asks why I didn't use .isSelected()... I did, it for some reason didn't work, but what I have done below does, so I dunno...
'''
#FXML public void initialize(URL url, ResourceBundle rb){
tabs.getSelectionModel().selectedItemProperty().addListener(
new ChangeListener<Tab>() {
#Override
public void changed(ObservableValue<? extends Tab> ov, Tab t, Tab t1)
{
if (tabs.getSelectionModel().getSelectedItem() == ExampleTab)
{
//do whatever
}
}
}
);

javafx reused pane initalization

Here's my situation. I have a javafx pane which I don't want to recreate each time I show it, because I want to keep all filled by user fields in between switching between views.
For that purpose I did this:
#FXML
private void initialize() {
createOrderPane = FxmlUtils.fxmlLoader(CREATE_ORDER_FXML);
}
public void setCenter(String fxmlPath) {
if(CREATE_ORDER_FXML.equals(fxmlPath)) {
borderPane.setCenter(createOrderPane);
}
else {
borderPane.setCenter(FxmlUtils.fxmlLoader(fxmlPath));
}
}
so in case user wants to see CREATE_ORDER_FXML it doesn't reload it, but uses already existing instance.
The problem is that some parts of the view should be reinitalized. For example database might change and I want to refresh some comboboxes which reads value from DB. How to achieve that?
Is there some onShow property? Or maybe I am able to get to the controller of createOrderPane object?

In JavaFx, how to control focus of a custom control?

Suppose a JavaFX CustomControl node that contains, say, two TextFields.
If any of these TextFields has the focus, then CustomControl.isFocused() should return true. If none of them has focus, then CustomControl.isFocused() should return false.
How do I do that?
As your CustomControl uses composition, you can delegate to the focus properties of each TextField. Given two instances,
private final TextField tf1 = new TextField("One");
private final TextField tf2 = new TextField("Two");
The implementation of an instance method isFocused() is then straightforward:
private boolean isFocused() {
return tf1.isFocused() | tf2.isFocused();
}
Add focus listeners as shown here to see the effect.
tf1.focusedProperty().addListener((Observable o) -> {
System.out.println(isFocused());
});
tf2.focusedProperty().addListener((Observable o) -> {
System.out.println(isFocused());
});
This can't be done. The whole problem is that isFocused() is final in Node.
It seems you wanted to override isFocused() in CustomControl, but that is not possible for a final method and it would violate the notion of a single component having focus. As CustomControl is a composite, you'll need to manage focus internally. You may want to use a custom FocusModel as seen in ListView.
Try one line solution:
public BooleanBinding aggregatedFocusProperty() {
return Bindings.or(field1.focusedProperty(), field2.focusedProperty());
}
Now on a client side you may listen this aggregated focus property.

How to skip DRAG_DETECTED Events from TableHeaderRow (resizing TableColumns)

In order to use a TableView (with resizable columns) as drag source,
I have attached an onDragDetected handler on that TableView with the effect, that resizing TableColumns does not work anymore: If the user clicks into the TableHeaderRow for dragging the column separators, these mouse events are consumed by my handler too.
The handler is attached to the whole TableView and I do not see a way to distinguish between events from TableRows and events from the TableHeaderRow.
Attaching the handler to the data-rows only is not appropriate in my case, since I need multiline selection (and do not want to have dependencies from the RowFactory to the application data model).
Any suggestions?
best Hans
I found the solution myself: I had to look up the TableHeaderRow instance with the lookup-method, and discard the DRAG_DETECTED event there.
Pane header = (Pane) mainTableView.lookup("TableHeaderRow");
header.setOnDragDetected(new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {
System.out.println("ignoring drag operation from table header.");
event.consume();
}
});
After that, resising of table columns works. Maybe there is something wrong with my drag+drop event handling that initially caused the problem!? Somebody voted down without comment...
The solution by Hans does work, but only after the window is shown. I added a window.setOnShown((WindowEvent e) listener and then I was able to do the lookup and header.setOnDragDetected.
Here is how I added it:
window.setOnShown((WindowEvent e) -> {
Pane header = (Pane) mainTableView.lookup("TableHeaderRow");
....
});
Otherwise, lookup returns null.

javafx setFocus after tabPaine change

Problem:
Have tabPane tabs OK.
In the first tab there is a text field. I am able to get focus on this field when starting the application.
After changing the tabs and coming back to the first tab I want focus to be on this textfield (barcodereader should be active in this field) without having to select the field with the mouse.
I am able to catch event from tabs with
tp.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Tab>()
{ etc
(could not post with code)
and I am able to trigger en event for the first tab.
But field.requestFocus(); does not work. Probably because this method comes before rendering the textfield.
So here is my question:
How do you set focus on a control after clicking tabs in TabPane?
If you handle the mouse release event, it works: (The doFocus enables the requestFocus handling only when a tab selection changed before, otherwise it kicks in every time you click somewhere in the TabPane.)
final SimpleBooleanProperty doFocus = new SimpleBooleanProperty(false);
tabPane.setOnMouseReleased(new EventHandler<Event>() {
#Override
public void handle(Event event) {
if (!doFocus.get()) {
return;
}
doFocus.set(false);
switch (tabPane.selectionModelProperty().getValue().selectedIndexProperty().intValue()) {
case 0: tf1b.requestFocus(); break;
case 1: tf2a.requestFocus(); break;
default: break;
}
}
});
tabPane.selectionModelProperty().getValue().selectedIndexProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observable,
Number oldValue, Number newValue) {
doFocus.set(true);
}
});
When the TabPane has focus, one can change tab selection with the cursor keys and there the TextFields also won't get the focus with selection based approach. This probably should be handled too, if you need it.
(Recently I had a similar problem. I noticed, that the TabPane switches tabs immediately when you press the mouse button. My guess would be, that the selection based approach requests focus on the TextField right after mouse down, but the continued mouse down steals the focus back to the TabPane. Or maybe even the single mouse down event which changes selection causes the focus to go back to TabPane. However, my assumptions regarding the reasons may not be correct, as I am a newbie to JavaFX.)
EDIT: That handling certainly is not optimal. For instance, if you change tabs with the keys, the doFocus will be enabled and then clicking anywhere in the TabPane will trigger the requestFocus call. I thought this should be mentioned.
Also, take a look at my solution for setting focus on TextArea, when user changes selected tab(using mouse or keyboard) https://stackoverflow.com/a/19046535/2791746

Resources