I am making a JavaFX app. I have create a Menuitem About. Upon clicking on the About Menuitem it will display a new window with some info about my app. The window is a Anchor Pane with custom close button. I have set the stage undercoated at run time. I want to close this window without closing my main application. I don't want to set its visibility turn off on method call. I see some solution in net like Window existingWindow = ((Node) event.getSource()).getScene().getWindow(); but i can't use this as am getting error similar to this Menu item not cast node javafx scene. How can I achieve this goal?
Actually this is not my own answer, but I managed to understand #James_D. I usually create to manage open windows, otherwise I have to write a lot of code And this is solution code.
In your controller class:
#FXML
void openAnotherWindow(ActionEvent actionEvent) {
try {
OpenWindow.openWindowMenuItem(someLabel, "views/some.fxml", "Title", 600, 400,
false, "resources/pictures/some_icon.png");
} catch (IOException e) {
e.printStackTrace();
}
}
And OpenWindow class
public class OpenWindow {
public static void openWindowMenuItem(Node label, String recource, String title,
int width, int height, boolean resizeable, String icon) throws IOException {
Parent root = FXMLLoader.load(Objects.requireNonNull(OpenWindow.class.getClassLoader().getResource(recource)));
Stage stage = new Stage();
Scene scene = new Scene(root, width, height);
if (icon != null) {
stage.getIcons().add(new Image(icon));
}
stage.setTitle(title);
stage.setResizable(resizeable);
stage.setScene(scene);
stage.show();
// close current window
label.getScene().getWindow().hide(); // this is key point
}
}
You can do it event without extra class. Hope it will help and again thanks to #James_D
Related
When reading javafx 8 tutorials, this seems to be the main work flow:
public class Test extends Application{
public static void main(String[] args){
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader fxmlLoader = new FXMLLoader(TestFXController.class.getResource("test.fxml"));
Parent root;
try {
root = fxmlLoader.load();
Scene scene = new Scene(root, 1200, 800);
primaryStage.setScene(scene);
primaryStage.show();
TestFXController controller = fxmlLoader.getController();
controller.plotSomething();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Let's say that I have an Algorithm which I want to run. After starting the above application I may end up with an interface containing a "run algorithm" button. After pressing the button, an action handler invokes the algorithm.
I then have: start java application -> build interface -> press button to solve Algorithm -> display solution. All that separates the graphical stuff from the algorithm is a button. In fact, the graphical interface 'drives' the application in the sense that it is responsible for launching the algorithm.
What I would prefer however is something like this:
public class Test2{
public void main(String[] args){
Algorithm alg=new Algorithm();
alg.solve();
GUI gui =new GUI(); //Spawns a Javafx 8 Graphical User Interface
gui.displaySolution(alg.getSolution());
}
}
To me, this seems a lot cleaner? I'm however not sure how to do this with javafx 8, or whether this is even possible? Any examples or references are highly appreciated. What should I put in the GUI class such that it launches a javafx 8 interface?
The example in Test2 would also open up possibilities to use a clean Observer Design Pattern like this:
public class Test3{
public void main(String[] args){
Algorithm alg=new Algorithm();
alg.addListener(new GUI()); //Add a Javafx 8 GUI as a listener.
alg.addListener(new TextualLogger());
alg.solve();
}
}
Notice that in the classes Test2 and Test3, the GUI no longer drives the application.
To clarify, my main question would be: what should be the implementation of the GUI class if I would run the code in Test2? Something like this:
public class GUI extends Application{
public GUI(){
//What should I put here? Perhaps launch(new String[]); ?
}
#Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader fxmlLoader = new FXMLLoader(TestFXController.class.getResource("test.fxml"));
Parent root;
try {
root = fxmlLoader.load();
Scene scene = new Scene(root, 1200, 800);
primaryStage.setScene(scene);
primaryStage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
public void displaySolution(Solution sol){
...
}
}
In a JavaFX application, you should think of the start(...) method essentially as the equivalent of the main(...) method in a "regular" Java application. (In fact, in Java 8, a JavaFX application does not need a main(...) method at all.) This mechanism for launching a JavaFX application was introduced in order to force the programmer, as much as possible, to initialize the UI on the correct thread (in comparison to Swing, where there is a large amount of code published which launches the GUI incorrectly). For convenience, the start(...) method is passed an initial stage, but there is no requirement for you to use it if you prefer to use a different one.
So you can just do
public class Test2 extends Application {
#Override
public void start(Stage primaryStage) {
Algorithm alg = new Algorithm();
alg.solve();
GUI gui = new GUI();
gui.displaySolution(alg.getSolution());
}
// included for the benefit of IDEs that do not support
// launching an Application without a main method:
public static void main(String[] args) { launch(args); }
}
and now GUI is not an Application subclass (which makes sense, because it represents the GUI, not an application):
public class GUI {
public GUI(){
FXMLLoader fxmlLoader = new FXMLLoader(TestFXController.class.getResource("test.fxml"));
Parent root;
try {
root = fxmlLoader.load();
Scene scene = new Scene(root, 1200, 800);
Stage stage = new Stage();
stage.setScene(scene);
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
public void displaySolution(Solution sol){
...
}
}
One thing to bear in mind here is that start(...) is executed on the FX Application Thread. Consequently, once you have shown the UI, any further long-running processes that need to be performed should be executed on background threads. In the use-case you've described, all the heavy lifting is done before you show the UI, so this is not an issue, but you may need to consider this if you try to extend this pattern at all.
I am not sure I follow exactly what you are attempting to do - are you trying to open a second JavaFX Window?
Would something like this work?
Scene resultScene = algorithm.getSolution();
Stage resultStage = new Stage();
resultStage.setScene(resultScene);
resultStage.addEventHandler() or addEventFilter()
resultStage.show();
This stage can be it's own window or a child of the primaryStage so that if you close the parent, it will also close.
If you really want to open second JavaFX window from one already running. You can visit.
Launch JavaFX application from another class
It will solve your issue.
below is the code how to run new JavaFx Application
Platform.runLater(new Runnable(){
#Override
public void run(){
new MainApp().start(new Stage()); // MainApp is the class name of your second Application
}
});
Make your class extend Application and Implement Runnable and add below mention code in that class
#Override
public void run(){
launch();
}
launch() method will be called from run() method. Do not use Main() method in the second class, else it with throw exception.
I'm facing an issue with JavaFX 8u40 where creating two or more modal windows will cause a system beep on Mac OS X when closing the children windows.
The example below creates a modal window who's a child of another modal window. When I close the child modal window, my system beeps (the same way it beeps if I try to click on the parent modal window).
The problem seems related to stage.initOwner(...) where closing the child modal window tries to access the parent modal window before the showAndWait() loop is finished.
I just want to confirm I'm not doing anything wrong before filing a bug report.
public class TestDialog extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
Button showModalButton = new Button("Show Modal Window");
showModalButton.setOnAction(e -> {
Stage modalStage = new Stage();
modalStage.initModality(Modality.WINDOW_MODAL);
modalStage.initOwner(stage);
Button createInnerModalButton = new Button("Create inner modal window");
createInnerModalButton.setOnAction(e2 -> {
Stage innerModalStage = new Stage();
innerModalStage.initModality(Modality.WINDOW_MODAL);
innerModalStage.initOwner(modalStage);
Button closeInnerModalButton = new Button("Close");
closeInnerModalButton.setOnAction(e3 -> {
innerModalStage.close();
});
VBox innerVBox = new VBox(
new Label("This is an inner modal window"), closeInnerModalButton);
innerModalStage.setScene(new Scene(innerVBox));
innerModalStage.showAndWait();
});
VBox vBox = new VBox(
new Label("This is a modal window"), createInnerModalButton);
modalStage.setScene(new Scene(vBox));
modalStage.showAndWait();
});
stage.setScene(new Scene(showModalButton));
stage.show();
}
}
I am developing a desktop application in which I want Admin have option to delete users, for which I planned that whenever Admin clicks on 'delete users' button a new tab will open in which check boxes with the name of all existing users in my database should appear(so that he can delete multiple users simultaneously); so basically I need to generate dynamic check boxes as per my database.
I am using Netbeans 7.0.1, jdk 1.6, sqlite3.
After searching on google I got two links which match to my problem:
http://www.coderanch.com/t/345949/GUI/java/create-dynamic-checkboxes#2805277
Creating dcheckbox dynamically in Java-NetBeans
I have tried to follow the code from above first link but it does not working for me properly. What I does is just created new JFrame in netbeans and called a method inside constructor which create checkboxes as per needed, method's code is as below:
public class Work extends javax.swing.JFrame {
/** Creates new form Work */
public Work() {
initComponents();
checks = new java.util.ArrayList<>();
createCheckboxes();
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 400, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 300, Short.MAX_VALUE)
);
pack();
}// </editor-fold>
private void createCheckboxes(){
panel = new javax.swing.JPanel();
this.add(panel);
for(int i = 0; i<4; i++){
javax.swing.JCheckBox box = new javax.swing.JCheckBox("check"+i);
panel.add(box);
checks.add(box);
panel.revalidate();
panel.repaint();
}
panel.setVisible(true);
}
public static void main(String args[]) {
/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(Work.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(Work.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(Work.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(Work.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new Work().setVisible(true);
}
});
}
// Variables declaration - do not modify
// End of variables declaration
private java.util.ArrayList <javax.swing.JCheckBox> checks;
private javax.swing.JPanel panel;
}
The output is just a blank frame. Please help me to know where I am wrong!!
And yes this code is not connected to database yet, once it will work then I can modify it to work with database.
Also is their any other betterway to accomplish my task or am on right path?`
I think it might help if u call the following function whenever to wanna create a new checkbox..
public class CheckBox extends JFrame{
//private static final long serialVersionUID = 1L;
public CheckBox() {
// set flow layout for the frame
this.getContentPane().setLayout(new FlowLayout(FlowLayout.TRAILING, 50, 20)); //(default) centered alignment and a default 5-unit horizontal and vertical gap.
JCheckBox checkBox1 = new JCheckBox("Checkbox 1");
checkBox1.setSelected(true);
JCheckBox checkBox2 = new JCheckBox("Checkbox 2", true);
JCheckBox checkBox3 = new JCheckBox("Checkbox 3");
// add checkboxes to frame
add(checkBox1);
add(checkBox2);
add(checkBox3);
}
private static void createAndShowGUI() {
//Create and set up the window.
//JFrame frame = new CreateCheckedUncheckedJCheckBox();
CheckBox cb = new CheckBox();
//Display the window.
cb.pack();
cb.setVisible(true);
cb.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowGUI();
}
});
}
}
You add the new checkboxes as if your frame was using some simple layout such as FlowLayout, but it is not - it is using GroupLayout - see the generated initComponents() method.
If you want to handle ALL components in the frame dynamically, you can do this (it is better to create an empty class file and then paste the code below; do not ask NB to create a JFrame as it would again create a form to be designed in the visual designer; if you still do it then r-click it and change the layout to something simpler):
public class Work extends javax.swing.JFrame {
private java.util.List <javax.swing.JCheckBox> checks = new java.util.ArrayList<>();;
public Work() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new java.awt.FlowLayout()); // simply put the components next to each other
createCheckboxes();
}
private void createCheckboxes(){
for(int i=0; i<4; i++) {
javax.swing.JCheckBox box = new javax.swing.JCheckBox("check"+i);
add(box);
checks.add(box);
}
pack(); // this will tell the JFrame's panel to layout all the components
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new Work().setVisible(true);
}
});
}
}
Or you can design part of your frame with the visual designer and then add the checkboxes. In that case add an empty panel in the designer, set the panel's layout to something like flow or grid layout and then add the checkboxes to that panel from your code in the same way as above.
You validate needs to be called only if the panel/frame is already visible. Calling pack works even then, but might change the size of the frame. Also validating can be done after all components were added not after adding each one.
To add check boxes or any other component dynamically in Netbeans JFrame one need to manage Layout Managers, by default netbeans frames use Free Design Layout, follow steps below:
Create blank JFrame -->Add Jpanel to it-->right click to the panel, select setLayout and change it to GridLayout.
Now we are free to add ant components on this panel.
Also don't forgate to add revalidate() and repaint() methods.
This worked for me.
I'm trying to add new widgets on an RPC view by clicking on an existing button. The code that I'm using is the following:
public void createPartControl(final Composite parent) {
parent.setLayout(new RowLayout(SWT.HORIZONTAL));
Button btnNewButton = new Button(parent, SWT.NONE);
btnNewButton.setText("New Button");
btnNewButton.addMouseListener(new MouseAdapter() {
#Override
public void mouseDown(MouseEvent e) {
Button b=new Button(parent,SWT.BUTTON1);
b.setText("asdasd");
}
});
}
The buttons are getting added on the view but are not visible. If I resize the view then they become visible. Why is this happening and how can it be solved?
I need somehow to refresh the view or call the event that the resize action calls.
The attached code works without problems in standard java applications.
Thank you,
Nick
Call the layout method of your parent Composite when you add a widget:
btnNewButton.addMouseListener(new MouseAdapter() {
#Override
public void mouseDown(MouseEvent e) {
Button b=new Button(parent,SWT.BUTTON1);
b.setText("asdasd");
parent.layout();
}
});
I am developing an Eclipse plug-in that has currently 2 views. In my first view I have a list of connections displayed in a TableViewer (name and connection status).In my second view I want to load the tables in a database (the connection). This loading will be done by clicking a menu item on a connection ("view details"). These tables will be displayed in a TreeViewer because they can also have children. I have tried to do it this way:
My View class:
public class DBTreeView extends ViewPart {
private TreeViewer treeViewer;
private Connection root = null;
public DBTreeView() {
Activator.getDefault().setDbTreeView(this);
}
public void createPartControl(Composite parent) {
treeViewer = new TreeViewer(parent);
treeViewer.setContentProvider(new DBTreeContentProvider());
treeViewer.setLabelProvider(new DBTreeLabelProvider());
}
public void setInput(Connection conn){
root = conn;
treeViewer.setInput(root);
treeViewer.refresh();
}
}
I made a setInput method that is called from the action registered with the menu item in the connections view with the currently selected connection as argument:
MViewContentsAction class:
public void run(){
selectedConnection = Activator.getDefault().getConnectionsView().getSelectedConnection();
Activator.getDefault().getDbTreeView().setInput(selectedConnection);
}
In my ContentProvider class:
public Object[] getChildren(Object arg0) {
if (arg0 instanceof Connection){
return ((Connection) arg0).getTables().toArray();
}
return EMPTY_ARRAY;
}
where EMPTY_ARRAY is an...empty array
The problem I'm facing is that when in debug mode, this piece of code is not executed somehow:
Activator.getDefault().getDbTreeView().setInput(selectedConnection);
And also nothing happens in the tree view when clicking the menu item. Any ideas?
Thank you
Huh. Ok, what you're doing here is.. not really the right way. What you should be doing is registering your TableViewer as a selection provider.
getSite().setSelectionProvider(tableViewer);
Then, define a selection listener and add it to the view with the tree viewer like this:
ISelectionListener listener = new ISelectionListener() {
public void selectionChanged(IWorkbenchPart part, ISelection sel) {
if (!(sel instanceof IStructuredSelection))
return;
IStructuredSelection ss = (IStructuredSelection) sel;
// rest of your code dealing with checking whether selection is what is
//expected and if it is, setting it as an input to
//your tree viewer
}
};
public void createPartControl(Composite parent) {
getSite().getPage().addSelectionListener(listener);
}
Now your tree viewer's input will be changed according to what is selected in the table viewer (btw, don't forget to call treeviewer.refresh() after you set new input).
See an example here.