On Thu, 10 Oct 2024 21:32:29 GMT, Andy Goryachev <ango...@openjdk.org> wrote:

> > I did my best to actually find some use cases...
> 
> Allow me to refer to some of the linked tickets in RFE 
> https://bugs.openjdk.org/browse/JDK-8090456:
> 
> [JDK-8091524](https://bugs.openjdk.org/browse/JDK-8091524) Introduce a "focus 
> container" concept in class Parent
> 
> [JDK-8091670](https://bugs.openjdk.org/browse/JDK-8091670) Add API for better 
> control over keyboard focus

**JDK-8091524** - problem: User wants to create a panel that has its own focus 
cycle, and focus should not escape to other controls in the same Scene.  I saw 
this issue and feel that it is a "WON'T FIX" as there are standard solutions 
for this already.

It is clearly an X/Y problem.  A common thing that trips up beginning FX 
developers is that they're unwilling to create a 2nd Scene or a Dialog and 
prefer to just "add a child somewhere to show some extra controls".  This is 
not how you do this, and we shouldn't need to cater to something that is 
basically building a Dialog type infrastructure from scratch.  How would this 
handle mouse clicks outside the "blessed" panel?  Should that be restricted as 
well then?

Possible ways to address this problem: use dialogs, use nested event loops, 
disable components that should not be part of the focus cycle temporarily, 
overlay a transparent pane blocking clicks, etc... but best option, just use a 
dialog...

**JDK-8091670** - describes the same problem... Ensemble is not using the right 
tools to restrict focus.  Use dialogs for this purpose.  There is no need to 
restrict focus on container level.  Again, what happens when focus is 
restricted to a container, and the user clicks outside it?  What should then 
happen when I navigate?  Should the restricted container by part of the primary 
focus cycle, but then capture it with no way to exit it once you get there?

## Working example

Just to show you can easily do this already, below is an example that will show 
a new pane, with navigation restricted to it, allowing you to select a new name 
for a button.  Note that you can't click outside it with the mouse (although 
I'm sure I can add that as well and then "hide" the dialog).  Also note that 
the Dialog doesn't appear as a dialog (they don't have to) and that no new 
Window is created on the task bar or whatever.


package app;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.geometry.Point2D;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Dialog;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.Border;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.stage.StageStyle;

public class App extends Application {

    @Override
    public void start(Stage primaryStage) {
        GridPane gp = new GridPane(10, 10);

        gp.addEventHandler(ActionEvent.ACTION, e -> {
            // Create a Dialog:
            Dialog<String> d = new Dialog<>();

            // Get Button that triggered it:
            Button node = (Button)e.getTarget();

            // Find location of Button where we want to display a new Pane:
            Point2D pos = node.localToScreen(new Point2D(0, 
node.getLayoutBounds().getHeight()));

            // Set pane position and make it look like it is integrated:
            d.initStyle(StageStyle.TRANSPARENT);
            d.initOwner(node.getScene().getWindow());
            d.setX(pos.getX());
            d.setY(pos.getY());

            // Some content for our pane:
            HBox content = new HBox(5, new Label("Change button name to: "), 
new Button("Foo"), new Button("Bar"), new Button("Baz"));

            // Add a border to make it more clearly delineated, and a handler 
when any button was clicked:
            content.setBorder(Border.stroke(Color.RED));
            content.addEventHandler(ActionEvent.ACTION, ae -> {
                d.setResult(((Button)ae.getTarget()).getText());
                d.close();
            });

            // Set the content, show the pane, and if there was a result, set 
that the new text on the button that triggered it:
            d.getDialogPane().setContent(content);
            d.showAndWait().ifPresent(node::setText);
        });

        gp.add(new VBox(new Label("Standard Buttons in normal container"), new 
VBox(5, new Button("Click me"), new Button("B"), new Button("C"))), 0, 0);
        gp.add(new VBox(new Label("Standard Buttons in ScrollPane"), new 
ScrollPane(new HBox(5, new Button("A"), new Button("B"), new Button("C")))), 1, 
0);

        Scene scene = new Scene(gp);

        primaryStage.setScene(scene);
        primaryStage.show();
    }
}

-------------

PR Comment: https://git.openjdk.org/jfx/pull/1555#issuecomment-2406172036

Reply via email to