I have a context menu, which contains a CustomMenuItem with some controls. When clicking a button, a dialog shows and the context menu hides automatically. Here is the problem: I would like to prevent the closing of the context menu when the dialog shows. How can I solve this problem?
I already have tracked done the event. When the dialog opens, a FocusUngrabEvent.FOCUS_UNGRAB event is fired, which is handled in PopupWindow. I already tried to add an EventFilter and EventHandler to the context menu for FocusUngrabEvent.FOCUS_UNGRAB and consume the event, but that does not help.
Here an SSCCE demonstrating this problem:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.CustomMenuItem;
import javafx.scene.control.Label;
import javafx.stage.Stage;
public class PimaryStage extends Application {
#Override
public void start(Stage primaryStage) {
// The button which shows the dialog.
Button button = new Button("Some Button");
button.setOnAction((event)-> {
Alert alert = new Alert(Alert.AlertType.WARNING);
alert.setTitle("Warning");
alert.setHeaderText(null);
alert.setContentText("Some Text");
alert.show();
});
// Custom menu item which contains the button.
CustomMenuItem menuItem = new CustomMenuItem(button);
menuItem.setHideOnClick(false);
// Context menu.
ContextMenu menu = new ContextMenu();
menu.getItems().add(menuItem);
// Label.
Label label = new Label("Click here to open the context menu.");
label.setContextMenu(menu);
// Set the scene and show the stage.
Scene scene = new Scene(label, 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
This worked for me:
#FXML
public void autoShow() {
contextmenu.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
e.consume();
}
});
}
Place the above method in your controller class and then call it from the initialize method in your controller class:
#Override
public void initialize(URL location, ResourceBundle resources) {
autoShow();
}
Related
On javafx, I have a GridPane with buttons. Each button has a number on them that increases when a leftclick on the button happens and it decreases when a rightclick happens.
I want to know how can I make it so that when the number of one button reaches a certain value (5 for example), then the mouseEvent activates on the buttons that surround the button.
Also if one of those buttons reaches that certain value too, then the mouseEvent activates on its surrounding buttons as well and so on and so forth.
For increasing, decreasing and showing the number of the buttons, I wrap the Button class in an inner class called NumberButton.
Here is my code:
package sample;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.input.MouseButton;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
public class Main extends Application {
BorderPane root= new BorderPane();
GridPane grid= new GridPane();
class NumberButton extends Button{
private int innerNumber;
public NumberButton(){
this.innerNumber=0;
showNumber();
}
public void showNumber(){
this.setText(String.valueOf(innerNumber));
}
public void increaseInnerNumber(){
this.innerNumber++;
showNumber();
}
public void decreaseInnerNumber(){
this.innerNumber--;
showNumber();
}
public int getInnerNumber() {
return this.innerNumber;
}
}
#Override
public void start(Stage primaryStage) throws Exception{
NumberButton[][] buttons= new NumberButton[10][10];
for (int i=0; i<buttons.length;i++){
for (int j=0; j<buttons[i].length;j++){
buttons[i][j]= new NumberButton();
NumberButton button= buttons[i][j];
button.setOnMouseClicked(mouseEvent -> {
if (mouseEvent.getButton()== MouseButton.PRIMARY){
button.increaseInnerNumber();
if (button.getInnerNumber()==5){
/*all surrounding buttons activate the mouseEvent
* and mouseEvent.getButton()== MouseButton.PRIMARY is true */
}
}else if (mouseEvent.getButton()==MouseButton.SECONDARY){
button.decreaseInnerNumber();
}
});
button.setMinSize(30,30);
button.setMaxSize(30,30);
grid.add(button,i,j);
}
}
root.setCenter(grid);
primaryStage.setTitle("Number Buttons!");
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I have tried using button.setOnAction() but then I don't know how to get if the event was triggered by a leftclick or a rightclick and when I tried using both button.setOnAction() and button.setOnMouseClicked() then the event triggered twice and I don't want that.
I have a ChoiceBox and I want to refresh it's content whenever user expands it. I haven't found a proper listener for this. All the stuff google gives is related to handling ChangeValue events.
I reckon I should add eventListener<ActionEvent> to ChoiceBox since what I'm handling is click on a ChoiceBox, but my implementation doesn't work.
ActionEvent fires when I click on any List value, not when I click ChoiceBox itself.
Register a listener with the choice box's showingProperty:
choiceBox.showingProperty().addListener((obs, wasShowing, isNowShowing) -> {
if (isNowShowing) {
// choice box popup is now displayed
} else {
// choice box popup is now hidden
}
});
Here is a quick demo:
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.ChoiceBox;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class ChoiceBoxPopupTest extends Application {
private int nextValue ;
#Override
public void start(Stage primaryStage) {
ChoiceBox<Integer> choiceBox = new ChoiceBox<>();
choiceBox.getItems().add(nextValue);
choiceBox.setValue(nextValue);
choiceBox.showingProperty().addListener((obs, wasShowing, isNowShowing) -> {
if (isNowShowing) {
choiceBox.getItems().setAll(++nextValue, ++nextValue, ++nextValue);
}
});
BorderPane root = new BorderPane();
root.setTop(choiceBox);
BorderPane.setAlignment(choiceBox, Pos.CENTER);
root.setPadding(new Insets(5));
Scene scene = new Scene(root, 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
What i mean is, suppose on my current scene there appears a 'login" button. When the user will click the login button the same scene will appear but with a new button named "browse". Basically i want to keep the "browse" button hidden until user clicks "login" button.
You can use the setVisible() as stated by #Idos. You need to initially set the visibility of the Browse button to false and on the action of Login button toggle the visibility to true.
Here is a MCVE to help you understand how it works:
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
Button login = new Button("Login");
Button browse = new Button("Browse");
browse.setVisible(false);
login.setOnAction(e -> browse.setVisible(true));
VBox root = new VBox(10, login, browse);
root.setAlignment(Pos.CENTER);
Scene scene = new Scene(root, 300, 275);
primaryStage.setScene(scene);
primaryStage.show();
}
}
I have an internal jfxtra window. On clicking a button, I want to bring it forward.
The code that I have tried :
window w = new window("mdi win");
private Stage primaryStage;
private BorderPane rootLayout;
...
public void win() {
Parent bla = FXMLLoader.load(getClass().getResource("bla.fxml"));
w.getContentPane().getChildren().add(bla);
rootLayout.getChildren().add(w);
}
private void wfront(ActionEvent event) throws Exception {
w.isMoveToFront(); // is not?
}
How to make it possible?
So you made me curious and I went through the JFXtras docs. I came to know that Window in Jfxtras extends Control. So there is a method called toFront which can be fired on it. To show this I have created a sample for you.
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import jfxtras.scene.control.window.Window;
public class NewWindow extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
StackPane stackPane = new StackPane();
Button button = new Button("Click Me to show Window !");
Window window = new Window("Cick Me to bring me to front");
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
window.toFront();
window.setTitle("I am on the Front");
}
});
window.setPrefSize(200, 200);
stackPane.getChildren().addAll(window, button);
Scene scene = new Scene(stackPane, 500, 500);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Let me know, if you are looking for something else !
I did implement a popup window in a new stage and I'm now trying to close it, no matter where I click (excluding the popup itself). This works just fine. Although the popup windows disappears when I click on another element (e.g. a button) on the background, I'd still like to get the event for the button. Any suggestions on how to achieve this? I put together a short example of the situation.
package application;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
BorderPane root = new BorderPane();
Scene scene = new Scene(root, 400, 400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
// the popup
Pane p = new Pane();
p.setPrefSize(100, 100);
p.setStyle("-fx-background-color: #660066");
final Stage popUp = new Stage();
Scene popUpScene = new Scene(p);
popUp.setScene(popUpScene);
Button btnShow = new Button("Show popUp");
root.setCenter(btnShow);
btnShow.setOnMouseClicked(new EventHandler<Event>() {
#Override
public void handle(Event event) {
ChangeListener stageFocusListener = new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> arg0, Boolean oldPropertyValue, Boolean newPropertyValue) {
if (!newPropertyValue) {
popUp.hide();
}
}
};
popUp.focusedProperty().addListener(stageFocusListener);
popUp.show();
}
});
Button btnTest = new Button("test");
root.setRight(btnTest);
btnTest.setOnMouseClicked(new EventHandler<Event>() {
#Override
public void handle(Event event) {
System.out.println("Button test clicked");
}
});
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
You can put the hiding event to the queue without disturbing the event handling procedure of the button
if (!newPropertyValue) {
Platform.runLater(new Runnable() {
#Override
public void run() {
popUp.hide();
}
});
}