javafx don't loss the focus when click other node - java

I have a vbox on left of rootpane,and a vbox on right of rootpane.
leftvobx have 3 textarea nodes,rightvbox have a colorpicker;
I want: when I choose one textarea node on leftvbox, then to click colorpicker on rightvbox, the current textarea don't loss the focus.
My idea is same as "Scene builder" , when we select a note in the workspace, then to handle the right slide function area(like change color,set size and font),the note will not lose focus, so the action know which node in workspace need handle.
Code:
VBox leftBox = new VBox();
VBox rightBox = new VBox();
leftBox.setPrefSize(200, 250);
rightBox.setPrefSize(200, 250);
leftBox.setStyle("-fx-background-color:blue");
Button btn1 = new Button("First");
Button btn2 = new Button("Second");
Button btn3 = new Button("Third");
ColorPicker colorpicker = new ColorPicker();
leftBox.getChildren().addAll(btn1,btn2,btn3);
rightBox.getChildren().add(colorpicker);
colorpicker.setOnAction(e->{
if(btn2.isFocused()){
btn2.setText("color changed.");
}
});
HBox root = new HBox();
root.getChildren().addAll(leftBox,rightBox);
Scene scene = new Scene(root, 400, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
enter image description here

There is no way to have two nodes focused afaik. That would be very weird, since every keyboard event etc would go to two nodes. In the JavaFX scene builder as well, you can try it. Click on something in the SceneBuilder and press delete, it will be deleted. Press on something in the SceneBuilder and then on the right and press delete and the item you selected first will not be deleted. Because it doesn't actually have focus. SceneBuilder just shows you what you had last selected.
To solve your problem. I would make a new Variable Button lastFocused; and make Listeners on the other Buttons focusedProperty something like this:
btn2.focusedProperty().addListener((ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) -> {
if(!newValue) lastFocused = btn2;
});
This should store the Button in the new variable as soon as it looses focus. As it looses focus when you focus the color picker, the variable will have the Button that was selected when the color picker got selected.
Now in the color picker something like this should work:
colorpicker.setOnAction(e->{
lastFocused.setText("color changed.");
lastFocused.requestFocus();
});
I have not actually tested the code.

Related

ScrollPane scroll does not work with other nodes

I want to have StackPane as my root pane. I want to have a scrollPane as a small box in the middle of the scene and two buttons below the container.
I tried to make it happen by writing this code:
private StackPane root = new StackPane();
private Scene scene = new Scene(root, 1366, 768);
public ContinueScreen() {
Button button1 = new ButtonBuilder("My Button1").setPrefWidth(200).build();
Button button2 = new ButtonBuilder("My Button2").setPrefWidth(200).build();
Button button3 = new ButtonBuilder("My Button3").setPrefWidth(200).build();
Button button4 = new ButtonBuilder("My Button4").setPrefWidth(200).build();
Button button5 = new ButtonBuilder("My Button5").setPrefWidth(200).build();
Button button6 = new ButtonBuilder("My Button6").setPrefWidth(200).build();
VBox vBox = new VBox(5);
vBox.getChildren().addAll(button1, button2, button3, button4, button5, button6);
ScrollPane scrollPane = new ScrollPane();
scrollPane.setContent(vBox);
scrollPane.setPannable(true);
scrollPane.setMaxSize(500, 180);
scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.ALWAYS);
scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED);
root.getChildren().add(scrollPane);
StackPane.setAlignment(scrollPane, Pos.CENTER);
}
As you can probably notice, the code does work perfectly fine but that is until I add the buttons below I was talking about. I added those buttons in an HBox as
HBox hBox = new HBox(5);
hBox.setAlignment(Pos.BOTTOM_CENTER);
hBox.getChildren().addAll(new Button("cat"), new Button("dog"));
root.getChildren().addAll(hBox);
Now both the scrollpane and the two buttons are shown. However the scroll pane now stops working for some reason. The scrollpane is shown and its content but the horizontal or the vertical scroll, both of them do not work. Anyone knows why is this happening and how to fix it?
As you are using StackPane as root it piles up the nodes on one another so the top pane is HBox and not the ScrollPane, so it you are not able to use.
Use BorderPane or VBox and try.
BorderPane root = new BorderPane();
Scene scene = new Scene(root, 1366, 768);
root.setCenter(scrollPane);
HBox hBox = new HBox(5);
hBox.getChildren().addAll(new Button("cat"), new Button("dog"));
root.setBottom(hBox);
The issue here is that StackPane is allowed to resize the HBox, which it does. The HBox covers the complete scene preventing mouse events from reaching the ScrollPane. You can easily see this by coloring the HBox:
hBox.setStyle("-fx-background-color: rgba(100%, 0%, 0%, 0.5)");
The most simple solution would be to set up the HBox to only receive events on non-(fully-)transparent areas:
hBox.setPickOnBounds(false);
However you could also set up the HBox to take up the space required to fit the preferred size of the content and do the alignment via the StackPane:
hBox.setPrefSize(Region.USE_COMPUTED_SIZE, Region.USE_COMPUTED_SIZE);
hBox.setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
StackPane.setAlignment(hBox, Pos.BOTTOM_CENTER);
// hBox.setAlignment(Pos.BOTTOM_CENTER);
Note that using a StackPane like this does not provide you with a responsive GUI: If you resize the window to a small enough height, the buttons will cover the ScrollPane.
You may have better luck using a BorderPane or wrapping the StackPane and the HBox in a VBox and setting VBox.vgrow to Priority.ALWAYS for the StackPane...

Creating new Transparent Stage on Event JavaFX

I'm trying to create a new Stage when a button is pressed.
It works but the problem is that I'd like this Stage to be fully transparent and lets us see what's behind the screen.
Code
Dimension Sizescreen = Toolkit.getDefaultToolkit().getScreenSize();
//Main stage with option menu
Pane window = new Pane();
Scene scene = new Scene(window);
stage.setTitle("Notification Extender");
//Create the button SetLooker
Button SetLooker = new Button("Set Looker");
//Add a Event when pressed
SetLooker.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
//Create a sub-Stage
Pane subwindow = new Pane();
Scene subscene = new Scene(subwindow);
Stage substage = new Stage();
substage.setTitle("Notification Extender");
//Set this subStage Transparent
substage.initStyle(StageStyle.TRANSPARENT);
subscene.setFill(Color.TRANSPARENT);
substage.setWidth(Sizescreen.getWidth());
substage.setHeight(Sizescreen.getHeight());
substage.setX(0);
substage.setY(0);
//Create a a graphique element
Rectangle redrec = new Rectangle(120,40,50,50);
redrec.setStroke(Color.RED);
redrec.setStrokeWidth(2);
redrec.setFill(Color.TRANSPARENT);
//Add the graphique element to the sub-stage
subwindow.getChildren().add(redrec);
//Show the sub-stage
substage.setScene(subscene);
substage.show();
}
});
//Add the button to the main stage
window.getChildren().add(SetLooker);
//Show the main stage
stage.setScene(scene);
stage.show();
The problem is that when I press the button it shows the stage but it's not transparent at all it's completely white.
I've also tried to change the main Stage, but I cannot change it once it has been shown.
You also need to remove the background from the root of your new scene:
subwindow.setBackground(null);

Parent Stage hidden on switching to the 3rd party window and again switching to Application Stage

My parent stage "stage1" is opening child stage "stage2" and i have set child stage's modality as below.
stage2.initModality(Modality.APPLICATION_MODAL);
Now when i open stage2 from stage1, stage1 is appears behind stage2 that is expected, but when i press "Ctrl+Tab" key, control switches to 3rd paty applicaton for example "Outlook", then I again press "Ctrl+Tab" key, it returns to our main applicaton and it shows stage2 but stage1 appears hidden. My expectation is that stage1 should be hidden behind stage2.
Any help is greatly appriciated.
It is because Stage2.getOwner() == null is true. Your expectation is the way it works, when it is false. so to solve your problem do this
Stage2.initOwner(Stage1);
ediit
here is some demo
#Override
public void start(Stage stage) {
Pane p = new Pane();
p.setStyle("-fx-background-color: red");
stage.setTitle("I AM THE PARENT");
Scene scene = new Scene(p);
stage.setWidth(600);
stage.setHeight(600);
stage.setScene(scene);
stage.show();
Stage s = new Stage(StageStyle.DECORATED);
s.initModality(Modality.APPLICATION_MODAL);
p = new Pane();
p.setStyle("-fx-background-color: yellow");
s.setScene(new Scene(p,150,150));
//s.initOwner(stage); //with this commented it wont work
s.show();
}
Also you will notice that when your press CTRL + TAB the windows popup only shows your second window STAGE2, that is who he knows of, because its has not parent, but when it has owner is shows only the owner

JavaFX - Adding a ScrollPane popup which closes when user clicks out of it

My title is badly worded because my problem is very hard to describe, so I drew an image for it:
I have an ImageView object which represents a pile of cards (not poker cards but just used them as an example). When this image view is clicked, I need a window to popup that features a ScrollPane and shows them all the card objects that are in the linked list. When the user clicks anywhere outside of the window (and later on, any right mouse button click) the scrollpane window needs to close.
Ways that I have already tried:
Scene with APPLICATION_MODAL. Then did Scene.showAndWait(). I didn't like this method because it made another application on the user's taskbar. It also felt clunky and just bad.
Changed my root pane to a StackPane, then added this Scrollpane to the stackpane when the user clicked on the deck. This for some reason was really slow and seemed really obtrusive. It was also annoying because my alternate class needed to have access to the root pane (since when it closes, it needs to go to the root StackPane and call .remove() on itself).
Are there any other better ways to accomplish this? My application is going to have many of these piles and so this framework needs to work very well.
I would still propose to open a new Stage with some restrictions to solve your issues with this approach.
You can use the initOwner property of the Stage to have another Stage as owner, therefore no other icon will appear on the taskbar.
You can use the initStyle property with TRANSPARENT or UNDECORATED StageStlye, this will ensure that only the content is visible.
And in the end you can use the focusedProperty to check whether the Stage lost focus to close it.
Example
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
BorderPane root = new BorderPane();
Scene scene = new Scene(root,400,400);
Button b = new Button("Open deck");
b.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
Stage popupStage = new Stage();
popupStage.initOwner(primaryStage);
popupStage.initStyle(StageStyle.UNDECORATED);
Scene sc = new Scene(new ScrollPane(), 300, 300);
popupStage.setScene(sc);
popupStage.focusedProperty().addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue,
Boolean newValue) {
if(!newValue)
popupStage.close();
}
});
popupStage.show();
}
});
root.setCenter(b);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
It is also possible of course to not open it in a new Stage, but draw a ScrollPane inside the current Stage which overlaps the content of the Stage using for example an AnchorPane or Group as root, but the first solution has the advantage that you are not bound to the dimensions of main Stage (the popup can have any size that you want).
You can achieve this with a low level system hook that catches the mouse events.
http://kra.lc/blog/2016/02/java-global-system-hook/ or https://github.com/kwhat/jnativehook/releases
I hope that is what you needed, otherwise i got your question wrong.

How do I make a class in JavaFX 2.0 a usable Node?

I am new to JavaFX so please don't hesitate to explain basic concepts. I am able to create a simple GUI and I have a TabPane with two tabs in my program. My question is how do I create a class that can be used as a node?
For example, tab.setContent(stuff) would add stuff to a tab, tab assuming of course that stuff is a Node. So let's say I create a class called Clock and want to add an instance of it to tab, how do I do such a thing?
The clock should be a graphical object. I'm new to graphical programming so references to Swing etc. won't be particularly helpful.
In your case, create a class "Clock" and extend it with a layout you wish it to contain. For example:
public class Clock extends BorderPane{}
Then, you can set properties or other Nodes to it by using a constructor.
public class Clock extends BorderPane{
TextArea ta = new TextArea("This is TOP");
this.setTop(ta);
Button b1 = new Button("This is button 1");
Button b2 = new Button("This is button 2");
HBox box = new HBox();
box.getChildren().addAll(b1,b2);
this.setCenter(box);
}
Then, you would call it from your main program as such:
#Override
public void start(Stage primaryStage){
primaryStage.setScene(new Scene(new Clock()));
primaryStage.show();
}
In your case, you would set the Scene when the tab is pressed. That can be done using the Tab class and adding an actionListener to it.
tab.setContent(new Clock());
Hope this helped.
Please add a method in clock, then also make a constructor that calls this method. put all
TextArea ta = new TextArea("This is TOP");
this.setTop(ta);
Button b1 = new Button("This is button 1");
Button b2 = new Button("This is button 2");
HBox box = new HBox();
box.getChildren().addAll(b1,b2);
this.setCenter(box);
inside that methode.

Categories

Resources