JavaFX2: MODAL capability to a context menu - javafx-2

Is there a way to add MODAL capability to a context menu?
My code is below:
package snippet;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.ColorPicker;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
public class ContextMenuSample extends Application
{
public static void main(String[] args)
{
launch(args);
}
#Override
public void start(Stage stage)
{
stage.setTitle("ContextMenuSample");
Scene scene = new Scene(new Group(), 450, 250);
Label toLabel = new Label("To: ");
TextField notification = new TextField();
final ContextMenu contextMenu = new ContextMenu();
contextMenu.setAutoHide(false);
contextMenu.setOnShowing(new EventHandler<WindowEvent>()
{
public void handle(WindowEvent e)
{
System.out.println("showing the context menu");
}
});
contextMenu.setOnShown(new EventHandler<WindowEvent>()
{
public void handle(WindowEvent e)
{
System.out.println("context menu has been shown");
}
});
MenuItem closeItem = new MenuItem("Close");
closeItem.setOnAction(new EventHandler<ActionEvent>()
{
public void handle(ActionEvent e)
{
contextMenu.hide();
}
});
MenuItem colorItem = new MenuItem("Choose", new ColorPicker());
colorItem.setOnAction(new EventHandler<ActionEvent>()
{
public void handle(ActionEvent e)
{
System.out.println("Preferences");
}
});
GridPane contextGridPane = new GridPane();
Pane pane = new Pane();
pane.getChildren().add(contextGridPane);
contextMenu.getItems().addAll(colorItem, deleteItem// , subsystem1,
// radioItem
);
toLabel.setContextMenu(contextMenu);
GridPane grid = new GridPane();
grid.setVgap(4);
grid.setHgap(10);
grid.setPadding(new Insets(5, 5, 5, 5));
grid.add(toLabel, 0, 0);
grid.add(notification, 1, 0);
grid.add(new ColorPicker(), 2, 0);
Group root = (Group) scene.getRoot();
root.getChildren().add(grid);
stage.setScene(scene);
stage.show();
}
}
When the user clicks on the label "To", a context menu appears. I wish to have modal capability for this context menu such that the user is not able to do anything else on the application unless some operation is performed on the context menu. Also, when the context menu is active, the user should not be able to click anywhere else on the application.
Regards,

The easiest solution would be to call another Stage and set its modality with initModality before you show the stage. You probably want to use Modality.APPLICATION_MODEL as far as I understood you.
Here is a small example derived from yours (btw your code was not even runnable, it had errors)
public class ContextMenuSample extends Application
{
public static void main(String[] args)
{
launch(args);
}
#Override
public void start(final Stage stageOne)
{
final Stage stageTwo = new Stage();
stageTwo.initModality(Modality.APPLICATION_MODAL);
final Pane layoutOne = new HBox(10);
Pane layoutTwo = new HBox(10);
Label labelOne = new Label("click");
Label labelTwo = new Label("other click");
labelOne.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
stageTwo.show();
}
});
labelTwo.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
stageTwo.close();
}
});
Scene sceneOne = new Scene(layoutOne);
Scene sceneTwo = new Scene(layoutTwo);
layoutOne.getChildren().add(labelOne);
layoutTwo.getChildren().add(labelTwo);
stageOne.setScene(sceneOne);
stageTwo.setScene(sceneTwo);
stageOne.show();
}
}

Related

Change an Observable Collection (bound to JavaFX node) in thread

What is the correct way to manipulate an Observable collection in a thread, where the collection is already bound to a JavaFX UI-node?
In my sample application, the connection between the collection and the nodes are broken before the thread can do any manipulation; and then they are re-connected after the thread is done. The methods are disconnectObservable() and connectObservable() respectively. Without these two methods, java.lang.IllegalStateException: Not on FX application thread is reported.
Ideally I would like ChangeObservableTask to make its changes to mWords, and then I would call some method to tell mObservable to refresh itself and notify its listeners. Is there such a thing?
Thanks.
package theapp;
import java.util.LinkedList;
import java.util.List;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class ThreadObList extends Application {
private final List<String> mWords;
private final ObservableList<String> mObservable;
private ListView mListView;
private Label mCount;
public ThreadObList() {
mWords = new LinkedList<>();
mObservable = FXCollections.observableList(mWords);
mWords.add("park");
}
#Override
public void start(Stage primaryStage) {
Button btn = new Button();
btn.setText("Start thread");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
ChangeObservableTask task = new ChangeObservableTask();
Thread thd = new Thread(task);
disconnectObservable();
thd.start();
try {
task.get();
System.out.println("ChangeObservableTask exited normally.");
}
catch(Exception ex) {
System.out.println(ex.getMessage());
}
connectObservable();
}
});
mCount = new Label();
mListView = new ListView();
VBox root = new VBox(5, btn, mCount, mListView);
VBox.setVgrow(mListView, Priority.ALWAYS);
connectObservable();
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
private void connectObservable() {
mListView.setItems(mObservable);
mCount.textProperty().bind(Bindings.size(mObservable).asString());
}
private void disconnectObservable() {
mListView.setItems(null);
mCount.textProperty().unbind();
}
private class ChangeObservableTask extends Task<Void> {
#Override
protected Void call() throws Exception {
mObservable.add("dart");
mObservable.add("truck");
mObservable.add("ocean");
return null;
}
}
}
Once the list is used as the contents of the ListView, you can only manipulate it from the FX Application Thread. See the Task javadocs for a bunch of usage examples.
You can create a copy of your ObservableList and pass it to your task, manipulate the copy and return the results. Then update the ObservableList with the results in the onSucceeded handler.
Also note that you shouldn't make any blocking calls, such as task.get() on the FX Application Thread, as you can make the UI unresponsive by doing so.
So you should do something along the lines of:
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
ChangeObservableTask task = new ChangeObservableTask(new ArrayList<>(mObservable));
Thread thd = new Thread(task);
task.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
#Override
public void handle(WorkerStateEvent event) {
mObservable.setAll(task.getValue());
}
});
thd.start();
}
});
and
private class ChangeObservableTask extends Task<List<String>> {
private final List<String> data ;
ChangeObservableTask(List<String> data) {
this.data = data ;
}
#Override
protected List<String> call() throws Exception {
data.add("dart");
data.add("truck");
data.add("ocean");
return data;
}
}

Code is not working properly when row is clicked

Can you help me to fix this code. It's not working working properly as I expected.
package javafxapplication2;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.util.Callback;
class Person {
private StringProperty aliasName;
private StringProperty newPanelName;
private StringProperty newPanelDescription;
private ObservableList<Person> panels = FXCollections.observableArrayList();
public final void setAliasName(String value) {
aliasNameProperty().set(value);
}
public final String getAliasName() {
return aliasNameProperty().get();
}
public StringProperty aliasNameProperty() {
if (aliasName == null) {
aliasName = new SimpleStringProperty();
}
return aliasName;
}
public final void setNewPanelName(String value) {
newPanelNameProperty().set(value);
}
public final String getNewPanelName() {
return newPanelNameProperty().get();
}
public StringProperty newPanelNameProperty() {
if (newPanelName == null) {
newPanelName = new SimpleStringProperty();
}
return newPanelName;
}
public final void setNewPanelDescription(String value) {
newPanelDescriptionProperty().set(value);
}
public final String getNewPanelDescription() {
return newPanelDescriptionProperty().get();
}
public StringProperty newPanelDescriptionProperty() {
if (newPanelDescription == null) {
newPanelDescription = new SimpleStringProperty();
}
return newPanelDescription;
}
public ObservableList<Person> panelsProperty() {
return panels;
}
public Person(String alias, String newPanelName, String newPanelDescription) {
setAliasName(alias);
setNewPanelName(newPanelName);
setNewPanelDescription(newPanelDescription);
}
}
public class JavaFXApplication2 extends Application {
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(final Stage primaryStage) {
primaryStage.setTitle("test");
Group root = new Group();
Scene scene = new Scene(root, 500, 250, Color.WHITE);
// create a grid pane
GridPane gridpane = new GridPane();
gridpane.setPadding(new Insets(5));
gridpane.setHgap(10);
gridpane.setVgap(10);
ObservableList<Person> leaders = FXCollections.observableArrayList();
leaders.add(new Person("test 1", "test 11", "test 111"));
leaders.add(new Person("test 2", "test 22", "test 222"));
leaders.add(new Person("test 3", "test 33", "test 333"));
leaders.add(new Person("test 4", "test 44", "test 444"));
final ListView<Person> leaderListView = new ListView<>(leaders);
leaderListView.setPrefWidth(450);
leaderListView.setPrefHeight(150);
//
leaderListView.setCellFactory(new Callback<ListView<Person>, ListCell<Person>>() {
#Override
public ListCell<Person> call(ListView<Person> param) {
final Label leadLbl = new Label();
final Tooltip tooltip = new Tooltip();
final ListCell<Person> cell = new ListCell<Person>() {
#Override
public void updateItem(Person item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
leadLbl.setText(item.getAliasName());
setText(item.getNewPanelName());// + " " + item.getNewPanelDescription());
tooltip.setText(item.getAliasName());
setTooltip(tooltip);
}
}
}; // ListCell
return cell;
}
}); // setCellFactory
// Double click
leaderListView.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
if (mouseEvent.getButton().equals(MouseButton.PRIMARY)) {
if (mouseEvent.getClickCount() == 2) {
Person item = leaderListView.getSelectionModel().getSelectedItem();
if (item != null) {
StackPane pane = new StackPane();
Scene scene = new Scene(pane);
Stage stage = new Stage();
stage.setScene(scene);
pane.getChildren().add(new TextField(item.getAliasName()));
stage.show();
}
}
}
}
});
gridpane.add(leaderListView, 0, 1);
// Buttons
// Button "Open"
Button btnYes = new Button("Open");
btnYes.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent event)
{
leaderListView.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Person>() {
#Override
public void changed(ObservableValue<? extends Person> observable, Person oldValue, Person newValue) {
Person item = leaderListView.getSelectionModel().getSelectedItem();
if (item != null) {
StackPane pane = new StackPane();
Scene scene = new Scene(pane);
Stage stage = new Stage();
stage.setScene(scene);
pane.getChildren().add(new TextField(item.getAliasName()));
stage.show();
}
System.out.println("selection changed");
}
});
}
});
// Button "Cancel"
Button btnNo = new Button("Cancel");
btnNo.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent event)
{
primaryStage.close();
}
});
HBox hbox = new HBox();
hbox.setSpacing(10);
hbox.setAlignment(Pos.CENTER);
hbox.getChildren().add(btnYes);
hbox.getChildren().add(btnNo);
gridpane.add(hbox, 0, 2);
root.getChildren().add(gridpane);
primaryStage.setScene(scene);
primaryStage.show();
}
}
I want to select one row and then to open a new window when I click the button Select to open a new window. Can you help me to fix the code?
Replace the btnYes.setOnAction with the following :
btnYes.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
Person item = leaderListView.getSelectionModel().getSelectedItem();
if (item != null) {
StackPane pane = new StackPane();
Scene scene = new Scene(pane);
Stage stage = new Stage();
stage.setScene(scene);
pane.getChildren().add(new TextField(item.getAliasName()));
stage.show();
}
}
});
It should be this the action of the btnYes:
btnYes.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent event)
{
Person item = leaderListView.getSelectionModel().getSelectedItem();
if (item != null) {
StackPane pane = new StackPane();
Scene scene = new Scene(pane);
Stage stage = new Stage();
stage.setScene(scene);
pane.getChildren().add(new TextField(item.getAliasName()));
stage.show();
}
}
});
(there might be an axtra braket, just edited online.)
Also, this is exactly the same code as in the list doubleclick event, might want to put it in a diferent method, so that you dont repeat code:
public void openNewWindow(){
Person item = leaderListView.getSelectionModel().getSelectedItem();
if (item != null) {
StackPane pane = new StackPane();
Scene scene = new Scene(pane);
Stage stage = new Stage();
stage.setScene(scene);
pane.getChildren().add(new TextField(item.getAliasName()));
stage.show();
}

Background is not changed when I switch buttons

I want to implement this example: http://docs.oracle.com/javafx/2/ui_controls/toggle-button.htm#
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Toggle;
import javafx.scene.control.ToggleButton;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class test extends Application
{
private void init(Stage primaryStage)
{
Group root = new Group();
primaryStage.setScene(new Scene(root));
String pillButtonCss = DX57DC.class.getResource("PillButton.css").toExternalForm();
// create 3 toggle buttons and a toogle group for them
ToggleButton tb1 = new ToggleButton("Left Button");
tb1.setId("pill-left");
ToggleButton tb2 = new ToggleButton("Center Button");
tb2.setId("pill-center");
ToggleButton tb3 = new ToggleButton("Right Button");
tb3.setId("pill-right");
final ToggleGroup group = new ToggleGroup();
tb1.setToggleGroup(group);
tb2.setToggleGroup(group);
tb3.setToggleGroup(group);
// select the first button to start with
group.selectToggle(tb1);
//////////////////////////////////////////
tb1.setUserData(Color.LIGHTGREEN);
tb2.setUserData(Color.LIGHTBLUE);
tb3.setUserData(Color.SALMON);
final Rectangle rect = new Rectangle(300, 300);
group.selectedToggleProperty().addListener(new ChangeListener<Toggle>()
{
#Override
public void changed(ObservableValue<? extends Toggle> ov,
Toggle toggle, Toggle new_toggle)
{
if (new_toggle == null)
{
rect.setFill(Color.WHITE);
}
else
{
rect.setFill(
(Color) group.getSelectedToggle().getUserData());
}
}
});
///////////////////////////////////////////
rect.setArcHeight(10);
rect.setArcWidth(10);
HBox hBox = new HBox();
hBox.getChildren().addAll(tb1, tb2, tb3);
hBox.setPadding(new Insets(20, 20, 260, 20));
hBox.getStylesheets().add(pillButtonCss);
VBox vbox = new VBox();
vbox.getChildren().add(hBox);
vbox.getChildren().add(rect);
root.getChildren().add(vbox);
}
#Override
public void start(Stage primaryStage) throws Exception
{
init(primaryStage);
primaryStage.show();
}
public static void main(String[] args)
{
launch(args);
}
}
But for some reason I can see the buttons but the rectangle is not displayed when I try to switch the buttons. Can you help me to find where is my mistake? And also how I can implement this example with several rectangles holding different content?
You have to add rect to your scene graph :
root.getChildren().addAll(hBox, rect);
Also, think of using an appropriate layout for your root, BorderPane instead of Group for example.

How to show and hide a window in JavaFX 2?

Need to show an example in which you show and hide a window in JavaFX 2.
A stage is a window in javafx-2. It provide the hide and show methods:
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class HideShowApp extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
final Stage window = new Stage();
window.setX(10);
Scene innerScene = new Scene(new Label("inner window"));
window.setScene(innerScene);
HBox root = new HBox(10d);
Button showButton = new Button("show");
showButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
window.show();
}
});
Button hideButton = new Button("hide");
hideButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
window.hide();
}
});
root.getChildren().add(showButton);
root.getChildren().add(hideButton);
stage.setScene(new Scene(root));
stage.show();
}
}

To Hide JavaFx fxml or JavaFx swing application to System Tray

I want to develop a client app for website .
I want the app to reside in system tray when minimised.
I dont know how to accomplish this task .
Is their any example for this type of operation.
The key here is to set the implicit exit to false Platform.setImplicitExit(false);
Also is important to show and hide the stage in a new thread.
Platform.runLater(new Runnable() {
#Override
public void run() {
stage.show();
}
});
Platform.runLater(new Runnable() {
#Override
public void run() {
stage.hide();
}
});
Next, the whole code:
import java.awt.AWTException;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.TrayIcon;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.URL;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import javax.imageio.ImageIO;
/**
*
* #author alvaro
*/
public class TrayTest extends Application {
private boolean firstTime;
private TrayIcon trayIcon;
public static void main(String[] args)
{
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
createTrayIcon(stage);
firstTime = true;
Platform.setImplicitExit(false);
Scene scene = new Scene(new Group(), 800, 600);
stage.setScene(scene);
stage.show();
}
public void createTrayIcon(final Stage stage) {
if (SystemTray.isSupported()) {
// get the SystemTray instance
SystemTray tray = SystemTray.getSystemTray();
// load an image
java.awt.Image image = null;
try {
URL url = new URL("http://www.digitalphotoartistry.com/rose1.jpg");
image = ImageIO.read(url);
} catch (IOException ex) {
System.out.println(ex);
}
stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent t) {
hide(stage);
}
});
// create a action listener to listen for default action executed on the tray icon
final ActionListener closeListener = new ActionListener() {
#Override
public void actionPerformed(java.awt.event.ActionEvent e) {
System.exit(0);
}
};
ActionListener showListener = new ActionListener() {
#Override
public void actionPerformed(java.awt.event.ActionEvent e) {
Platform.runLater(new Runnable() {
#Override
public void run() {
stage.show();
}
});
}
};
// create a popup menu
PopupMenu popup = new PopupMenu();
MenuItem showItem = new MenuItem("Show");
showItem.addActionListener(showListener);
popup.add(showItem);
MenuItem closeItem = new MenuItem("Close");
closeItem.addActionListener(closeListener);
popup.add(closeItem);
/// ... add other items
// construct a TrayIcon
trayIcon = new TrayIcon(image, "Title", popup);
// set the TrayIcon properties
trayIcon.addActionListener(showListener);
// ...
// add the tray image
try {
tray.add(trayIcon);
} catch (AWTException e) {
System.err.println(e);
}
// ...
}
}
public void showProgramIsMinimizedMsg() {
if (firstTime) {
trayIcon.displayMessage("Some message.",
"Some other message.",
TrayIcon.MessageType.INFO);
firstTime = false;
}
}
private void hide(final Stage stage) {
Platform.runLater(new Runnable() {
#Override
public void run() {
if (SystemTray.isSupported()) {
stage.hide();
showProgramIsMinimizedMsg();
} else {
System.exit(0);
}
}
});
}
}
As far as I know it will be possible in JFX 8. Right now the best solution is to embed your application into AWT and hide the AWT window itself.

Resources