I have a JPanel component containing a JFXPanel with a browser that embedds a YouTube video. I'm using the videos embed URL from YouTube (i.e. https://www.youtube.com/embed/W-J2OYN9fF8?autoplay=true&controls=0).
I can add the JPanel (VideoPlayer) to a surrounding component without any problem. However - when I remove the VideoPlayer I would also like to stop the YouTube-player. As of now - it keeps playing in the background (with annoying sound). I'm guessing I have to get inside the JFX thread somehow... So, if someone could please help me with code to put in the stopTrailer() method - I'd be very grateful!
Here's my current code. For those who are looking for a simple way to embed a JFX YouTube player in a normal JPanel - this works great - appart from the limitations above...
public class VideoPlayer extends JPanel {
private Stage stage;
private WebView browser;
private JFXPanel jfxPanel;
private WebEngine webEngine;
private String videoUrl;
public VideoPlayer(String url){
this.videoUrl = url;
jfxPanel = new JFXPanel();
createScene();
setLayout(new BorderLayout());
setPreferredSize(new Dimension(800, 560));
add(jfxPanel, BorderLayout.CENTER);
}
private void createScene() {
PlatformImpl.startup(new Runnable() {
#Override
public void run() {
stage = new Stage();
stage.setTitle("Video");
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(videoUrl);
ObservableList<Node> children = root.getChildren();
children.add(browser);
jfxPanel.setScene(scene);
}
});
}
public void stopTrailer() {
}
}
The answer to this was actually really simple. I put the following in the stopTrailer method.
public void stopTrailer() {
PlatformImpl.startup(new Runnable() {
#Override
public void run() {
remove(jfxPanel);
webEngine.load(null);
}
});
}
What it actually does is to reload the browser webEngine to the "address" null. And removes the panel. It seems a bit weird to me cause I would interpret this code as the start of a second thread - without access to the first one. Perhaps someone could explain just how this works?
Related
I'm building a Swing application and I'm using JFXPanel to bring up a WebView for user authentication. I need to return the url that the WebEngine is sent to after a successful user sign-on- but I don't know how to pull the URL from the view at the time the window is closed. I'm aware of Stage.setOnHiding, but this can't apply here since JFXPanels don't act as stages, though they contain a scene.
I'm very new to JavaFX so if this code snippet demonstrates bad conventions, I'd be happy to hear it!
private static void buildAuthBrowser() {
JFrame frame = new JFrame("frame");
final JFXPanel fxPanel = new JFXPanel();
frame.add(fxPanel);
frame.setSize(800, 600);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Platform.runLater(new Runnable() {
#Override
public void run() {
initFX(fxPanel);
}
});
}
private static void initFX(JFXPanel fxPanel) {
// fx thread
Scene scene = createScene();
fxPanel.setScene(scene);
}
private static Scene createScene() {
Group root = new Group();
Scene scene = new Scene(root);
WebView view = new WebView();
WebEngine browser = view.getEngine();
browser.load(auth.getUrl());
root.getChildren().add(view);
return (scene);
}
Found a solution- I was able to set a listener on the engine in the scene builder method, this way, every time the browser visits a new URL it automatically updates a private variable.
in createScene():
authBrowser.getLoadWorker().stateProperty().addListener((observable, oldValue, newValue) -> {
if (Worker.State.SUCCEEDED.equals(newValue)) {
setCode(authBrowser.getLocation());
}
});
I have a Java project that plays a .flv media file through JavaFX Media Player, and it's working fine. Recently, I've been wanting to experiment by adding GUI components to this Project (JPanel, JLabel). However, I've failed in all my attempts and after doing some research turns out it's not as simple as i first thought.. I've tried borderPane.setTop(JLabel) but I get a "Cannot convert Jlabel to Node" error.. I feel that I'm missing something
If anyone has any idea why this isnt working for me, I would greatly appreciate any form of explanation or examples.. :)
Here is the code if it might be of use to you!
#Override
public void start(Stage stage){
String path = "Data/Video/Clip.flv";
Media media = new Media(new File(path).toURI().toString());
MediaPlayer mediaPlayer = new MediaPlayer(media);
MediaView mediaView = new MediaView(mediaPlayer);
BorderPane borderPane = new BorderPane();
borderPane.setCenter(mediaView);
//borderPane.add(logoPanel); <<<<<<< Error
Scene scene = new Scene(borderPane, 1024, 800);
scene.setFill(javafx.scene.paint.Color.BLACK);
stage.setTitle("Media Player");
stage.setScene(scene);
stage.show();
mediaPlayer.setAutoPlay(true);
BorderPane is a JavaFX Node whereas JPanel is a Java Swing Component.
You cannot add a JPanel to a BorderPane, what you are looking for instead is the JavaFX equivalent of the JPanel which is the Pane class.
If you are developing using JavaFX it is easier to just use JavaFX components. If you must use Swing components then you can use the SwingNode class.
What you basically want to achieve: add some Swing components to an JavaFX application.
You have to use SwingNode class to "wrap" a JComponent.
SwingNode Class
JavaFX 8 introduces the SwingNode class, which is located in the
javafx.embed.swing package. This class enables you to embed Swing
content in a JavaFX application. To specify the content of the
SwingNode object, call the setContent method, which accepts an
instance of the javax.swing.JComponent class.
You can check this tutorial how embed Swing component into JavaFX application.
Small example to put a Swing Button into the center of a BorderPane:
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
BorderPane root = new BorderPane();
Scene scene = new Scene(root,400,400);
SwingNode swingNode = new SwingNode();
JButton jButton = new JButton("I am a Swing button");
jButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Message from Swing");
}
});
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
swingNode.setContent(jButton);
}
});
root.setCenter(swingNode);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
By the way, BorderPane has no method "add" (as in your commented line):
You can use setCenter, setTop, setBottom, setLeft and setRight to add Nodes into it (as you used to fill the center).
If your goal was not to embed Swing into JavaFX, just to use JavaFX controls, you can check this article what controls JavaFX has by default.
Inside of my JPanel, I have a button calling SimpleBrowser
JButton swingButton = new JButton();
swingButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
SimpleBrowser openBrowser = new SimpleBrowser();
openBrowser.main((new String[0]));
}
});
swingButton.setText("Browser");
add(swingButton, BorderLayout.SOUTH);
this is my SimpleBrowser class
public class SimpleBrowser extends Application {
VBox vb = new VBox();
public void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage primaryStage) {
vb.setId("root");
WebView browser = new WebView();
WebEngine engine = browser.getEngine();
String url = "https://www.google.com";
engine.load(url);
vb.getChildren().addAll(browser);
Scene scene = new Scene(vb);
primaryStage.setScene(scene);
primaryStage.show();
}
When I run this code, JButton opens up properly SimpleBrowser and display google. However, when I close this application and repress JButton, nothing happens. It suppose to relaunch SimpleBrowser and display google.
Could you guys help me?
I actually find this code from oracle which helped me a lot.
I will share it here just in case if anyone needs
https://docs.oracle.com/javafx/2/swing/SimpleSwingBrowser.java.htm
explanation can be found here
https://docs.oracle.com/javafx/2/swing/swing-fx-interoperability.htm#CHDIEEJE
Thank you for trying to help me
I am trying to instantiate many JFrames with WebView, it will work as long as after opening the first WebView, at least one WebView is still alive and the JFrame (along with everything else) arent disposed of.
After some checking, it seems that after closing the all WebView JFrame, the Platform.runLater() no longer runs on the next instantiation of the JFrame with the WebViewPanel.
The following is the simplified code:
public class WebViewPanel{
private JFXPanel jfxPanel;
private WebView view;
private WebEngine webEngine;
private JPanel panel;
public WebViewPanel(JPanel panel){
this.panel = panel;
panel.setVisible(true);
createScene();
}
private void createScene(){
Platform.runLater(new Runnable(){
#Override
public void run(){ //Runnable no longer runs after all JFrames with WebViewPanels are closed
jfxPanel = new JFXPanel();
view = new WebView();
webEngine = view.getEngine();
jfxPanel.setScene(new Scene(view));
panel.add(jfxPanel);
jfxPanel.setVisible(true);
}
});
}
}
So, what must I do to resolve this problem?
This happens because Platform exits itself if not explicitly set.
Here's what you need to do just after
Platform.runLater(new Runnable(){ // ..code
add Platform.setImplicitExit(false); at the first row
so your new code will be -
private void createScene(){
Platform.runLater(new Runnable(){
Platform.setImplicitExit(false);
#Override
public void run(){
jfxPanel = new JFXPanel();
view = new WebView();
webEngine = view.getEngine();
jfxPanel.setScene(new Scene(view));
panel.add(jfxPanel);
jfxPanel.setVisible(true);
}
});
}
Just FYI if you are trying to display the panel more than once there is no need to call createScene() add the JFXPanel to a JFrame(preferable panel works fine too) with a static reference. dispose the frame to close it and when again you need to show this simply set the same frame setVisibale(true);. everytime calling this frame you can also check if the static reference of this frame points to null(representing first call) then call createscene() else just set the static reference to visible.
I try to embed a JavaFX panel to java Swing using the tutorial from here
I am using java 8 update 20, JavaFX 2.0 or 2.2 (not very sure how to check)
Here is my code:
JavaFX code:
public class SwingFXWebView{
public final JFXPanel jfxpanel;
public SwingFXWebView(String[] para, int width, int height){
jfxpanel = new JFXPanel();
jfxpanel.setLayout(new BorderLayout());
//add(jfxpanel, BorderLayout.CENTER);
Platform.runLater( new Runnable(){
public void run(){
initFX(jfxpanel);
}
});
}
private static void initFX(JFXPanel jfxpanel){
Scene scene = createScene();
jfxpanel.setScene(scene);
}
private static Scene createScene() {
Platform.setImplicitExit(false);
Group root = new Group();
final Scene scene = new Scene(root, Color.ALICEBLUE);
WebView browser;
browser = new WebView();
//browser.setContextMenuEnabled(false);
browser.autosize();
WebEngine webEngine = browser.getEngine();
webEngine.load("www.google.ca");
root.getChildren().add(browser);
return (scene);
}
Swing code:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
//Jdesktop browser
sfwv = new SwingFXWebView(para, panelContents.getWidth(),panelContents.getHeight());
panelContents.add(sfwv.jfxpanel, BorderLayout.CENTER);
....
}
It works so far. if I mouse right click to refresh the page and do it for second time, the JVM crashes.
A fatal error has been detected by the Java Runtime Environment:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x000000005c2728e0, pid=5376, tid=5084
#
It looks like the thread problem, but I strictly follow the tutorial from oracle. Any idea what I have done wrong?
Thanks in advance!