Используя веб-просмотр 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);
}