2017-02-23 101 views
0

Используя веб-просмотр JavaFX, я изменяю несколько атрибутов html (фон, граница и цвет) для всех тегов DOM веб-сайта по всему миру. Мое намерение состоит в том, чтобы настроить темную тему, которая будет очень похожа на высококонтрастные настройки. Единственной проблемой, которую я не могу решить, является небольшая задержка кода в последнем методе setWebpageTheme (Boolean successed). Это приводит к яркому белому мерцанию, когда применяются атрибуты html css и изменяются фон от белого до темного. См. Полный код ниже.JavaFX webview global CSS темная тема

Главный класс:

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(); 
    } 
} 

Web-браузер 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); 
      } 
     } 
    } 
} 

Текст Имя файла Путь: /style/template.css < -fx настройки графического интерфейса пользователя (не для веб-страниц)

.root{ 
    -fx-background: rgb(44,44,44); 
} 

.button { 
    -fx-border-radius: 5; 
    -fx-background-radius: 5; 
    -fx-min-height: 32; 
    -fx-min-width: 40; 
    -fx-background-color: radial-gradient(radius 100%, rgb(22, 33, 188), rgb(3,22,122)); 
    -fx-text-fill: rgb(196,188,222); 
} 

TextField { 
    -fx-border-radius: 5; 
    -fx-background-radius: 5; 
    -fx-max-height: 32; 
    -fx-min-width: 280; 
    -fx-border-color: #555; 
    -fx-border-width: 1 1 1 1; 
    -fx-background-color: #333; 
    -fx-text-fill: rgb(196,188,222); 
} 

.combo-box-base { 
    -fx-border-radius: 5; 
    -fx-background-radius: 5; 
    -fx-min-height: 35; 
    -fx-background-color: #333; 
    -fx-border-color: transparent; 
    -fx-border-width: 2 2 2 2; 
} 

.combo-box-base .arrow-button { 
    -fx-background-color: radial-gradient(radius 100%, rgb(22, 33, 188), rgb(3,22,122)); 
} 

.combo-box .combo-box-popup, .list-view, .list-cell { 
    -fx-background-color: #333; 
    -fx-text-fill: rgb(155,188,166); 
} 

.combo-box .text-input { 
    -fx-border-radius: 5; 
    -fx-background-radius: 5; 
    -fx-background-color: #333; 
    -fx-border-color: #555; 
    -fx-border-width: 1 1 1 1; 
    -fx-text-fill: rgb(155,188,166); 
} 

.scroll-bar { 
    -fx-background-color: #222; 
} 

.scroll-bar .thumb { 
    -fx-background-color: radial-gradient(radius 100%, rgb(22, 33, 188), rgb(3,22,122)); 
} 

.label { 
    -fx-font: 14px "Arial"; 
    -fx-border-color: rgb(57, 58, 59); 
    -fx-border-width: 2 2 2 2; 
    -fx-text-fill: rgb(155,188,166); 
} 

.progress-bar > .track { 
    -fx-text-box-border: rgb(44, 44, 44); 
    -fx-control-inner-background: rgb(22, 22, 44); 
} 

ответ

0

Я разработал решение, позволяющее минимизировать влияние затухания темного фона или быть конкретным, e неэффективность, в которой я добавляю атрибуты ко всем тегам DOM html. Я добавил нижеследующую таблицу стилей html, используя следующий код до вызова метода setWebpageTheme (boolean success); Это не на 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; 
}