30 votes

Mettre en sourdine une WebView en JavaFX, est-ce possible ?

C'est très simple. Est-il possible de mettre en sourdine ou de contrôler le volume d'une WebView JavaFX ? J'ai cherché sur Google pendant un certain temps, mais je n'ai trouvé aucune mention de cette possibilité. J'ai regardé le code de WebView y WebEngine et il semble qu'il n'y ait rien sur le contrôle du volume.

J'ai encore besoin d'autres MediaPlayer dans la même application pour travailler et produire du son, je ne peux donc pas mettre en sourdine toute l'application.

10voto

Maciej Pulikowski Points 1890

En ce moment, il y a NON une telle API pour la sonorisation dans WebView o WebEngine Contrôle.

Mais vous pourriez injecter JavaScript pour activer/désactiver le son et contrôler les sons. Cette méthode, ne fonctionne qu'avec les éléments HTML5 < vidéo > o < audio > car des éléments comme Flash o JS initialisée est impossible à restreindre en général. J'ai créé un programme d'exemple pour vous :

WebView mute/unmute - program

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception{
        WebView myWebView = new WebView();
        WebEngine engine = myWebView.getEngine();
        //dirty code xD

        Button btn = new Button("Load Youtube");
        btn.setOnAction((ActionEvent event) -> engine.load("http://www.youtube.com/embed/A6hrw6KGdtM?autoplay=1"));

        Button btn2 = new Button("Mute");
        btn2.setOnAction((ActionEvent event) -> engine.executeScript(getJSAudioVideo(true)));

        Button btn3 = new Button("Unmute");
        btn3.setOnAction((ActionEvent event) -> engine.executeScript(getJSAudioVideo(false)));

        Button btn4 = new Button("+");
        btn4.setOnAction((ActionEvent event) -> engine.executeScript(getJSSoundVolume(0.9)));

        Button btn5 = new Button("-");
        btn5.setOnAction((ActionEvent event) -> engine.executeScript(getJSSoundVolume(0.1)));

        VBox root = new VBox();
        root.getChildren().addAll(myWebView, btn, btn2, btn3, btn4, btn5);

        Scene scene = new Scene(root, 800, 500);
        primaryStage.setScene(scene);
        primaryStage.setTitle("Mute a WebView in JavaFX, is it possible?");

        primaryStage.show();
    }

    /**
     * @param mute
     * @return JS code for mute/unmute
     */
    public String getJSAudioVideo(boolean mute){
        return "var videos = document.querySelectorAll('video'),\n" +
                "    audios = document.querySelectorAll('listen');\n" +
                "    [].forEach.call(videos, function(video) { video.muted = "+String.valueOf(mute)+"; });\n" +
                "    [].forEach.call(audios, function(audio) { audio.muted = "+String.valueOf(mute)+"; });";
    }

    /**
     * @param volume
     * @return JS code for setting volume sound
     */
    public String getJSSoundVolume(double volume){
        //max 1.0, min 0.0 Default: 1.0
        double _volume = (volume > 1.0 || volume < 0.0) ? 1.0 : volume;

        return "var videos = document.querySelectorAll('video'),\n" +
                "    audios = document.querySelectorAll('listen');\n" +
                "    [].forEach.call(videos, function(video) { video.volume = "+String.valueOf(_volume)+"; });\n" +
                "    [].forEach.call(audios, function(audio) { audio.volume = "+String.valueOf(_volume)+"; });";

    }

    public static void main(String[] args) {
        launch(args);
    }
}

9voto

dzikoysk Points 1333

Nous savons tous que c'est une partie manquante de l'API, alors que pouvez-vous faire pour l'implémenter vous-même ? Réfléchissons à ce qu'est réellement un WebView :

Le composant navigateur embarqué est basé sur WebKit [...] Par défaut, WebKit ne prend pas en charge le rendu des pages Web. Afin de rendre et d'afficher le contenu HTML, Oracle a dû écrire son propre moteur de rendu en utilisant l'API Java Graphics 2D.

Cela signifie que le moteur doit avoir une mise en œuvre. L'implémentation de WebKit se trouve dans com.sun.webkit paquet (une grande partie des classes ne sont que des enveloppes pour les appels natifs). . Bien sûr, dans la plupart des cas, vous ne voulez pas utiliser com.sun.* mais comme vous travaillez actuellement avec JavaFX, cela n'a pas vraiment d'importance.

Si nous sautons un peu dans les sources du soleil, nous pouvons trouver WCMediaPlayer.class avec des méthodes audio abstraites comme :

protected abstract void setRate(float rate);
protected abstract void setVolume(float volume);
protected abstract void setMute(boolean mute);
protected abstract void setSize(int w, int h);
protected abstract void setPreservesPitch(boolean preserve);

Allez Java, laisse-moi t'appeler :

volumeMethod = WCMediaPlayer.class.getDeclaredMethod("setVolume", float.class);
volumeMethod.setAccessible(true);

J'apprécie votre aide mais comment puis-je obtenir WCMediaPlayer instances ? Nous devons examiner les références à new WCMediaPlayerImpl() . Je l'ai eu ! WCGraphicsManager.class crée le MediaPlayer par fwkCreateMediaPlayer() après tout, elle place le pointeur et l'instance dans le fichier refMap :

Field refMapField = WCGraphicsManager.class.getDeclaredField("refMap");
refMapField.setAccessible(true);

Heureusement, le manager a exposé getGraphicsManager() pour obtenir une instance :

WCGraphicsManager graphicsManager = WCGraphicsManager.getGraphicsManager();
refMap = (Map<Integer, Ref>) refMapField.get(graphicsManager);

La carte capturée contient Ref (il existe également d'autres WC* ), il faut donc les filtrer :

Collection<WCMediaPlayer> mediaPlayers = refMap.values().stream()
    .filter(ref -> ref instanceof WCMediaPlayer)
    .map(ref -> (WCMediaPlayer) ref)
    .collect(Collectors.toList());

Vous vous attendez probablement à un exemple fonctionnel, voici donc le code que j'ai utilisé :

WebEngineTest Preview

public class WebEngineTest extends Application {

    private Map<Integer, Ref> refMap;
    private Method volumeMethod;

    @Override
    @SuppressWarnings("unchecked")
    public void start(Stage primaryStage) throws Exception {
        WebView webView = new WebView();
        WebEngine engine = webView.getEngine();
        engine.load("https://www.youtube.com/watch?v=hRAZBSoAsgs");

        Field refMapField = WCGraphicsManager.class.getDeclaredField("refMap");
        refMapField.setAccessible(true);

        volumeMethod = WCMediaPlayer.class.getDeclaredMethod("setVolume", float.class);
        volumeMethod.setAccessible(true);

        WCGraphicsManager graphicsManager = WCGraphicsManager.getGraphicsManager();
        refMap = (Map<Integer, Ref>) refMapField.get(graphicsManager);

        Button button = new Button("Volume");
        button.setOnAction(event -> setVolume(0.1f));

        Group group = new Group();
        group.getChildren().addAll(webView, button);

        Scene scene = new Scene(group, 625, 625);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public void setVolume(float volume) {
        Collection<WCMediaPlayer> mediaPlayers = this.getMediaPlayers();
        mediaPlayers.forEach(mediaPlayer -> setVolumeMethod(mediaPlayer, volume));
    }

    private void setVolumeMethod(Object instance, Object... args) {
        try {
            volumeMethod.invoke(instance, args);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private Collection<WCMediaPlayer> getMediaPlayers() {
        return refMap.values().stream()
                .filter(ref -> ref instanceof WCMediaPlayer)
                .map(ref -> (WCMediaPlayer) ref)
                .collect(Collectors.toList());
    }

}

Enfin, n'oubliez pas l'ordre de ces appels. Par exemple, refMap ne contient pas tous les Refs jusqu'à ce que l'état du moteur ne soit pas SUCCEEDED o WCGraphicsManager.getGraphicsManager() renvoie à null si l'élément graphique n'est pas créé du tout.

Le meilleur moyen est probablement de combiner ces solutions. Il est difficile de supporter un mélange de technologies web sans scenerio et l'API pauvre fournie par JavaFX. Vous pouvez également essayer d'intégrer un autre navigateur, comme Chromium.

6voto

Subash J Points 1401

Pour dire WebView il s'agit d'une extension de la classe Node. Elle encapsule un objet WebEngine, incorpore du contenu HTML dans la scène d'une application et fournit des propriétés et des méthodes pour appliquer des effets et des transformations. La méthode getEngine() appelée sur un objet WebView renvoie le moteur Web qui lui est associé. [Source :](http://The%20WebView%20class%20is%20an%20extension%20of%20the%20Node%20class.%20It%20encapsulates%20a%20WebEngine%20object,%20incorporates%20HTML%20content%20into%20an%20application's%20scene,%20and%20provides%20properties%20and%20methods%20to%20apply%20effects%20and%20transformations.%20The%20getEngine()%20method%20called%20on%20a%20WebView%20object%20returns%20a%20web%20engine%20associated%20with%20it.)

WebView ne prend donc pas en charge d'API pour le contrôle de la sourdine/du volume pour le moment. Il existe une API pour mettre en sourdine le contenu chargé dans le MediaPlayer (c'est-à-dire,)

Pour obtenir le statut de muteProperty : Lien vers la source

public BooleanProperty muteProperty()

Pour vérifier la condition de sourdine : Lien vers la source

public final boolean isMute()

Pour couper le son de la vidéo, réglez la valeur sur true : Lien vers la source

public final void setMute(boolean value)

OU utilisez autrement l'API JavaScript pour couper la vidéo/l'audio :

getElementById("Your video Id");

et réglez la commande sur Mute par :

vid.muted = true;

Lien vers la source

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X