JavaFX webview全局CSS黑暗主题

时间:2017-02-23 07:10:49

标签: java html css javafx webview

使用JavaFX webview,我将全局更改所有网站DOM标记的几个html属性(背景,边框和颜色)。我的目的是拥有一个定制的黑暗主题,其表现与高对比度设置非常相似。我无法解决的唯一问题是最后一个方法setWebpageTheme(布尔成功)产生的代码略有延迟。当应用html css属性时,它会产生明亮的白色闪烁,并将白色变为黑色页面背景。请参阅下面的完整代码。

主类:

<ion-list>
  <ion-item text-wrap>
    <ion-avatar item-left>
      <img src="img/avatar-small.jpg">
    </ion-avatar>
    <h2>Alissa Connor said something</h2>
    <p>Sed ut perspiciatis unde omnis iste natus error sit Sed ut perspiciatis unde omnis iste natus error sit Sed ut perspiciatis unde omnis iste natus error sit </p>
  </ion-item>
</ion-list>

网络浏览器GUI:

import javafx.application.Application;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Main extends Application {

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

    public Parent createContent() {
        final WebBrowser browser = new WebBrowser();
        return browser;
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        primaryStage.setResizable(true);
        Scene scene = new Scene(createContent());
        primaryStage.setTitle("Eric's Web Demo");
        scene.getStylesheets().add("style/template.css");
        primaryStage.setScene(scene);
        primaryStage.show();
    }
}

文本文件路径名:/style/template.css&lt; -fx GUI设置(不适用于网页)

import org.w3c.dom.Attr;
import org.w3c.dom.NodeList;

import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener.Change;
import javafx.concurrent.Worker.State;
import javafx.event.ActionEvent;
import javafx.geometry.Dimension2D;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.VPos;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebHistory;
import javafx.scene.web.WebHistory.Entry;
import javafx.scene.web.WebView;

public class WebBrowser extends BorderPane {

    private static final Dimension2D DIM = new Dimension2D(1220, 680);
    private final WebView webView;
    private final WebEngine webEngine;
    private final ComboBox<String> addressBox;
    private final TextField searchField;
    private final Button backButton;
    private final Button forwardButton;
    private final Button proceedButton;
    private final Button searchButton;
    private final ProgressBar progressBar;
    private final Label statusLabel;

    public WebBrowser() {

        this.setMinSize(DIM.getWidth(), DIM.getHeight());
        this.setPrefSize(DIM.getWidth(), DIM.getHeight());

        backButton = new Button("\uD83E\uDC78");
        backButton.setOnAction(this::backButtonListener);

        forwardButton = new Button("\u2794");
        forwardButton.setDefaultButton(true);
        forwardButton.setOnAction(this::forwardButtonListener);

        proceedButton = new Button("Go");
        proceedButton.setOnAction(this::proceedButtonListener);

        final HBox buttonGroup = new HBox();
        buttonGroup.setSpacing(5);
        buttonGroup.setPadding(new Insets(10, 5, 10, 5));
        buttonGroup.getChildren().addAll(backButton, forwardButton, proceedButton);

        addressBox = new ComboBox<String>();
        addressBox.setItems(FXCollections.observableArrayList());
        addressBox.setValue("http://stackoverflow.com/questions/32783532/applying-css-file-to-javafx-webview");
        addressBox.setOnAction(this::proceedButtonListener);
        addressBox.setEditable(true);
        addressBox.setMaxWidth(Double.MAX_VALUE);

        searchField = new TextField();
        searchField.setPromptText("\uD83D\uDD0D Search");

        searchButton = new Button("\uD83D\uDD0D");
        searchButton.setDefaultButton(true);
        searchButton.setOnAction(this::searchButtonListener);

        statusLabel = new Label("Status: ");
        progressBar = new ProgressBar(0);   

        webView = new WebView();
        webEngine = webView.getEngine();
        webEngine.load(addressBox.getValue());
        webEngine.getLoadWorker().stateProperty().addListener(this::stateChangeListener);
        webEngine.locationProperty().addListener(this::urlChangeListener);
        progressBar.progressProperty().bind(webEngine.getLoadWorker().progressProperty());

        final WebHistory history = webEngine.getHistory();
        history.getEntries().addListener(this::historyListener);

        final GridPane root = new GridPane();
        GridPane.setConstraints(buttonGroup,  0, 0, 1, 1, HPos.LEFT,   VPos.CENTER, Priority.NEVER,  Priority.NEVER);
        GridPane.setConstraints(addressBox,   1, 0, 1, 1, HPos.CENTER, VPos.CENTER, Priority.ALWAYS, Priority.NEVER);
        GridPane.setConstraints(searchField,  2, 0, 1, 1, HPos.RIGHT,  VPos.CENTER, Priority.NEVER,  Priority.NEVER);
        GridPane.setConstraints(searchButton, 3, 0, 1, 1, HPos.RIGHT,  VPos.CENTER, Priority.NEVER,  Priority.NEVER);
        GridPane.setConstraints(webView,      0, 1, 4, 1, HPos.LEFT,   VPos.CENTER, Priority.ALWAYS, Priority.ALWAYS);
        GridPane.setConstraints(statusLabel,  0, 2, 1, 1, HPos.LEFT,   VPos.CENTER, Priority.NEVER,  Priority.NEVER);
        GridPane.setConstraints(progressBar,  3, 2, 3, 1, HPos.RIGHT,  VPos.CENTER, Priority.NEVER,  Priority.NEVER);
        GridPane.setMargin(addressBox,   new Insets(5, 0, 5, 0));
        GridPane.setMargin(searchField,  new Insets(5, 5, 5, 5));
        GridPane.setMargin(searchButton, new Insets(5, 8, 5, 0));
        GridPane.setMargin(statusLabel,  new Insets(5, 0, 5, 5));
        GridPane.setMargin(progressBar,  new Insets(5, 5, 5, 5));
        root.addRow(0, buttonGroup, addressBox, searchField, searchButton);
        root.addRow(1, webView); 
        root.addRow(2,statusLabel, progressBar);

        this.setCenter(root);       
    }  

    public void historyListener(Change<? extends Entry> changeValue) {
        changeValue.next();
        for (Entry entry : changeValue.getRemoved()) {
            addressBox.getItems().remove(entry.getUrl());
            System.out.print("Removed url: ");
            System.out.println(entry.getUrl());
        }
        for (Entry entry : changeValue.getAddedSubList()) {
            System.out.print("Added url: ");
            addressBox.getItems().add(entry.getUrl());
            System.out.println(entry.getUrl());
        }
    }

    public void progressBarListener(ObservableValue<? extends Number> ov, Number old_val, Number new_val) {
        progressBar.setProgress(new_val.doubleValue());
    }

    private void stateChangeListener(ObservableValue<? extends Object> observable, Object oldValue, Object newValue) {

        setWebpageTheme(newValue == State.SUCCEEDED);
        String output = newValue.toString().toLowerCase();
        statusLabel.setText("Status: " + output);
    }

    private void urlChangeListener(ObservableValue<? extends String> observable, String oldValue, String newValue) {
        addressBox.setValue(newValue);
    }

    public void forwardButtonListener(ActionEvent event) {
        webEngine.executeScript("history.forward()");
    }

    private void backButtonListener(ActionEvent event) {
        webEngine.executeScript("history.back()");
    }

    private void searchButtonListener(ActionEvent event) {
        String google = "http://www.google.com/search?q=" + searchField.getText();
        webEngine.load(google.startsWith("http://") || google.startsWith("https://") 
                ? google : "http://" + google);
    }

    private void proceedButtonListener(ActionEvent event) {
        String url = addressBox.valueProperty().getValue();
        webEngine.load(url.startsWith("http://") || url.startsWith("https://") 
                ? url : "http://" + url);
    }

    private void setWebpageTheme(Boolean succeeded) {
        // Can safely access DOM and set styles.
        if (succeeded == true) {
            // This gives the DOM Document for the web page.
            NodeList htmlTags = webEngine.getDocument().getElementsByTagName("*");
            Attr newAttr = null;
            for (int i = 0; i < htmlTags.getLength(); i++) {
                newAttr = webEngine.getDocument().createAttribute("style");
                newAttr.setValue("background-color: #222; border-color: #333; background: #222; color: #bbb; ");
                htmlTags.item(i).getAttributes().setNamedItem(newAttr);
            }
        }
    }
}

1 个答案:

答案 0 :(得分:0)

我已经提出了一个解决方案,以尽量减少黑暗背景延迟的影响,或者具体来说,我正在为所有DOM html标签添加属性的效率低下。在调用方法setWebpageTheme(boolean succeed)之前,我使用以下代码添加了下面的html样式表;它并非100%完美,但它对我的目的来说是可以忍受的。如果有人找到了更好的解决方案,我仍然感兴趣。

    webEngine.setUserStyleSheetLocation(getClass().getResource("/style/style.css").toString());

style.css

*, a, abbr, acronym, address, applet, b, big, blockquote, body, br, button, caption, center, cite, code, dd, del, dfn, div,
dl, dt, element, em, em, fieldset, font, form, h1, h2, h3, h4, h5, h6, head, header, html, html, i, iframe, iframe, img, 
img, input, ins, kbd, label, label, legend, li, link, meta, nav, noscript, object, ol, ol, p, path, pre, q, s, samp, script,
small, span, strike, strong, style, sub, sup, svg, table, tbody, td, textarea, tfoot, th, thead, title, tr, tt, u, ul, var { 
    background-color: #222; border-color: #333; background: #222; color: #bbb; 
}