Java Swing to JavaFX (RMI/Threads) - java

Currently teaching myself advanced object programming and I've hit a snag when trying to write a Javafx solution to a given Swing solution.
The problem was to develop an RMI program with Polling. I have the Swing version working perfectly, and I believe I've narrowed the problem down this section of code.
Swing
public static void main(String args[])
{
java.awt.EventQueue.invokeLater(new Runnable() {
public void run()
{
new PollClient().setVisible(true);
}
});
}
JavaFx
public static void main(String args[])
{
Platform.runLater(new Runnable(){
#Override
public void run()
{
launch(args);
}
});
}
Any advice would be appreciated.

Platform.runLater specifies in its documentation that it executed on the JavaFX application thread at an unspecified time in the future. For this thread to exist you must first launch your application.
This means that since the application isnt launched the action to launch the application is never executed.
Regardless, JavaFX should be launched from within the main function, no need to insert a delay:
Application.launch(PollClient.class, args)

Related

Fullscreen JavaFX program in the same desktop with other applications?

I'm making a fullscreen JavaFX program, but I want it to run as a screensaver in the background with other applications simultaneously running on top of it. Right now, it automatically creates a separate desktop just for the program. Any solutions?
Swing is definitely an option. Here is a place to start:
public class MyClass {
public void myAction () {
// your logic goes here
System.out.println("hello");
}
public static void main(String[] args) {
MyClass mc = new MyClass();
mc.myAction();
}
}

Cannot make use of a .jar file if it has more than one thread

When I create a .jar file and the program only uses the main thread then everything is fine but when I need concurrency and add my own thread the .jar file does not open or run one I double click it.
Here is an Example:
class idk {
public static void main(String args[]) throws Exception {
new Thread(new Runnable() {
public void run() {
try {
JFrame j = new JFrame();
j.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
j.setVisible(true);
j.getContentPane().setPreferredSize(new Dimension(800, 500);
j.pack();
j.setLocationRelativeTo(null);
} catch(Exception e1) {}
}
}).start();
}
}
The above code will not execute for some reason when compiled into a .jar file.
However if I just used the same code but left out the thread it works just fine.
You must only ever use one thread, Swing's event dispatching thread (EDT), to interact with UI components. Create your main window with this code:
SwingUtilities.invokeLater(new Runnable() { ... } );
Concurrency in the application should be done using the SwingWorker objects, and the publish method, if they need to interact with the UI.
Creating your own Threads and creating or using Swing components from those threads will cause you grief.
See Concurrency in Swing

Javafx - Exception in thread "main" java.lang.ExceptionInInitializerError [duplicate]

My application is Swing-based. I would like to introduce JavaFX and configure it to render a Scene on a secondary display.
I could use a JFrame to hold a JFXPanel which could hold a JFXPanel but I would like to achieve this with JavaFX API.
Subclassing com.sun.glass.ui.Application and using Application.launch(this) is not an option because the invoking thread would be blocked.
When instantiating a Stage from Swing EDT, the error I get is:
java.lang.IllegalStateException: Toolkit not initialized
Any pointers?
EDIT: Conclusions
Problem: Non-trivial Swing GUI application needs to run JavaFX components. Application's startup process initializes the GUI after starting up a dependent service layer.
Solutions
Subclass JavaFX Application class and run it in a separate thread e.g.:
public class JavaFXInitializer extends Application {
#Override
public void start(Stage stage) throws Exception {
// JavaFX should be initialized
someGlobalVar.setInitialized(true);
}
}
Sidenote: Because Application.launch() method takes a Class<? extends Application> as an argument, one has to use a global variable to signal JavaFX environment has been initialized.
Alternative approach: instantiate JFXPanel in Swing Event Dispatcher Thread:
final CountDownLatch latch = new CountDownLatch(1);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new JFXPanel(); // initializes JavaFX environment
latch.countDown();
}
});
latch.await();
By using this approach the calling thread will wait until JavaFX environment is set up.
Pick any solution you see fit. I went with the second one because it doesn't need a global variable to signal the initialization of JavaFX environment and also doesn't waste a thread.
Found a solution. If I just create a JFXPanel from Swing EDT before invoking JavaFX Platform.runLater it works.
I don't know how reliable this solution is, I might choose JFXPanel and JFrame if turns out to be unstable.
public class BootJavaFX {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new JFXPanel(); // this will prepare JavaFX toolkit and environment
Platform.runLater(new Runnable() {
#Override
public void run() {
StageBuilder.create()
.scene(SceneBuilder.create()
.width(320)
.height(240)
.root(LabelBuilder.create()
.font(Font.font("Arial", 54))
.text("JavaFX")
.build())
.build())
.onCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent windowEvent) {
System.exit(0);
}
})
.build()
.show();
}
});
}
});
}
}
Since JavaFX 9, you can run JavaFX application without extending Application class, by calling Platform.startup():
Platform.startup(() ->
{
// This block will be executed on JavaFX Thread
});
This method starts the JavaFX runtime.
The only way to work with JavaFX is to subclass Application or use JFXPanel, exactly because they prepare env and toolkit.
Blocking thread can be solved by using new Thread(...).
Although I suggest to use JFXPanel if you are using JavaFX in the same VM as Swing/AWT, you can find more details here: Is it OK to use AWT with JavaFx?
I checked the source code and this is to initialize it
com.sun.javafx.application.PlatformImpl.startup(()->{});
and to exit it
com.sun.javafx.application.PlatformImpl.exit();
I used following when creating unittests for testing javaFX tableview updates
public class testingTableView {
#BeforeClass
public static void initToolkit() throws InterruptedException
{
final CountDownLatch latch = new CountDownLatch(1);
SwingUtilities.invokeLater(() -> {
new JFXPanel(); // initializes JavaFX environment
latch.countDown();
});
if (!latch.await(5L, TimeUnit.SECONDS))
throw new ExceptionInInitializerError();
}
#Test
public void updateTableView() throws Exception {
TableView<yourclassDefiningEntries> yourTable = new TableView<>();
.... do your testing stuff
}
}
even though this post is not test related, then it helped me to get my unittest to work
without the BeforeClass initToolkit, then the instantiation of TableView in the unittest would yield a message of missing toolkit
There's also way to initialize toolkit explicitly, by calling:
com.sun.javafx.application.PlatformImpl#startup(Runnable)
Little bit hacky, due to using *Impl, but is useful, if you don't want to use Application or JXFPanel for some reason.
re-posting myself from this post
private static Thread thread;
public static void main(String[] args) {
Main main = new Main();
startup(main);
thread = new Thread(main);
thread.start();
}
public static void startup(Runnable r) {
com.sun.javafx.application.PlatformImpl.startup(r);
}
#Override
public void run() {
SoundPlayer.play("BelievexBelieve.mp3");
}
This is my solution. The class is named Main and implements Runnable. Method startup(Runnable r) is the key.
Using Jack Lin’s answer, I found that it fired off the run() twice. With a few modifications that also made the answer more concise, I offer the following;
import com.sun.javafx.application.PlatformImpl;
public class MyFxTest implements Runnable {
public static void main(String[] args) {
MyFxTest main = new MyFxTest();
PlatformImpl.startup((Runnable) main);
}
#Override
public void run() {
// do your testing;
System.out.println("Here 'tis");
System.exit(0); // Optional
}
}

Show popup at the start if file is missing

I am creating a small GUI java application that it will store some user credentials in a file.
If the file is missing or has the wrong properties then I want a pop to get brought up that will inform the user to register his credentials (so a new file can be created with the proper ones).
I have nailed down the logic of when the file is incorrect and/or missing but what I can't figure out (due to my inexperience with JFrame) is where exactly in the code to check if the user needs to enter his credentials so he can be prompted.
Let's say that the function showWarning() is the one that will check and display the popup if needed and this is my main JFrame function (this was generated from Netbeans mostly):
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new GUI().setVisible(true);
}
});
}
Do I put the showWarning() function inside the main function? If yes, do I put it right after new GUI().setVisible(true);? What is the proper way of doing this?
EDIT: I am stumbling to the same problem I did before. This is my showWarning() that I drafted quickly for testing purposes:
public void showWarning(){
File propertiesFile = new File("config.properties");
if (propertiesFile.exists() && propertiesExist(propertiesFile)) {
JOptionPane.showMessageDialog(rootPane, "Creds are ok");
} else {
JOptionPane.showMessageDialog(rootPane, "Creds are not ok");
}
}
The problem that I am having is that I can't make this method static in order to use it without an object because of the rootPane which is a non-static object. The problem that this caused is that I can't just write:
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new GUI().setVisible(true);
showWarning();
}
});
}
I can't use showWarning() like that since it's a non-static method.
Do I need to have the GUI object in a variable properly or is there a way to make the showWarning() a static method?
If you want the check to run right when the program starts, you would want to put your function call after the main JFrame gui is set visible. See edited code below. Of course, I'm using the ambiguous showWarning() function here, but you should talor that line of code to your need. If calling a function, then right the function, but if wanting to call a new popup jframe you will need to do more lines of code there.
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new GUI().setVisible(true);
LoginForm login = new LoginForm();
login.setVisible(true);
}
});
}
Now here you would want to change the variables accordingly. The LoginForm is a Jframe already created.
You probably want your popup dialog to be modal, so the program does not continue until the user has handled and fixed the problem. To do this, do not use a JFrame but a JDialog for your popup dialog and make it modal. Then you can simply put the showWarning() call everywhere you want. I think I would put it inside the main.
Use JDialog for creating the pop up.
And either you add the showWarning() method call in main like this :
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new GUI().setVisible(true);
showWarning();
}
});
}
or better you can invoke the method showWarning() when the user credentials have to be enetered in the file. If checked just before it, it would be optimal.

Weird thing with GUI and Threads in java

Given the following code:
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
ClientGUI gui = new ClientGUI();
gui.start();
}
});
}
everything works fine, I get a nice GUI window. OK.
Now, lets add an infinite loop after gui.start() :
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
ClientGUI gui = new ClientGUI();
gui.start();
while (true) {
}
}
});
}
and the output is a blank window that does not react to window exiting.
Can someone explain me what exactly happans here?
Can someone explane me what exactly happans here?
Sure. You're keeping the event dispatch thread tied up in an infinite loop, so it never gets to react to events such as "close window". Don't do that.
You should keep the event dispatch thread available for as much of the time as possible - don't perform any long-running tasks on it, including IO operations such as reading from files or the network.
See the "Concurrency in Swing" tutorial for more details.

Categories