JavaFx webview YouTube - javafx

A couple of weeks ago, i used NetBeans to create one of it's javafx examples
The webview project, and it worked fine.
I am especially interested in using javafx to play youtube videos
in a swinginterop application.
This is part of a bigger project, so i used the SwingInterop example from NetBeans to load the players on a JFrame
I need to load more than one YouTube Video.
And again everything worked great.
I am using Windows XP, NetBeans 7.2, Java 1.7 9
These days i tried the application again but this time on youtube i see
"This Video is currently unavailable".
The first thing that came into my mind was that maybe
i don't have the latest FlashPlayer ...
Needless to say i downloaded everything...
The application just won't play youtube videos anymore
I even reinstalled java and netbeans again but nothing changed.
I also mention that on Firefox, which is the browser i have on my pc
youtube works just fine.
It is pretty annoying to know that ... something was ok and maybe ...
i found a way to mess things in there ...
So right now, i can see web pages in javafx webview but youtube videos are still not playing...
The last time i asked for help i did not put the code ... sorry about that.
So i made another small project with only two classes in it to show what i did
I did not test this on another pc because, if it happened once
chances are it will happen again and since things don't fix themselves
i want to be able to answer this question when it will pop up.
Thank you jewelsea and Gregory for the interest
here is the code :
the frame on which the players are loaded
package stackoverflow;
import java.awt.Dimension;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
public class PlayersFrame extends JFrame
{
public PlayersFrame()
{
// initialize jframe
setLayout(null);
setTitle(" YouTube on JFrame");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
CreatePlayersList();
}
// all the players have the same size
Dimension PlayerSize = new Dimension(300, 230);
private void CreatePlayersList()
{
/*
* create an instance of playerclass
* containing the location and the youtube embedded address
* for each of the four players
*/
Point NewPlayerLocation = null;
PlayerClass NewPlayer = null;
NewPlayerLocation = new Point(10, 10);
NewPlayer = new PlayerClass(NewPlayerLocation, PlayerSize, "http://www.youtube.com/embed/SvcDwPlaWgw?rel=0");
// add player1 class to the players list
Players.add(NewPlayer);
NewPlayerLocation = new Point(320, 10);
NewPlayer = new PlayerClass(NewPlayerLocation, PlayerSize, "http://www.youtube.com/embed/L0huXvTeVvU?rel=0");
// add player2 class to the players list
Players.add(NewPlayer);
NewPlayerLocation = new Point(10, 240);
NewPlayer = new PlayerClass(NewPlayerLocation, PlayerSize, "http://www.youtube.com/embed/rHcnsEoSK_c?rel=0");
// add player3 class to the players list
Players.add(NewPlayer);
NewPlayerLocation = new Point(320, 240);
NewPlayer = new PlayerClass(NewPlayerLocation, PlayerSize, "http://www.youtube.com/embed/vaXuK-RsT6E?rel=0");
// add player4 class to the players list
Players.add(NewPlayer);
// stand by
LoadPlayers();
}
// list of players data
List<PlayerClass> Players = new ArrayList<>();
/*
* a class to hold data about a player
*/
public class PlayerClass
{
public PlayerClass(Point playerLocation, Dimension playerSize, String youTubeAddress)
{
PlayerLocation = playerLocation;
PlayerSize = playerSize;
YouTubeAddress = youTubeAddress;
}
public Point PlayerLocation = null;
public Dimension PlayerSize = null;
public String YouTubeAddress = null;
}
/*
* in this swinginterop project i want to display youtube videos on a jframe
* with webview i get more that i ask for
* webview will display an entire web page
* so a web page is created on the fly containing a frame for the player
*/
private String GeneratePlayerPage(Dimension PlayerSize, String EmbeddedAddress)
{
String GeneratedPage = null;
GeneratedPage = "<html>\n";
GeneratedPage += "<body>\n";
GeneratedPage += "<iframe\n";
GeneratedPage += "style=\"position:absolute;\n";
GeneratedPage += "left:0px;top:0px;" +
"width:" + String.valueOf(PlayerSize.width) +
"px;height:" + String.valueOf(PlayerSize.height) + "px;\"\n";
GeneratedPage += "src=\"" + EmbeddedAddress + "\"" + "\n";
GeneratedPage += "frameborder=\"0\" allowfullscreen>\n";
GeneratedPage += "</iframe>\n";
GeneratedPage += "</body>\n";
GeneratedPage += "</html>";
return(GeneratedPage);
}
/*
* why synchronized ? ...
*
* each javafx object runs on it's own thread
* this means that, sooner or later
* you will have to deal with crossthreading issues
*
* in this project it does not throw an error
* but since the playersform will add controls on a locked procedure,
* and i don't use a single player on the jframe,
* some of the players will not appear on the frame.
*
* if only one player is loaded on the jframe
* then all this is not necessary.
*
* i don't know if the players are there but are not rendered
* or the players were just not loaded
*
* with this synchronized void a callback from the javafx object is handled
*/
public synchronized void OkPlayer()
{
try
{
/*
* a player was loaded
* delay before the next player
*/
Thread.sleep(10);
}
catch(Exception Ex)
{}
/*
* if the players list is empty than all the players have been loaded
* but you also get an error, so check the size ...
*/
if(Players.size() > 0)
{
LoadPlayers();
}
}
void LoadPlayers()
{
/*
* get the data from the first playerclass in the players list
* and create a new player
*/
PlayerClass TempPlayer = Players.get(0);
Dimension playerSize = TempPlayer.PlayerSize;
YouTubePlayer player = new YouTubePlayer(this, playerSize,
GeneratePlayerPage(playerSize, TempPlayer.YouTubeAddress));
add(player);
player.setLocation(TempPlayer.PlayerLocation);
player.setSize(TempPlayer.PlayerSize);
player.setVisible(true);
// remove the used playerclass from the players list
Players.remove(0);
}
}
and the player
package stackoverflow;
import java.awt.Dimension;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UnsupportedLookAndFeelException;
public final class YouTubePlayer extends JPanel
{
public YouTubePlayer(PlayersFrame playersFrame, Dimension PlayerSize, String YouTubeAddress)
{
remote = playersFrame;
init(PlayerSize, YouTubeAddress);
}
private static JFXPanel browserFxPanel;
private Pane browser;
public void init(Dimension playerSize, String youTubeAddress)
{
final Dimension PlayerSize = playerSize;
final String YouTubeAddress = youTubeAddress;
browserFxPanel = new JFXPanel();
browserFxPanel.setPreferredSize(new Dimension(PlayerSize.width, PlayerSize.height));
add(browserFxPanel);
Platform.runLater(new Runnable()
{
public void run()
{
// inside the player's thread
createScene(PlayerSize, YouTubeAddress);
}
});
}
/*
* the program will start on the javafx thread
* the main void is placed in the javafx component
*
* maybe there are other ways to launch the program
* but for this one it is good enough ... for now
*/
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
try
{
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels())
{
// set windows look and feel
if ("Windows".equals(info.getName()))
{
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
}
catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException Ex)//ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException ex)
{}
// create an instance of playersframe
PlayersFrame LoadPlayers = new PlayersFrame();
LoadPlayers.setSize(new Dimension(640, 520));
// make it visible
LoadPlayers.setVisible(true);
}
});
}
PlayersFrame remote = null;
private void createScene(Dimension PlayerSize, String YouTubeAddress)
{
browser = createBrowser(PlayerSize, YouTubeAddress);
browserFxPanel.setScene(new Scene(browser));
/*
* player loaded
* let playersform know that it can proceed
* with the next player, if there still is one
*/
remote.OkPlayer();
}
private Pane createBrowser(Dimension PlayerSize, String YouTubeAddress)
{
WebView view = new WebView();
view.setPrefSize(PlayerSize.width, PlayerSize.height);
final WebEngine eng = view.getEngine();
eng.loadContent(YouTubeAddress);
GridPane grid = new GridPane();
grid.getChildren().addAll(view);
return grid;
}
}
this is what it looks like
http://i.stack.imgur.com/UvhcJ.jpg
and this is the 'thing'
http://i.stack.imgur.com/lB4uY.jpg
the last player acts the same as the others
If i use the example from NetBeans and just paste a YouTube link
i get the same result
I really need to know what is happening
Thank you

Check out the system requirements:
http://docs.oracle.com/javafx/2/system_requirements_2-2/jfxpub-system_requirements_2-2.htm
For Windows XP and Windows Vista, JavaFX Media 2.2 requires that one of the following external modules be installed to play AAC audio and H.264/AVC video:
MainConcept H.264/AVC Pro Decoder Pack
DivX Plus Codec Pack
MainConcept Showcase (includes demo version codecs)
DivX is freely downloadable: http://www.divx.com/
Reference: https://forums.oracle.com/thread/2467376

Related

how to differentiate between a single click or double click on a table row in javafx

I am trying to create a table in javafx that allows a user to click on a row to go to one page or double click the row to go to a different page. The problem is that the application registers the event of the single click, but does not wait to see if there is another double click. Is there a way to have the program wait and see if there is another click?
what i have so far looks similar to something like
TableView searchResults;
ObservableList<MovieRow> rows = FXCollections.observableArrayList();
private TableColumn<MovieRow, String> title;
title.setCellValueFactory(new PropertyValueFactory<>("mTitle"));
rows.add(new MovieRow("The cat in the hat"));
searchResults.setItems(rows);
searchResults.setRowFactory(tv -> {
TableRow<MovieRow> row = new TableRow<>();
row.setOnMouseClicked(event -> {
MovieRow tempResult = row.getItem();
if (event.getClickCount() == 1) {
System.out.println(tempResult.getMTitle + " was clicked once");
}else{
System.out.println(tempResult.getMTitle + " was clicked twice");
}
});
return row;
});
public class MovieRow{
private String mTitle;
public MovieRow(String title){
mTitle = title;
}
public String getMTitle() {
return mTitle;
}
}
actual output
single click: The cat in the hat was clicked once
double click: The cat in the hat was clicked once
desired output
single click: The cat in the hat was clicked once
double click: The cat in the hat was clicked twice
I've only found results on handling double clicks by themselves or single clicks by themselves but not having both, so I'm not sure if this is even possible. Any help would be much appreciated. Thanks.
There's no way to do this that's part of the API: you just have to code "have the program wait and see if there is another click" yourself. Note that this means that the single-click action has to have a slight pause before it's executed; there's no way around this (your program can't know what's going to happen in the future). You might consider a different approach (e.g. left button versus right button) to avoid this slightly inconvenient user experience.
However, a solution could look something like this:
public class DoubleClickHandler {
private final PauseTransition delay ;
private final Runnable onSingleClick ;
private final Runnable onDoubleClick ;
private boolean alreadyClickedOnce ;
public DoubleClickHandler(
Duration maxTimeBetweenClicks,
Runnable onSingleClick,
Runnable onDoubleClick) {
alreadyClickedOnce = false ;
this.onSingleClick = onSingleClick ;
this.onDoubleClick = onDoubleClick ;
delay = new PauseTransition(maxTimeBetweenClicks);
delay.setOnFinished(e -> {
alreadyClickedOnce = false ;
onSingleClick.run()
});
}
public void applyToNode(Node node) {
node.setOnMouseClicked(e -> {
delay.stop();
if (alreadyClickedOnce) {
alreadyClickedOnce = false ;
onDoubleClick.run();
} else {
alreadyClickedOnce = true ;
delay.playFromStart();
}
});
}
}
Which you can use with:
searchResults.setRowFactory(tv -> {
TableRow<MovieRow> row = new TableRow<>();
DoubleClickHandler handler = new DoubleClickHandler(
Duration.millis(500),
() -> {
MovieRow tempResult = row.getItem();
System.out.println(tempResult.getMTitle + " was clicked once");
},
() -> {
MovieRow tempResult = row.getItem();
System.out.println(tempResult.getMTitle + " was clicked twice");
}
);
handler.applyToNode(row);
return row ;
});
I encountered the same requirement once and worked on developing a custom event dispatcher. The solution what #James_D provided is clean, simple and works great. But if you want to generalize this behavior on a large scale, you can define a new custom mouse event and an event dispatcher.
The advantage of this approach is its usage will be just like other mouse events and can be handled in both event filters and handlers.
Please check the below demo and the appropriate code:
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.*;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class DoubleClickEventDispatcherDemo extends Application {
#Override
public void start(Stage stage) throws Exception {
Rectangle box1 = new Rectangle(150, 150);
box1.setStyle("-fx-fill:red;-fx-stroke-width:2px;-fx-stroke:black;");
addEventHandlers(box1, "Red Box");
Rectangle box2 = new Rectangle(150, 150);
box2.setStyle("-fx-fill:yellow;-fx-stroke-width:2px;-fx-stroke:black;");
addEventHandlers(box2, "Yellow Box");
HBox pane = new HBox(box1, box2);
pane.setSpacing(10);
pane.setAlignment(Pos.CENTER);
addEventHandlers(pane, "HBox");
Scene scene = new Scene(new StackPane(pane), 450, 300);
stage.setScene(scene);
stage.show();
// THIS IS THE PART OF CODE SETTING CUSTOM EVENT DISPATCHER
scene.setEventDispatcher(new DoubleClickEventDispatcher(scene.getEventDispatcher()));
}
private void addEventHandlers(Node node, String nodeId) {
node.addEventFilter(MouseEvent.MOUSE_CLICKED, e -> System.out.println("" + nodeId + " mouse clicked filter"));
node.addEventHandler(MouseEvent.MOUSE_CLICKED, e -> System.out.println("" + nodeId + " mouse clicked handler"));
node.addEventFilter(CustomMouseEvent.MOUSE_DOUBLE_CLICKED, e -> System.out.println("" + nodeId + " mouse double clicked filter"));
node.addEventHandler(CustomMouseEvent.MOUSE_DOUBLE_CLICKED, e -> System.out.println(nodeId + " mouse double clicked handler"));
}
/**
* Custom MouseEvent
*/
interface CustomMouseEvent {
EventType<MouseEvent> MOUSE_DOUBLE_CLICKED = new EventType<>(MouseEvent.ANY, "MOUSE_DBL_CLICKED");
}
/**
* Custom EventDispatcher to differentiate from single click with double click.
*/
class DoubleClickEventDispatcher implements EventDispatcher {
/**
* Default delay to fire a double click event in milliseconds.
*/
private static final long DEFAULT_DOUBLE_CLICK_DELAY = 215;
/**
* Default event dispatcher of a node.
*/
private final EventDispatcher defaultEventDispatcher;
/**
* Timeline for dispatching mouse clicked event.
*/
private Timeline clickedTimeline;
/**
* Constructor.
*
* #param initial Default event dispatcher of a node
*/
public DoubleClickEventDispatcher(final EventDispatcher initial) {
defaultEventDispatcher = initial;
}
#Override
public Event dispatchEvent(final Event event, final EventDispatchChain tail) {
final EventType<? extends Event> type = event.getEventType();
if (type == MouseEvent.MOUSE_CLICKED) {
final MouseEvent mouseEvent = (MouseEvent) event;
final EventTarget eventTarget = event.getTarget();
if (mouseEvent.getClickCount() > 1) {
if (clickedTimeline != null) {
clickedTimeline.stop();
clickedTimeline = null;
final MouseEvent dblClickedEvent = copy(mouseEvent, CustomMouseEvent.MOUSE_DOUBLE_CLICKED);
Event.fireEvent(eventTarget, dblClickedEvent);
}
return mouseEvent;
}
if (clickedTimeline == null) {
final MouseEvent clickedEvent = copy(mouseEvent, mouseEvent.getEventType());
clickedTimeline = new Timeline(new KeyFrame(Duration.millis(DEFAULT_DOUBLE_CLICK_DELAY), e -> {
Event.fireEvent(eventTarget, clickedEvent);
clickedTimeline = null;
}));
clickedTimeline.play();
return mouseEvent;
}
}
return defaultEventDispatcher.dispatchEvent(event, tail);
}
/**
* Creates a copy of the provided mouse event type with the mouse event.
*
* #param e MouseEvent
* #param eventType Event type that need to be created
* #return New mouse event instance
*/
private MouseEvent copy(final MouseEvent e, final EventType<? extends MouseEvent> eventType) {
return new MouseEvent(eventType, e.getSceneX(), e.getSceneY(), e.getScreenX(), e.getScreenY(),
e.getButton(), e.getClickCount(), e.isShiftDown(), e.isControlDown(), e.isAltDown(),
e.isMetaDown(), e.isPrimaryButtonDown(), e.isMiddleButtonDown(),
e.isSecondaryButtonDown(), e.isSynthesized(), e.isPopupTrigger(),
e.isStillSincePress(), e.getPickResult());
}
}
}

How can I access scroll position in controlsfx GridView for JavaFX?

I am using a controlsfx GridView in a JavaFX application. It shows a scrollbar when needed, but I can't find any way to determine where the scrollbar is positioned at, nor update it. I need to be able to do things like respond to a "go to the top" command from the user and scroll up; or scroll to keep the selected thumbnail visible as the user uses arrow keys to navigate through the grid. But I don't see how to get access to the current scroll position, nor manipulate it, as you can with a ScrollPane.
For example, here is a sample application that creates a GridView with 100 generated images in it. I add a listener to the "onScrollProperty", but it is never called. I also have no idea how I would cause it to scroll to a certain scroll position (0..1):
import java.awt.image.BufferedImage;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.stage.Stage;
import org.controlsfx.control.GridView;
import org.controlsfx.control.cell.ImageGridCell;
// Demo class to illustrate the slowdown problem without worrying about thumbnail generation or fetching.
public class GridViewDemo extends Application {
private static final int CELL_SIZE = 200;
public static void main(String[] args) {
launch(args);
}
public void start(Stage primaryStage) {
// Create a Scene with a ScrollPane that contains a TilePane.
GridView<Image> gridView = new GridView<>();
gridView.setCellFactory(gridView1 -> new ImageGridCell());
gridView.setCellWidth(CELL_SIZE);
gridView.setCellHeight(CELL_SIZE);
gridView.setHorizontalCellSpacing(10);
gridView.setVerticalCellSpacing(10);
addImagesToGrid(gridView);
gridView.onScrollProperty().addListener((observable, oldValue, newValue) -> {
// Never called
System.out.println("Scrolled...");
});
primaryStage.setScene(new Scene(gridView, 1000, 600));
primaryStage.setOnCloseRequest(x -> {
Platform.exit();
System.exit(0);
});
primaryStage.show();
}
private void addImagesToGrid(GridView<Image> gridView) {
for (int i = 0; i < 100; i++) {
final Image image = createFakeImage(i, CELL_SIZE);
gridView.getItems().add(image);
}
}
// Create an image with a bunch of rectangles in it just to have something to display.
private static Image createFakeImage(int imageIndex, int size) {
BufferedImage image = new BufferedImage(size, size, BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
for (int i = 1; i < size; i ++) {
g.setColor(new Color(i * imageIndex % 256, i * 2 * (imageIndex + 40) % 256, i * 3 * (imageIndex + 60) % 256));
g.drawRect(i, i, size - i * 2, size - i * 2);
}
return SwingFXUtils.toFXImage(image, null);
}
}
The needed maven include is:
<dependency>
<groupId>org.controlsfx</groupId>
<artifactId>controlsfx</artifactId>
<version>8.0.6_20</version>
</dependency>
Here is a screen shot of what it looks like.
Maybe to late for the questioner. But after i stumbled across the same problem, after hours of investigation, hopefully useful to others...
I add a listener to the "onScrollProperty", but it is never called.
This "works as intended". :-/ See https://bugs.openjdk.java.net/browse/JDK-8096847.
You have to use "addEventFilter()". See example below.
To set the scroll position is a pain. You have to get the underlying "VirtualFlow" object of the GridView. VirtualFlow contains methods to set the scroll position to specific rows. It's strange that GridView seems to have no API for this common use case. :-(
A "prove of concept" example how to set scroll position, for a GridView with images:
/**
* Register a scroll event and a key event listener to gridView.
* After that navigate with "arrow up" and "arrow down" the grid.
* #param gridView
*/
private void addScrollAndKeyhandler(final GridView<Image> gridView) {
// example for scroll listener
gridView.addEventFilter(ScrollEvent.ANY, e-> System.out.println("*** scroll event fired ***"));
// add UP and DOWN arrow key listener, to set scroll position
gridView.addEventHandler(KeyEvent.KEY_PRESSED, e -> {
if (e.getCode() == KeyCode.UP) oneRowUp(gridView);
if (e.getCode() == KeyCode.DOWN) oneRowDown(gridView);
});
}
int selectedRow = 0; // current "selected" GridView row.
/**
* Scrolls the GridView one row up.
* #param gridView
*/
private void oneRowUp(final GridView<Image> gridView) {
// get the underlying VirtualFlow object
VirtualFlow<?> flow = (VirtualFlow<?>) ((GridViewSkin<?>) gridView.getSkin()).getChildren().get(0);
if (flow.getCellCount() == 0) return; // check that rows exist
if (--selectedRow < 0) selectedRow = 0;
if (selectedRow >= flow.cellCountProperty().get()) selectedRow = flow.getCellCount() - 1;
System.out.println("*** KeyEvent oneRowUp " + selectedRow + " ***");
flow.scrollTo(selectedRow);
}
/**
* Scrolls the GridView one row down.
* #param gridView
*/
private void oneRowDown(final GridView<Image> gridView) {
// get the underlying VirtualFlow object
VirtualFlow<?> flow = (VirtualFlow<?>) ((GridViewSkin<?>) gridView.getSkin()).getChildren().get(0);
if (flow.getCellCount() == 0) return; // check that rows exist
if (++selectedRow >= flow.cellCountProperty().get()) selectedRow = flow.getCellCount() - 1;
System.out.println("*** KeyEvent oneRowDown " + selectedRow + " ***");
flow.scrollTo(selectedRow);
}
(Tested with javafx 15.0.1 and controlsfx 11.0.3)

JavaFX setOnEndOfMedia on next MediaPlayer

I have List<MediaPlayer> that is populating by
private List<MediaPlayer> players() {
for (String file : path.list((dir1, name) -> {
if (name.endsWith(SUPPORTED_VIDEO_FILE_EXTENSIONS)){
return true;
}
return false;
})) {
players.add(createPlayer(Paths.get(path + "/" + file).toUri().toString()));
System.out.println(Paths.get(path + "/" + file).toUri().toString());
}
return players;
}
In my case size of List<MediaPlayer> is 3. Than i use it there
if (currentNumOfVideo == -1) {
currentNumOfVideo = 0;
}
mv = new MediaView();
MediaPlayer currentPlayer = players.get(currentNumOfVideo);
mv.setMediaPlayer(currentPlayer);
currentPlayer.play();
players.get(currentNumOfVideo).setOnEndOfMedia(() -> {
players.get(currentNumOfVideo).stop();
if (currentNumOfVideo < players.size()) {
currentNumOfVideo += 1;
mv.setMediaPlayer(players.get(currentNumOfVideo));
players.get(currentNumOfVideo).play();
} else {
currentNumOfVideo = 0;
mv.setMediaPlayer(players.get(currentNumOfVideo));
players.get(currentNumOfVideo).play();
}
});
First video playing, when it ends second video starts. After second video MediaPlayer stops and didn't play third video.
I understand that because of my setOnEndOfMedia that is only on first MediaPlayer. When the second video starts it doesn't have setOnEndOfMedia. How can I setOnEndOfMedia on every video in my List<MediaPlayer>.
Personally, I would not create all the MediaPlayer instances ahead-of-time. Instead, get a list of Media objects or at least the URIs pointing to the media. Then create a method which is responsible for playing the next video when the current video ends. That method will dispose the old MediaPlayer, create the next MediaPlayer, and configure it to call the same method upon completion. For example:
import java.util.List;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaView;
import javafx.stage.Stage;
public class Main extends Application {
private MediaView mediaView;
private List<Media> media;
private int curIndex;
#Override
public void start(Stage primaryStage) throws Exception {
media = ...; // get media from somewhere
mediaView = new MediaView();
primaryStage.setScene(new Scene(new StackPane(mediaView), 720, 480));
primaryStage.show();
playNextVideo();
}
private void playNextVideo() {
disposePlayer();
if (curIndex == media.size()) {
return; // no more videos to play
}
MediaPlayer player = new MediaPlayer(media.get(curIndex++));
player.setAutoPlay(true); // play ASAP
player.setOnEndOfMedia(this::playNextVideo); // play next video when this one ends
mediaView.setMediaPlayer(player);
}
private void disposePlayer() {
MediaPlayer player = mediaView.getMediaPlayer();
if (player != null) {
player.dispose(); // release resources
}
}
}
This may cause a pause between videos. If that's not acceptable you could create the next MediaPlayer ahead-of-time, either at the same time as the current MediaPlayer or when the current player reaches a certain timestamp (e.g. 10 seconds before the end). But I still wouldn't create all the MediaPlayer instances ahead-of-time.

jxbrowser -- jquery.AreYouSure .. warning message always in English...

i trying to use jquery.AreYouSure into JxBrowser(5.2 and/or next version).
jquery.AreYouSure works... but the warning pop up windows is always in english...
This behaviour is wrong and differ from chrome/firox/ie.... these show message in the current language...
this is a demo url
http://www.papercut.com/products/free-software/are-you-sure/demo/are-you-sure-demo.html
By default, JxBrowser displays dialogs configured with English language. At the same time, JxBrowser API provides functionality that allows modifying default behavior and display your own dialogs with required language. To change the language you need to register your own DialogHandler where you can display your own dialog. For example:
import com.teamdev.jxbrowser.chromium.Browser;
import com.teamdev.jxbrowser.chromium.CloseStatus;
import com.teamdev.jxbrowser.chromium.UnloadDialogParams;
import com.teamdev.jxbrowser.chromium.swing.BrowserView;
import com.teamdev.jxbrowser.chromium.swing.DefaultDialogHandler;
import javax.swing.*;
import java.awt.*;
/**
* The sample demonstrates how to catch onbeforeunload dialog.
*/
public class BeforeUnloadSample {
public static void main(String[] args) {
Browser browser = new Browser();
final BrowserView view = new BrowserView(browser);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.add(view, BorderLayout.CENTER);
frame.setSize(700, 500);
frame.setVisible(true);
browser.setDialogHandler(new DefaultDialogHandler(view) {
#Override
public CloseStatus onBeforeUnload(UnloadDialogParams params) {
String title = "Confirm Navigation";
String message = params.getMessage();
int returnValue = JOptionPane.showConfirmDialog(view, message, title, JOptionPane.OK_CANCEL_OPTION);
if (returnValue == JOptionPane.OK_OPTION) {
return CloseStatus.OK;
} else {
return CloseStatus.CANCEL;
}
}
});
browser.loadHTML("<html><body onbeforeunload='return myFunction()'>" +
"<a href='http://www.google.com'>Click here to leave</a>" +
"<script>function myFunction() { return 'Leave this web page?'; }" +
"</script></body></html>");
}
}

java.lang.ClassCastException: android.widget.LinearLayout cannot be cast to android.support.v4.app.Fragment

I get this error java.lang.ClassCastException: android.widget.LinearLayout cannot be cast to android.support.v4.app.Fragment when I try to open my activity CuteCollection.java in my app. The strange part is that when I click on the first line (FragmentPagerAdapter.java:122) in the logcat error, it shows me a line from a file in the v4.support library. I cannot edit that code, so there must be something in my code I can change.
To get to this activity, I click a button in my HomeFragment.java fragment, which is a fragment in my navigation drawer, which also has the android.support.v4.app.Fragment extension, just like all items do in my navigation drawer.
I think it might be something to do with my FragmentPagerAdpater. Although I did change all of my android.app.Fragment to android.support.v4.app.Fragment, but still the same error.
UPDATE: When I click on the first line in the support.v4 library, called FragmentPagerAdapter, it brings up that class and shows Fragment fragment = (Fragment)object; highlighted, which is part of this method (although I can't edit this, since it's from Android):
#Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
Fragment fragment = (Fragment)object;
if (fragment != mCurrentPrimaryItem) {
if (mCurrentPrimaryItem != null) {
mCurrentPrimaryItem.setMenuVisibility(false);
mCurrentPrimaryItem.setUserVisibleHint(false);
}
if (fragment != null) {
fragment.setMenuVisibility(true);
fragment.setUserVisibleHint(true);
}
mCurrentPrimaryItem = fragment;
}
}
Any tips or advice? Thanks.
CuteCollectionFragment.java
package org.azurespot.cutecollection;
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.astuetz.PagerSlidingTabStrip;
import org.azurespot.R;
/**
* Created by mizu on 1/26/15.
*/
public class CuteCollection extends ActionBarActivity {
private static final int PHOTO_TAB = 0;
private static final int VIDEO_TAB = 1;
private static final int AUDIO_TAB = 2;
private static final int TEXT_TAB = 3;
PhotoTab photoTab;
TextTab textTab;
VideoTab videoTab;
AudioTab audioTab;
public CuteCollection(){}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_cute_collection);
// Instantiate tabs
photoTab = new PhotoTab();
textTab = new TextTab();
videoTab = new VideoTab();
audioTab = new AudioTab();
// Initialize the ViewPager and set an adapter
ViewPager pager = (ViewPager) findViewById(R.id.viewpager);
pager.setAdapter(new TabsAdapter(getSupportFragmentManager()));
// Bind the tabs to the ViewPager
PagerSlidingTabStrip tabs = (PagerSlidingTabStrip)
findViewById(R.id.tabs);
tabs.setViewPager(pager);
}
private class TabsAdapter extends FragmentPagerAdapter {
public TabsAdapter(FragmentManager fm) {
super(fm);
}
/**
* #return the number of pages (tabs) to display
*/
#Override
public int getCount() {
return 4;
}
#Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return "Photos";
case 1:
return "Videos";
case 2:
return "Sounds";
case 3:
return "Poems";
}
return null;
}
/**
* #return true if the value returned from
* {#link #instantiateItem(ViewGroup, int)} is the same object
* as the {#link View} added to the {#link ViewPager}.
*/
#Override
public boolean isViewFromObject(View view, Object o) {
return o == view;
}
#Override
public android.support.v4.app.Fragment getItem(int position) {
switch(position){
case PHOTO_TAB:
Bundle photoBundle = new Bundle();
photoBundle.putInt("page_position", position + 1);
PhotoTab pt = new PhotoTab();
pt.setArguments(photoBundle);
return pt;
case VIDEO_TAB :
Bundle videoBundle = new Bundle();
videoBundle.putInt("page_position", position + 1);
VideoTab vt = new VideoTab();
vt.setArguments(videoBundle);
return new VideoTab();
case AUDIO_TAB:
Bundle audioBundle = new Bundle();
audioBundle.putInt("page_position", position + 1);
AudioTab at = new AudioTab();
at.setArguments(audioBundle);
return new AudioTab();
case TEXT_TAB:
Bundle textBundle = new Bundle();
textBundle.putInt("page_position", position + 1);
TextTab tt = new TextTab();
tt.setArguments(textBundle);
return new TextTab();
}
return null;
}
/**
* Instantiate the {#link View} which should be displayed at
* {#code position}. Here we inflate a layout from the apps resources
* and then change the text view to signify the position.
*/
#Override
public Object instantiateItem(ViewGroup container, int position) {
// Inflate a new layout from our resources
View view = getLayoutInflater().inflate(R.layout.pager_item,
container, false);
// Add the newly created View to the ViewPager
container.addView(view);
// Retrieve a TextView from the inflated View, and update it's text
TextView title = (TextView) view.findViewById(R.id.item_title);
title.setText(String.valueOf(position));
// Return the View
return view;
}
/**
* Destroy the item from the {#link ViewPager}. In our case this is
* simply removing the {#link View}.
*/
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
}
}
fragment_cute_collection.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#2198bb" >
<com.astuetz.PagerSlidingTabStrip
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
custom:pstsTextColorSelected="#ffffff"
custom:pstsUnderlineColor="#ffffff"
custom:pstsIndicatorColor="#ffffff"
android:textColor="#2198bb"/>
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="0px"
android:background="#android:color/white" />
</RelativeLayout>
Logcat
03-07 18:35:42.669 6340-6340/org.azurespot E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: org.azurespot, PID: 6340
java.lang.ClassCastException: android.widget.LinearLayout cannot be cast to android.support.v4.app.Fragment
at android.support.v4.app.FragmentPagerAdapter.setPrimaryItem(FragmentPagerAdapter.java:122)
at android.support.v4.view.ViewPager.populate(ViewPager.java:1071)
at android.support.v4.view.ViewPager.populate(ViewPager.java:919)
at android.support.v4.view.ViewPager.onMeasure(ViewPager.java:1441)
at android.view.View.measure(View.java:17619)
at android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.java:719)
at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:455)
at android.view.View.measure(View.java:17619)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5428)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
at android.view.View.measure(View.java:17619)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5428)
at android.support.v7.internal.widget.ActionBarOverlayLayout.onMeasure(ActionBarOverlayLayout.java:453)
at android.view.View.measure(View.java:17619)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5428)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
at android.view.View.measure(View.java:17619)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5428)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1410)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:695)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:588)
at android.view.View.measure(View.java:17619)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5428)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2588)
at android.view.View.measure(View.java:17619)
at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2317)
at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1412)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1613)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1270)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6691)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:813)
at android.view.Choreographer.doCallbacks(Choreographer.java:613)
at android.view.Choreographer.doFrame(Choreographer.java:583)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:799)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:146)
at android.app.ActivityThread.main(ActivityThread.java:5731)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1291)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1107)
at dalvik.system.NativeStart.main(Native Method)
Your current code seems to run into trouble unless you fix the Exception error. There is a working sample code from Google, and this is quite similar to your code design and meets your vision. I have tried it, and it works. Link at SlidingTabsBasic . One warning is that you will have to change your Gradle build file. If you choose this route, then I can post my build file.
Another similar sample on the same webpage is SlidingTabsColors, which sounds good since I end up in customizing colors for any GUI I make. The SDKs are possibly available on your local drive if you installed it.
If you decide on this route, just accept it as best answer, and post whatever issues you may come up with. At least, I know the sample code works.
Just to let you know, there is an interesting reading at Creating Swipe Views with Tabs, which meets your vision also, and the code seems simpler than what I recommend above. But...it uses ActionBar.TabListener which is deprecated for Lollipop, API version 21. Your choice...
There may be 2 different solutions/parts.
Part 1)
In your posted Java file, do this:
import android.support.v4.app.Fragment ;
remove or comment out:
import android.app.Fragment;
The reason is you are using android.support.v4.app.Fragment. And this is not compatible with your current import android.app.Fragment. Also all your imports reference android.support.v4, so you know you should do it anyway to be consistent :-)
Unfortunately the compiler does not detect this incompatibility.
Part 2)
Since you're using ActionBarActivity, there may be an issue with the build file or settings. The problem is confirmed by others in Stackoverflow # ActionBarActivity cannot resolve a symbol and Error inflating class from library. I know your error sounds different but I think the problem may be the same. Basically you can check your build gradle file (assuming you're using it):
dependencies {
compile "com.android.support:support-v4:21.0.2"
}
The idea is to use compile "com.android.support:support-v4..."

Resources