I have a simple JavaFX Application that open a Browser and shows google page. After exit the Application and free all objects, I can see that the JavaFX objects like Scene, Stage, WebView and WebEngine are alive in the heap memory after call GC.
I can see this objects with JProfiler and other Profiler tools.
This is my Test code:
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.stage.Stage;
import javax.swing.JButton;
import javax.swing.JFrame;
public class TestMemoryLeak
{
private Stage anotherStage;
private Application app;
public void initFrame()
{
JButton btnStart = new JButton("Start");
ActionListener a1 = new ActionListener() {
public void actionPerformed(ActionEvent e) {
Thread javaFxThread = new Thread(new Runnable() {
#Override
public void run() {
new JFXPanel();
Platform.runLater(new Runnable() {
#Override
public void run() {
try
{
app = MyApplication.class.newInstance();
anotherStage = new Stage();
app.start(anotherStage);
}
catch (Exception e)
{
e.printStackTrace();
}
}
});
}
});
javaFxThread.setDaemon(true);
javaFxThread.start();
}
};
btnStart.addActionListener(a1);
JButton btnStop = new JButton("Stop");
ActionListener a2 = new ActionListener() {
public void actionPerformed(ActionEvent e) {
Platform.runLater(new Runnable() {
public void run() {
try
{
anotherStage.close();
anotherStage = null;
app.stop();
Platform.exit();
}
catch (Exception e)
{
e.printStackTrace();
}
}
});
}
};
btnStop.addActionListener(a2);
JFrame frame = new JFrame();
frame.getContentPane().setLayout(new FlowLayout());
frame.getContentPane().add(btnStart);
frame.getContentPane().add(btnStop);
frame.setTitle("Memory Leak");
frame.setSize(300, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public static void main(String[] args)
{
new TestMemoryLeak().initFrame();
}
}
And my JavaFX Application:
import javafx.application.Application;
import javafx.geometry.HPos;
import javafx.geometry.VPos;
import javafx.scene.Scene;
import javafx.scene.layout.Region;
import javafx.scene.paint.Color;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
public class MyApplication extends Application {
private Scene scene;
#Override
public void start(Stage stage)
{
// create the scene
stage.setTitle("Web View");
scene = new Scene(new Browser(), 800, 600, Color.web("#666970"));
stage.setScene(scene);
stage.show();
}
}
class Browser extends Region {
WebView browser = new WebView();
WebEngine engine = browser.getEngine();
public Browser() {
// load the web page
engine.load("http://www.google.es");
//add the web view to the scene
getChildren().add(browser);
}
#Override
protected void layoutChildren() {
double w = getWidth();
double h = getHeight();
layoutInArea(browser,0,0,w,h,0, HPos.CENTER, VPos.CENTER);
}
}
To test the application click on Start Button to show google web page, click on Stop Button to stop the application, run a Profiler tool, and call gc, the JavaFX classes are alive.
I am using java version "1.7.0_51" and windows 8.1
Is there something wrong in my code? Or this is the normal behavior?
Thanks for your responses.
Related
my goal is to see the colorchange of the rectangle after every second ,after the Stage + Scene appears.
I researched and tried several things:
code under primaryStage.show() [look at my examplecode]
primaryStage.setOnShown() or primaryStage.setOnShowing()
EventHandler from Stage
EventHandler from Scene
Button with eventhandler
All in vain.
In most situation the stage comes, then the program performs the colorchange in the background (without visualization) and at last the scene appears with the endresult. Or version 2: I see nothing, the code goes through and in the end comes immediately the final result.
Here is my code:
package sample;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
GridPane gridPane = new GridPane();
Rectangle[] recs = new Rectangle[10];
for (int i = 0; i < recs.length; i++) {
recs[i] = new Rectangle(30, 30, Color.GREEN);
recs[i].setStroke(Color.BLACK);
gridPane.add(recs[i], i, 0);
}
primaryStage.setTitle("Code after primaryStage.show()");
primaryStage.setScene(new Scene(gridPane, 400, 300));
primaryStage.show();
for (Rectangle rec : recs) {
Thread.sleep(1000);
rec.setFill(Color.ORANGE);
}
}
public static void main(String[] args) {
launch(args);
}
}
The issue here is that your loop is running on the main application thread, so it locks any GUI updates until it's completed.
Perform the loop on its own thread instead and use Platform.runLater() to update each rectangle:
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
GridPane gridPane = new GridPane();
Rectangle[] recs = new Rectangle[10];
for (int i = 0; i < recs.length; i++) {
recs[i] = new Rectangle(30, 30, Color.GREEN);
recs[i].setStroke(Color.BLACK);
gridPane.add(recs[i], i, 0);
}
primaryStage.setTitle("Code after primaryStage.show()");
primaryStage.setScene(new Scene(gridPane, 400, 300));
primaryStage.show();
new Thread(() -> {
for (Rectangle rec :
recs) {
try {
Thread.sleep(1000);
Platform.runLater(() -> rec.setFill(Color.ORANGE));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
public static void main(String[] args) {
launch(args);
}
}
So What's Happening?
new Thread(() -> {
Opens up a new thread in the background of your application so that the UI remains responsive.
We can then start your loop within a try/catch block.
Platform.runLater(() -> rec.setFill(Color.ORANGE));
When working with a background thread, it's important to know that you cannot make changes to the UI directly. This line tells JavaFX to execute the rec.setFill() statement on the JavaFX Application thread.
.start();
You've already created the new Thread, this just starts it.
Here is another approach using TimeLine. Code from here.
import java.util.concurrent.atomic.AtomicInteger;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Main extends Application
{
#Override
public void start(Stage primaryStage) throws Exception
{
GridPane gridPane = new GridPane();
Rectangle[] recs = new Rectangle[10];
for (int i = 0; i < recs.length; i++) {
recs[i] = new Rectangle(30, 30, Color.GREEN);
recs[i].setStroke(Color.BLACK);
gridPane.add(recs[i], i, 0);
}
primaryStage.setTitle("Code after primaryStage.show()");
primaryStage.setScene(new Scene(gridPane, 400, 300));
primaryStage.show();
AtomicInteger counter = new AtomicInteger();
Timeline oneSecondsWonder = new Timeline(new KeyFrame(Duration.seconds(1), (ActionEvent event) -> {
System.out.println("this is called every 1 second on UI thread");
recs[counter.getAndIncrement()].setFill(Color.ORANGE);
}));
oneSecondsWonder.setCycleCount(recs.length);
oneSecondsWonder.play();
}
public static void main(String[] args)
{
launch(args);
}
}
I am trying to implement embedded browser in my java Netbeans project so far so good but still the browser is not sophisticated enough to store cookies or any advanced features my goal is basically to be able to access google account and check email or calendar or any similar operation.. can someone please direct me to the right code? thanks in advance.
here is my code:
import com.sun.javafx.application.PlatformImpl;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javafx.application.Platform;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeListener;
/**
* SwingFXWebView
*/
public class SwingFXWebView extends JPanel {
private Stage stage;
private WebView browser;
private JFXPanel jfxPanel;
private JButton swingButton;
private WebEngine webEngine;
public SwingFXWebView(){
initComponents();
}
public static void main(String ...args){
// Run this later:
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
final JFrame frame = new JFrame();
frame.getContentPane().add(new SwingFXWebView());
frame.setMinimumSize(new Dimension(640, 480));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
private void initComponents(){
jfxPanel = new JFXPanel();
createScene();
setLayout(new BorderLayout());
add(jfxPanel, BorderLayout.CENTER);
swingButton = new JButton();
swingButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Platform.runLater(new Runnable() {
#Override
public void run() {
webEngine.reload();
}
});
}
});
swingButton.setText("Reload");
add(swingButton, BorderLayout.SOUTH);
}
/**
* createScene
*
* Note: Key is that Scene needs to be created and run on "FX user thread"
* NOT on the AWT-EventQueue Thread
*
*/
private void createScene() {
PlatformImpl.startup(new Runnable() {
#Override
public void run() {
stage = new Stage();
stage.setTitle("Hello Java FX");
stage.setResizable(true);
Group root = new Group();
Scene scene = new Scene(root,80,20);
stage.setScene(scene);
// Set up the embedded browser:
browser = new WebView();
webEngine = browser.getEngine();
webEngine.load("https://www.google.com");
//https://calendar.google.com
ObservableList<Node> children = root.getChildren();
children.add(browser);
jfxPanel.setScene(scene);
}
});
}
}
Disclaimer: I am very new to Java, but I've been building .NET applications for 13 years.
I'm trying to build this Java application that does some basic calculations for tutoring. It's honestly not that big of a program, but I can't even get it to the Hello, World! state! I have a requirement that's making it difficult:
GUI should be built using javax.swing components jButton, jLabel, jTextField, jTextArea, jFrame, and jPanel.
So, I downloaded NetBeans 7.3 and created a JavaFX in Swing application. The default code obviously works but it uses Button instead of JButton:
private void createScene() {
Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("Hello World!");
}
});
StackPane root = new StackPane();
root.getChildren().add(btn);
fxContainer.setScene(new Scene(root));
}
so I when I change it to use a JButton I have to also change the type the root is built from. While banging my head against the wall I found an example here (not directly related) that used the JRootPane and I thought that might work in place of the StackPane. So I refactored the code like this:
private void createScene() {
JButton btn = new JButton();
btn.setText("Say 'Hello World'");
JRootPane root = new JRootPane();
root.getContentPane().add(btn);
fxContainer.setScene(new Scene(root));
}
and that code is fine except for fxContainer.setScene(new Scene(root)); because root isn't a Parent.
FYI, the application class implements JApplet and has a main and init that looks like this:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (Exception e) {
}
JFrame frame = new JFrame("Tutoring Calculator");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JApplet applet = new TutoringCalculator();
applet.init();
frame.setContentPane(applet.getContentPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
applet.start();
}
});
}
#Override
public void init() {
fxContainer = new JFXPanel();
fxContainer.setPreferredSize(new Dimension(JFXPANEL_WIDTH_INT, JFXPANEL_HEIGHT_INT));
add(fxContainer, BorderLayout.CENTER);
// create JavaFX scene
Platform.runLater(new Runnable() {
#Override
public void run() {
createScene();
}
});
}
How can I fulfill the requirement stated above? Am I really going about this whole thing the wrong way?
SSCCE
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package tutoringcalculator;
import java.awt.BorderLayout;
import java.awt.Dimension;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JRootPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
/**
*
* #author Owner
*/
public class TutoringCalculator extends JApplet {
private static final int JFXPANEL_WIDTH_INT = 300;
private static final int JFXPANEL_HEIGHT_INT = 250;
private static JFXPanel fxContainer;
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (Exception e) {
}
JFrame frame = new JFrame("Tutoring Calculator");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JApplet applet = new TutoringCalculator();
applet.init();
frame.setContentPane(applet.getContentPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
applet.start();
}
});
}
#Override
public void init() {
fxContainer = new JFXPanel();
fxContainer.setPreferredSize(new Dimension(JFXPANEL_WIDTH_INT, JFXPANEL_HEIGHT_INT));
add(fxContainer, BorderLayout.CENTER);
// create JavaFX scene
Platform.runLater(new Runnable() {
#Override
public void run() {
createScene();
}
});
}
private void createScene() {
JButton btn = new JButton();
btn.setText("Say 'Hello World'");
JRootPane root = new JRootPane();
root.getContentPane().add(btn);
fxContainer.setScene(new Scene(root));
}
}
This code works either as an applet or desktop app. here:
import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.*;
// <applet code=TutoringCalculator width=400 height=400></applet>
public class TutoringCalculator extends JApplet {
// The size of an applet is set by the HTML!
//private static final int JFXPANEL_WIDTH_INT = 300;
//private static final int JFXPANEL_HEIGHT_INT = 250;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Tutoring Calculator");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JApplet applet = new TutoringCalculator();
applet.init();
frame.setContentPane(applet.getContentPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
applet.start();
}
});
}
private JPanel swingContainer;
#Override
public void init() {
swingContainer = new JPanel(new BorderLayout());
add(swingContainer, BorderLayout.CENTER);
createScene();
}
private void createScene() {
JButton btn = new JButton();
btn.setText("Say 'Hello World'");
JRootPane root = new JRootPane();
root.getContentPane().add(btn);
swingContainer.add(root);
}
}
I could not be bothered figuring why you are using a RootPane so I left that as is.
Further tips
The spec. mentions JFrame but not JApplet. Since applets are significantly harder to develop, debug and deploy, I suggest you focus entirely on getting it working in a frame.
For frame positioning, you cannot go by setLocationByPlatform(true). See this answer for demo.
I am working on a swing application using JavaFX controls.
in this application i have three controls buttons WebView and JTable.
on clicking on button1 table should be added on the screen and web view should be removed while on clicking on other button
table should be removed and web view should be added.
I am using the following code.
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.web.*;
import javafx.stage.Stage;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Group;
import javax.swing.*;
import java.io.*;
import java.awt.*;
import java.awt.event.*;
public class webviewtestclass extends JFrame implements ActionListener {
JFXPanel fxpanel,fxpanel1;
static String filepath;
JTable table;
public webviewtestclass()
{
setLayout(null);
JButton b1= new JButton("OK");
JButton b2= new JButton("OKK");
add(b1);
add(b2);
b1.setBounds(20,50,50,30);
b2.setBounds(70,50,50,30);
b1.addActionListener(this);
b2.addActionListener(this);
fxpanel= new JFXPanel();
add(fxpanel);
fxpanel.setBounds(10,50,1000,800);
Object obj=new Object[50][20];
String title[]={"head1","head2"};
table=new JTable(title,obj);
add(table);
}
public void actionPerformed(ActionEvent ae)
{
if(ae.getActionCommand().equals("OK"))
{
remove(fxpanel);
add(table);
}
if(ae.getActionCommand().equals("OKK"))
{
remove(table);
add(fxpanel);
}
Platform.runLater(new Runnable() {
public void run()
{
initFx(fxpanel);
}}
);
}
private static void initFx(final JFXPanel fxpanel)
{
String htmlpath="d:/lcrux/html/";
Group group= new Group();
Scene scene= new Scene(group);
fxpanel.setScene(scene);
WebView webview = new WebView ();
group.getChildren().add(webview);
webview.setMinSize(1200,800);
webview.setMaxSize(1200,800);
webview.setVisible(true);
final WebEngine eng = webview.getEngine();
File htmlFile = new File(htmlpath+filepath);
try
{
eng.load(htmlFile.toURI().toURL().toString());
}
catch(Exception ex)
{
}
}
public static void main(final String args[])
{
webviewtestclass frm=new webviewtestclass();
frm.show();
}
}
Put both components in a CardLayout to swap between them. Code using a CardLayout can be seen in this answer.
I've recently completed a project in Java,and showed it to my advisor.
Forget about the detail about the project,my final output of the program is to simply output two webpages(one is translated by Google,the other is the Chinses webpage that I retrieved).
The two statements that I wrote are:
Process p=Runtime.getRuntime().exec("cmd /c start http://news.baidu.com/ns?word="+key1+"+"+keyy+"&bt=0&et=0&si=&rn=20&tn=newsA&ie=gb2312&ct=1&cl=2&f=12");
Process r=Runtime.getRuntime().exec("cmd /c start http://translate.google.cn/translate?u=http%3A%2F%2F"+u.substring(7)+"&sl=en&tl=zh-CN&hl=zh-CN&ie=UTF-8");
They will pop up two IE windows to show the webpage.
My advisor is satisfied with my result,but he is not happy with the output format.He would like to see these two webpages shown in a GUI window instead of IE windows.(Preferably with some panel seperating the two pages in this GUI).
I am just suddenly stuck on this point,how would I put those two webpages into a GUI frame in Java (in two seperate text boxes or sth. similar).
I am using Eclipse IDE.
Please kindly help ,either with ideas or code,thanks.
You would need a web browser component for the rendering of your HTML.
See the thread here for a list of possible browser component.
You can see nice screenshots on the The DJ Project web page as well.
It depends on what GUI toolkit you are using:
Swing - see ccheneson answer
SWT/JFrame - it has it's own browser component
I have used QT Webkit to do something similar to this before and it actually worked out extremely well.
http://qt.nokia.com/doc/qtjambi-4.4/html/com/trolltech/qt/qtjambi-index.html
If you want to access an HTTPS site using this method however it's a little more difficult to get it completely working.
JavaFX is the best option.It can work together with Swing.
package com.test.swing.pro;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javafx.application.Platform;
import javafx.collections.ObservableList;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebHistory;
import javafx.scene.web.WebView;
public class SwingJFxBrower {
private static WebEngine engine = null;
static JTextField urlText = null;
private static void initAndShowGUI() {
// This method is invoked on the EDT thread
JFrame frame = new JFrame("Swing and JavaFX : Browser");
JButton back = new JButton("<<<<");
JButton go = new JButton("Go");
back.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
goBack();
}
});
go.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
loadUrlCustom();
}
});
back.setPreferredSize(new Dimension(100, 25));
go.setPreferredSize(new Dimension(100, 25));
frame.add(back, BorderLayout.NORTH);
JLabel urlLabel = new JLabel("URL: ", JLabel.RIGHT);
urlText = new JTextField(100);
urlText.setPreferredSize(new Dimension(100, 25));
java.awt.Font font = new java.awt.Font("Courier", java.awt.Font.BOLD, 12);
urlText.setFont(font);
urlLabel.setPreferredSize(new Dimension(100, 25));
frame.add(urlLabel, BorderLayout.WEST);
frame.add(urlText, BorderLayout.CENTER);
frame.add(go, BorderLayout.EAST);
final JFXPanel jfxPanel = new JFXPanel();
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
jfxPanel.setPreferredSize(new Dimension(screenSize.width - 150, screenSize.height - 200));
frame.add(jfxPanel, BorderLayout.SOUTH);
frame.setLayout(new FlowLayout());
Platform.runLater(() -> {
WebView webView = new WebView();
jfxPanel.setScene(new Scene(webView));
engine = webView.getEngine();
loadUrl();
});
frame.setSize(300, 200);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setSize(screenSize.width - 100, screenSize.height - 150);
frame.setResizable(false);
centreWindow(frame);
}
private static void loadUrl() {
engine.load("https://duckduckgo.com/");
}
private static void loadUrlCustom() {
String url = (urlText.getText());
boolean validUrl = isValidURL(url);
if (validUrl) {
urlText.setBackground(java.awt.Color.WHITE);
urlText.setForeground(java.awt.Color.BLACK);
Platform.runLater(new Runnable() {
#Override
public void run() {
engine.load(url);
}
});
} else {
urlText.setBackground(java.awt.Color.RED);
urlText.setForeground(java.awt.Color.WHITE);
}
}
public static void goBack() {
try {
final WebHistory history = engine.getHistory();
Platform.runLater(new Runnable() {
public void run() {
try {
history.go(-1);
} catch (Exception ignore) {
}
}
});
} catch (Exception ignore) {
}
}
public static boolean isValidURL(String url) {
URL u = null;
try {
u = new URL(url);
} catch (MalformedURLException e) {
return false;
}
try {
u.toURI();
} catch (URISyntaxException e) {
return false;
}
return true;
}
public String goForward() {
final WebHistory history = engine.getHistory();
ObservableList<WebHistory.Entry> entryList = history.getEntries();
int currentIndex = history.getCurrentIndex();
Platform.runLater(new Runnable() {
public void run() {
history.go(1);
}
});
return entryList.get(currentIndex < entryList.size() - 1 ? currentIndex + 1 : currentIndex).getUrl();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
initAndShowGUI();
}
});
}
public static void centreWindow(Window frame) {
Dimension dimension = Toolkit.getDefaultToolkit().getScreenSize();
int x = (int) ((dimension.getWidth() - frame.getWidth()) / 2);
int y = (int) ((dimension.getHeight() - frame.getHeight()) / 2);
frame.setLocation(x, y);
}
}