JavaFX 实现自己的浏览器

大家好,今天给大家带来了使用JavaFX定制自己的浏览器

这是一个桌面应用可以使用jar方式运行,也可以用别的工具打包成exe,本人因不喜欢模块化,因此未使用FXML,纯代码加css方式实现的,大家先看看效果

 

 下面为结构图,代码一字不漏全在下面,可以直接复制粘贴运行,就创建普通的项目就行,不要用模块化

创建项目

1.先创建一个最普通的maven项目这里我就不演示了直接给大家看pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>MyBrowser</artifactId>
    <version>1.0.0</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-controls</artifactId>
            <version>17.0.1</version>
        </dependency>

        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-web</artifactId>
            <version>17.0.1</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.3</version>
        </dependency>

    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>3.3.0</version>
                <configuration>
                    <archive>
                        <manifest>
                            <!-- <mainClass>启动类位置</mainClass> -->
                            <mainClass>com.kur.ban.BrowserStart</mainClass>
                        </manifest>
                    </archive>

                    <descriptorRefs>
                        <!-- jar 携带依赖 -->
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

创建BrowserApplication类

创建BrowserApplication继承Application重写start方法

package com.kur.ban;

import cn.hutool.core.lang.Console;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.collections.ListChangeListener;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.image.Image;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import javafx.stage.StageStyle;

import java.awt.*;
import java.io.File;

public class BrowserApplication extends Application {
    private static final Log log = LogFactory.get();

    /**
     * @init() 此方法为初始化方法
     * @start() 此方法为运行中方法
     * @stop() 此方法在窗口关闭时调用
     */
    @Override
    public void init() throws Exception {
        super.init();
        log.info("正在初始化...");

        //下面的操作为创建一个txt文件,用来记录下载历史

        //获取系统的\
        String property = System.getProperty("file.separator");
        File file = new File("D:" + property + "Browser");
        //file.exists() 此方法为检测路径是否存在
        if (file.exists()) {
            String path = file.getAbsolutePath() + property + "download.txt";
            File download = new File(path);
            if (download.exists()) {
                log.info("默认存放下载记录的文件已存在");
            } else {
                if (download.createNewFile()) {
                    log.info("成功创建默认存放下载记录的文件");
                } else {
                    log.debug("创建默认存放下载记录的文件失败");
                }
            }
        } else {
            //file.mkdir() 此方法为创建文件夹的方法
            if (file.mkdir()) {
                String path = file.getAbsolutePath() + property + "download.txt";
                File download = new File(path);
                //download.createNewFile() 此方法为创建文件
                if (download.createNewFile()) {
                    log.info("成功创建默认存放下载记录的文件");
                }
                log.info("成功创建存放下载记录的文件的目标文件夹");
            }
        }
    }

    double x = 0; //记录x轴坐标
    double y = 0; //记录y轴坐标

    @Override
    public void start(Stage stage) throws Exception {
        //创建布局
        BorderPane borderPane = new BorderPane();
        borderPane.setId("borderPane");
        //创建场景
        Scene scene = new Scene(borderPane);
        //把场景放入到窗口
        stage.setScene(scene);
        stage.setWidth(1500);
        stage.setHeight(800);
        //因为是浏览器所以使用TabPane新建和删除页面
        TabPane tabPane = new TabPane();
        //通过方法返回一个tab
        Tab tab = Element_Tab.getTab(tabPane, stage);
        //添加一个tab
        tabPane.getTabs().add(tab);
//        tabPane.getSelectionModel().select(tab);
        //返回一个HBox布局,里面放着各种按钮
        HBox hBox = Element_TopButton.getTopButton(stage);
        //把tabPane放在borderPane的中间位置
        borderPane.setCenter(tabPane);
        //把hBox放在borderPane的上面
        borderPane.setTop(hBox);
        //设置窗口的样式,设置成无任何样式跟按钮,按钮需要全部自定义
        stage.initStyle(StageStyle.TRANSPARENT);
        //显示窗口
        stage.show();

        //给tabPane添加监听,监听tab面板增加和减少
        tabPane.getTabs().addListener(new ListChangeListener<Tab>() {
            @Override
            public void onChanged(Change<? extends Tab> change) {
                //默认选中新增加的tab面板
                tabPane.getSelectionModel().select(change.getList().size() - 1);
                if (change.getList().size() == 0) {
                    log.debug("所有的tab窗口都被关闭了,自动结束程序运行!");
                    Console.log("--------------------------------");
                    stage.close();
                    Platform.exit();
                }
            }
        });

        //鼠标按压事件
        scene.setOnMousePressed(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent mouseEvent) {
                //mouseEvent.getScreenX()获取鼠标在屏幕上的坐标
                //stage.getX() 获取窗口的坐标
                x = mouseEvent.getScreenX() - stage.getX();
                y = mouseEvent.getScreenY() - stage.getY();
            }
        });

        //鼠标拖动事件
        scene.setOnMouseDragged(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent mouseEvent) {
                stage.setX(mouseEvent.getScreenX() - x);
                stage.setY(mouseEvent.getScreenY() - y);
            }
        });
        //添加css样式
        scene.getStylesheets().addAll("/css/tabPane.css",
                "/css/topButton.css",
                "/css/textFiled.css",
                "/css/button.css",
                "/css/hBox.css",
                "/css/topHBox.css",
                "/css/progressBar.css",
                "/css/menuBar.css",
                "/css/label.css"
        );
        //添加图标
        stage.getIcons().add(new Image("icon/system.jpeg"));
    }

    @Override
    public void stop() throws Exception {
        super.stop();
    }
}

创建启动类BrowserStart

package com.kur.ban;
import javafx.application.Application;

//因为未使用模块化所以需要此启动方式,不然会报javafx缺少组件的错误
public class BrowserStart {
    public static void main(String[] args){
        Application.launch(BrowserApplication.class, args);
    }
}

创建Element_Tab

package com.kur.ban;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileReader;
import cn.hutool.core.io.file.FileWriter;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import javafx.collections.ListChangeListener;
import javafx.concurrent.Worker;
import javafx.scene.control.*;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URLConnection;
import java.util.*;

public class Element_Tab {
    private static String tittle;

    public static Tab getTab(TabPane tabPane, Stage stage) throws IOException {
        Log log = LogFactory.get();
        Tab tab = new Tab();
        BorderPane borderPane = new BorderPane();
        tab.setContent(borderPane);
        WebView webView = new WebView();
        WebEngine engine = webView.getEngine();
        engine.load("https://www.baidu.com");
        webView.setContextMenuEnabled(true);
        TextField textField = Element_TextFiled.getTextField(engine);
        textField.setId("textFiled");
        Button retreat = Element_Button.retreat(engine);
        Button advance = Element_Button.advance(engine);
        Button refresh = Element_Button.refresh(engine);
        Button go = Element_Button.go(textField, engine);
        Button addTab = Element_Button.addTab(tabPane, stage);
        MenuBar menuBar = Element_MenuBar.getMenuBar(engine, stage);


        MenuBar downloadMenuBar = new MenuBar();
        downloadMenuBar.setId("downloadMenuBar");
        Menu downloadMenu = new Menu("下载管理");
        downloadMenu.setId("downloadMenu");
        downloadMenuBar.getMenus().addAll(downloadMenu);

        HBox topHBox = new HBox(retreat, advance, textField, go, addTab, refresh, menuBar, downloadMenuBar);
        topHBox.setId("topHBox");
        topHBox.setFillHeight(true);
        borderPane.setTop(topHBox);
        borderPane.setCenter(webView);
        ProgressBar progressBar = Element_ProgressBar.getProgressBar(webView, engine);
        progressBar.setId("progressBar");
        borderPane.setBottom(progressBar);
        engine.getLoadWorker().stateProperty().addListener((observableValue, state, t1) -> {
            if (t1 == Worker.State.FAILED) {
                engine.reload();
                Alert alert = new Alert(Alert.AlertType.ERROR);
                alert.initOwner(stage);
                alert.setTitle("加载错误");
                alert.setContentText("您的网址有误! 请输入正确的网址." + "\n检查网络连接是否正常.");
                alert.getButtonTypes().addListener((ListChangeListener<ButtonType>) change -> {
                    Button button = (Button) change.getList();
                    button.setOnAction(actionEvent -> {
                        textField.isFocused();
                        engine.reload();
                    });
                });
                alert.show();
            }
        });
        engine.titleProperty().addListener((observableValue, oldValue, newValue) -> {
            tab.setText(newValue);
            if (newValue != null) {
                String[] split = newValue.split(" ");
                List<String> list = Arrays.stream(split).toList();
                tittle = list.get(0);
            }
        });

        engine.locationProperty().addListener((observableValue, oldValue, newValue) -> {
            String contentTypeFromName = URLConnection.guessContentTypeFromName(newValue);
            if (contentTypeFromName != null) {
                String extName = FileUtil.extName(newValue);

                DownloadProgram program = new DownloadProgram();

                program.downloadBefore(newValue, tittle, stage, downloadMenu, extName);
            }
        });


        String property = System.getProperty("file.separator");
        String path = "D:" + property + "Browser" + property + "download.txt";
        FileReader fileReader = new FileReader(path, "UTF-8");
        HashMap<String, String> map = new HashMap<>();
        String[] str = new String[50];
        int i = 0;
        for (String readLine : fileReader.readLines()) {
            String trim = readLine.trim();
            if (!trim.isEmpty()) {
                String[] split = trim.split("&");
                List<String> list = Arrays.stream(split).toList();

                File file = new File(list.get(1));
                if (file.exists()) {
                    i = i + 1;
                    log.info("检测到文件[ " + list.get(0) + " ]存在");
                    map.put(list.get(0), list.get(1));
                    str[i] = list.get(0);

                    VBox vBox = Element_MenuItem.getItem(list.get(0), map.get(list.get(0)));
                    MenuItem menuItem = new MenuItem();
                    menuItem.setGraphic(vBox);
                    downloadMenu.getItems().addAll(menuItem);
                } else {
                    log.info("检测到文件[ " + list.get(0) + " ]不存在");
                }
            }
        }
        for (String key : str) {
            if (key != null) {
                System.out.println("map.get(key) = " + map.get(key));
            }
        }

        String del = "D:" + property + "Browser" + property + "download.txt";
        File file = new File(del);
        if (file.exists()) {
            if (file.delete()) {
                log.info("成功删除文件:" + del);

            } else {
                log.info("删除失败: " + del);
            }
        }
        CreateFile.newFile();
        File write = new File(del);
        if (write.exists()) {
            FileWriter fileWriter = new FileWriter(write);
            for (String key : str) {
                if (key != null) {
                    fileWriter.append("\n" + key + "&" + map.get(key));
                }
            }
        }
        return tab;
    }
}

创建CreateFile

package com.kur.ban;

import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;

import java.io.File;
import java.io.IOException;

public class CreateFile {
    private static final Log log = LogFactory.get();

    public static void newFile() throws IOException {
        //获取系统的\
        String property = System.getProperty("file.separator");
        File file = new File("D:" + property + "Browser");
        //file.exists() 此方法为检测路径是否存在
        if (file.exists()) {
            String path = file.getAbsolutePath() + property + "download.txt";
            File download = new File(path);
            if (download.exists()) {
                log.info("默认存放下载记录的文件已存在");
            } else {
                if (download.createNewFile()) {
                    log.info("成功创建默认存放下载记录的文件");
                } else {
                    log.debug("创建默认存放下载记录的文件失败");
                }
            }
        } else {
            //file.mkdir() 此方法为创建文件夹的方法
            if (file.mkdir()) {
                String path = file.getAbsolutePath() + property + "download.txt";
                File download = new File(path);
                //download.createNewFile() 此方法为创建文件
                if (download.createNewFile()) {
                    log.info("成功创建默认存放下载记录的文件");
                }
                log.info("成功创建存放下载记录的文件的目标文件夹");
            }
        }
    }
}

创建Element_Button

package com.kur.ban;

import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import javafx.scene.control.Button;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebHistory;
import javafx.stage.Stage;

import java.io.FileNotFoundException;
import java.io.IOException;

public class Element_Button {
    private static final Log log = LogFactory.get();
    public static Button retreat(WebEngine engine) {

        ImageView image = new ImageView(new Image("icon/img_1.png", 29, 29, true, true));
        Button button = new Button("", image);
        button.setId("retreat");
        button.setPrefWidth(4);
        button.setPrefHeight(32);
        button.setOnAction(actionEvent -> {
            WebHistory history = engine.getHistory();
            try {
                history.go(-1);
            } catch (Exception e) {
                log.debug("-1索引越界");
                throw new RuntimeException(e);
            }

        });
        return button;
    }

    public static Button advance(WebEngine engine) {
        ImageView image = new ImageView(new Image("icon/img_1.png", 29, 29, true, true));
        Button button = new Button("", image);
        button.setId("advance");
        button.setPrefWidth(40);
        button.setPrefHeight(32);
        image.setRotate(180);
        button.setOnAction(actionEvent -> button.setOnAction(actionEvent1 -> {
            WebHistory history = engine.getHistory();
            try {
                history.go(1);
            } catch (Exception e) {
                log.debug("1索引越界");
                throw new RuntimeException(e);
            }
        }));
        return button;
    }

    public static Button refresh(WebEngine engine) {
        ImageView image = new ImageView(new Image("icon/img_2.png", 29, 29, true, true));
        Button button = new Button("", image);
        button.setId("refresh");
        button.setPrefWidth(40);
        button.setPrefHeight(32);
        button.setOnAction(actionEvent -> engine.reload());
        return button;
    }

    public static Button addTab(TabPane tabPane, Stage stage) {
        ImageView image = new ImageView(new Image("icon/img_5.png", 29, 29, true, true));
        Button button = new Button("", image);
        button.setId("addTab");
        button.setPrefWidth(40);
        button.setPrefHeight(32);
        button.setOnAction(actionEvent -> {
            try {
                Tab tab = Element_Tab.getTab(tabPane, stage);
                tabPane.getTabs().addAll(tab);

            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        });
        return button;
    }

    public static Button go(TextField textField, WebEngine engine) {
        Button button = new Button("Go");
        button.setId("go");
        button.setPrefWidth(48);
        button.setPrefHeight(40);
        button.setOnAction(actionEvent -> engine.load(textField.getText()));
        return button;
    }
}

创建Element_AlertStage

package com.kur.ban;

import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.RadioButton;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.StageStyle;

public class Element_AlertStage {
    public static Stage getAlertStage(Stage stage) {

        Stage alertStage = new Stage();
        AnchorPane anchorPane = new AnchorPane();
        Scene scene = new Scene(anchorPane);
        alertStage.setScene(scene);
        alertStage.setWidth(250);
        alertStage.setHeight(200);
        alertStage.initStyle(StageStyle.TRANSPARENT);
        alertStage.initModality(Modality.APPLICATION_MODAL);
        alertStage.initOwner(stage);
        ToggleGroup group = new ToggleGroup();
        RadioButton min = new RadioButton("最小化到系统托盘");
        min.setId("min");
        min.setSelected(true);
        RadioButton max = new RadioButton("退出班班浏览器");
        max.setId("max");
        min.setToggleGroup(group);
        max.setToggleGroup(group);
        Button sure = new Button("确定");
        sure.setId("sure");
        Button close = new Button("关闭");
        close.setId("close");
        anchorPane.getChildren().addAll(close, min, max, sure);
        scene.getStylesheets().addAll("/css/alert.css");
        alertStage.show();

        AnchorPane.setTopAnchor(close, 00.0);
        AnchorPane.setLeftAnchor(close, alertStage.getWidth() - close.getWidth());
        AnchorPane.setTopAnchor(min, 70.0);
        AnchorPane.setLeftAnchor(min, alertStage.getWidth() / 2 - min.getWidth() / 2);
        AnchorPane.setTopAnchor(max, 100.0);
        AnchorPane.setLeftAnchor(max, alertStage.getWidth() / 2 - min.getWidth() / 2);
        AnchorPane.setTopAnchor(sure, 140.0);
        AnchorPane.setLeftAnchor(sure, alertStage.getWidth() / 2 - sure.getWidth() / 2);
        sure.setOnAction(actionEvent -> {
            if (min.isSelected()) {
                Platform.setImplicitExit(false);
                Element_SystemTray.getSystemTray(stage);
                alertStage.close();
                stage.hide();
            } else {
                alertStage.close();
                stage.close();
                Platform.exit();
            }
        });
        close.setOnAction(actionEvent -> alertStage.close());
        return alertStage;
    }
}

创建Element_HistoryStage

package com.kur.ban;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebHistory;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.StageStyle;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Element_HistoryStage {
    public static Stage getHistoryStage(WebEngine engine, Stage stage) {
        Stage historyStage = new Stage();
        ListView<String> listView = new ListView<>();
        Scene scene = new Scene(listView);
        historyStage.setScene(scene);
        historyStage.setWidth(300);
        historyStage.setHeight(600);
        historyStage.initStyle(StageStyle.UTILITY);
        historyStage.initModality(Modality.APPLICATION_MODAL);
        historyStage.setX(1200);
        historyStage.setY(200);
        historyStage.initOwner(stage);

        historyStage.setTitle("历史记录");
        ObservableList<String> list = FXCollections.observableArrayList();
        ObservableList<WebHistory.Entry> history = engine.getHistory().getEntries();
        history.forEach(entry -> {
            String url = entry.getUrl();
            String title = entry.getTitle();
            list.add(title + "\n" + url);
        });

        listView.setItems(list);

        listView.getSelectionModel().selectedItemProperty().addListener((observableValue, s, t1) -> {
            String[] split = t1.split("\n");

            List<String> urlList = Arrays.stream(split).toList();

            engine.load(urlList.get(1));
        });
        scene.getStylesheets().addAll("/css/listView.css");

        return historyStage;
    }
}

创建Element_MenuBar

package com.kur.ban;

import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.input.KeyCombination;
import javafx.scene.web.WebEngine;
import javafx.stage.Stage;

public class Element_MenuBar {
    public static MenuBar getMenuBar(WebEngine engine, Stage stage) {

        MenuBar menuBar = new MenuBar();
        menuBar.setId("toolBar");
        Menu menu = new Menu("工具");
        menu.setId("toolMenu");
        MenuItem history = new MenuItem("历史记录");
        history.setId("history");
        history.setAccelerator(KeyCombination.valueOf("ctrl+h"));
        menu.getItems().addAll(history);
        menuBar.getMenus().add(menu);
        history.setOnAction(actionEvent -> Element_HistoryStage.getHistoryStage(engine, stage).show());
        return menuBar;
    }
}

创建Element_MenuItem

package com.kur.ban;

import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;

import java.awt.*;
import java.io.File;
import java.io.IOException;

public class Element_MenuItem {
    private static final Log log= LogFactory.get();

    public static VBox getItem(String tittle,String saveFile){
        VBox vBox = new VBox();
        HBox hBox = new HBox();
        Label tittleLabel = new Label();
        tittleLabel.setText(tittle);
        Label saveFileLabel = new Label();
        saveFileLabel.setMaxWidth(200);
        saveFileLabel.setMinWidth(200);
        saveFileLabel.setText(saveFile);
        Button open = new Button("打开文件夹");
        Button delete = new Button("删除");
        hBox.getChildren().addAll(saveFileLabel, open, delete);
        vBox.getChildren().addAll(tittleLabel, hBox);
        hBox.setSpacing(5);
        vBox.setAlignment(Pos.CENTER);
        hBox.setAlignment(Pos.CENTER);
        vBox.setMinWidth(150);
        open.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent actionEvent) {
                System.out.println(saveFileLabel.getText());
                File file = new File(saveFileLabel.getText());
                Desktop desktop = Desktop.getDesktop();
                try {
                    desktop.open(new File(file.getParent()));
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        delete.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent actionEvent) {
                File file = new File(saveFileLabel.getText());
                if (file.delete()){
                    delete.setText("已删除");
                    delete.setDisable(true);
                    log.info("成功删除文件: [ "+saveFileLabel.getText()+" ]");
                }else {
                    log.info("删除失败: [ "+saveFileLabel.getText()+" ]");
                }
            }
        });
        return vBox;
    }
}

创建Element_ProgressBar

package com.kur.ban;

import javafx.scene.control.ProgressBar;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;

public class Element_ProgressBar {

    public static ProgressBar getProgressBar(WebView webView, WebEngine engine) {
        ProgressBar progressBar = new ProgressBar();
        progressBar.getStylesheets().addAll("/css/progressBar.css");

        webView.widthProperty().addListener((observableValue, number, xin) -> progressBar.setPrefWidth(xin.doubleValue()));
        engine.getLoadWorker().progressProperty().addListener((observableValue, number, t1) -> progressBar.setProgress(t1.doubleValue()));
        return progressBar;
    }
}

创建Element_SystemTray

package com.kur.ban;

import javafx.application.Platform;
import javafx.stage.Stage;

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

public class Element_SystemTray {

    public static void getSystemTray(Stage stage) {
        SystemTray systemTray = SystemTray.getSystemTray();

        Image image = Toolkit.getDefaultToolkit().getImage("D:\\JavaFXCode\\MyBrowser\\src\\main\\resources\\icon\\img_2.png");

        PopupMenu popupMenu = new PopupMenu();
        MenuItem item1 = new MenuItem("quit");
        item1.setFont(new Font("微软雅黑", Font.BOLD, 20));
        MenuItem item2 = new MenuItem("show");
        popupMenu.add(item1);
        popupMenu.add(item2);
        popupMenu.setFont(new Font("微软雅黑", Font.BOLD, 20));
        TrayIcon trayIcon = new TrayIcon(image, "班班浏览器", popupMenu);
        trayIcon.setImageAutoSize(true);
        try {
            systemTray.add(trayIcon);
        } catch (AWTException e) {
            throw new RuntimeException(e);
        }

        item1.addActionListener(e -> {
            Platform.runLater(stage::close);
            systemTray.remove(trayIcon);
            Platform.exit();
        });
        item2.addActionListener(e -> {

            Platform.runLater(stage::show);
            systemTray.remove(trayIcon);
        });

        trayIcon.addMouseListener(new MouseListener() {
            @Override
            public void mouseClicked(MouseEvent e) {
                if (e.getClickCount() == 2) {
                    Platform.runLater(stage::show);
                    systemTray.remove(trayIcon);
                }
            }

            @Override
            public void mousePressed(MouseEvent e) {

            }

            @Override
            public void mouseReleased(MouseEvent e) {

            }

            @Override
            public void mouseEntered(MouseEvent e) {

            }

            @Override
            public void mouseExited(MouseEvent e) {

            }

        });
    }
}

创建Element_TextFiled

package com.kur.ban;

import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import javafx.application.Platform;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.web.WebEngine;

import java.net.MalformedURLException;
import java.net.URL;

public class Element_TextFiled {
    private static final Log log=LogFactory.get();
    public static TextField getTextField(WebEngine engine) {
        TextField textField = new TextField();
        textField.setPrefWidth(900);
        textField.setPrefHeight(40);
        textField.setText(engine.getLocation());
        engine.locationProperty().addListener((observableValue, s, t1) -> textField.setText(t1));

        textField.setOnKeyReleased(keyEvent -> {
            if (keyEvent.getCode() == KeyCode.ENTER) {
                String text = textField.getText();
                Platform.runLater(() -> {
                    String url = toURL(text);
                    if (url == null) {
                        url = toURL("https://" + text);
                    }
                    engine.load(url);
                });
            }
        });
        return textField;
    }

    public static String toURL(String url) {
        try {
            return new URL(url).toExternalForm();
        } catch (MalformedURLException e) {

            log.debug("网址解析失败:"+e.getMessage());

            return null;
        }
    }
}

创建Element_TopButton

package com.kur.ban;

import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

public class Element_TopButton {
    public static HBox getTopButton(Stage stage) {
        Button min = new Button("最小化");
        min.setId("min");
        Button max = new Button("最大化");
        max.setId("max");
        Button close = new Button("关闭");
        close.setId("close");
        HBox hBox = new HBox();
        hBox.setId("hBox");
        hBox.getChildren().addAll(min, max, close);
        hBox.setAlignment(Pos.BASELINE_RIGHT);
        close.setOnAction(actionEvent -> {
            Stage alertStage = Element_AlertStage.getAlertStage(stage);
            alertStage.show();
        });
        max.setOnAction(actionEvent -> {
            boolean fullScreen = stage.isFullScreen();
            stage.setFullScreen(!fullScreen);
        });
        min.setOnAction(actionEvent -> stage.setIconified(true));

        hBox.setOnMouseClicked(mouseEvent -> {
            if (mouseEvent.getClickCount() == 2) {
                stage.setMaximized(!stage.isMaximized());
            }
        });
        return hBox;
    }
}

创建DownloadProgram

package com.kur.ban;
import cn.hutool.core.io.file.FileWriter;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.control.*;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuItem;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import java.awt.*;
import java.io.File;
import java.io.IOException;
public class DownloadProgram {

    private File saveFile = null;

    /**
     *
     * @param url 文件下载地址
     * @param tittle 文件的标题
     * @param stage 用来子窗口的父窗口
     * @param downloadMenu 把生成的MenuItem放入menu
     * @param extName 根据网址解析的文件类型,比如exe,MP3之类的
     */
    public void downloadBefore(String url, String tittle, Stage stage, Menu downloadMenu, String extName) {

        FileChooser chooser = new FileChooser();

        Log log = LogFactory.get();

        //如果文件类型是exe的话文件保存框的保存类型就只有exe格式
        //下面以此类推
        if (extName.equals("exe")){
            chooser.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("应用程序", "*.exe"));
        }else if (extName.equals("png")){
            chooser.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("图片类型", "*.png"));
        } else if (extName.equals("jpg")) {
            chooser.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("图片类型", "*.jpg"));
        }else if (extName.equals("jpeg")) {
            chooser.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("图片类型", "*.jpeg"));
        }else if (extName.equals("txt")) {
            chooser.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("文本类型", "*.txt"));
        }else if (extName.equals("mp3")) {
            chooser.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("音乐类型", "*.mp3"));
        }else if (extName.equals("mp4")) {
            chooser.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("视频类型", "*.mp4"));
        }else if (extName.equals("zip")) {
            chooser.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("压缩文件", "*.zip"));
        }else if (extName.equals("tar.gz")) {
            chooser.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("压缩文件", "*.tar.gz"));
        }

        //文件的默认保存的文件名是标题加文件类型
        chooser.setInitialFileName(tittle + "." + extName);
        Stage fileStage = new Stage();
        fileStage.setWidth(600);
        fileStage.setHeight(500);
        fileStage.initOwner(stage);
        chooser.setTitle(tittle);

        //如果文件类型是下面的类型才会弹出文件保存框
        if (extName.equals("exe")||extName.equals("png")||extName.equals("jpg")||
                extName.equals("jpeg")||extName.equals("txt")||extName.equals("mp3")||
                extName.equals("mp4")||extName.equals("zip")||extName.equals("tag.gz")
        ){
            saveFile = chooser.showSaveDialog(fileStage);
        }

        //saveFile 文件保存路径
        if (saveFile != null) {
            log.info("文件名称是:"+saveFile.getName());
            tittle=saveFile.getName();
            //创建MenuItem
            MenuItem menuItem = new MenuItem();
            VBox vBox = new VBox();
            HBox hBox = new HBox();
            //显示标题的label
            Label tittleLabel = new Label();
            //显示状态消息的label
            Label msgLabel = new Label();
            msgLabel.setMinWidth(60);
            msgLabel.setMaxWidth(60);
            //下载进度条
            ProgressBar progressBar = new ProgressBar();
            progressBar.setMinWidth(133);
            progressBar.setMaxWidth(133);
            //往menu添加menuItem
            downloadMenu.getItems().addAll(menuItem);
            //两个功能按钮
            Button open = new Button("打开文件夹");
            hBox.setSpacing(5);
            //把组件放进布局里
            hBox.getChildren().addAll(msgLabel, progressBar, open);
            vBox.getChildren().addAll(tittleLabel, hBox);
            tittleLabel.setText(saveFile.getName());
            vBox.setAlignment(Pos.CENTER);
            hBox.setAlignment(Pos.CENTER);
            vBox.setMinWidth(150);

            //DownloadUtils 下载工具类,使用了javafx的多线程
            DownloadUtils downloadUtils = new DownloadUtils();
            downloadUtils.setUrl(url);
            downloadUtils.setSaveFile(saveFile);
            downloadUtils.start();
            //graphic- 新的对话框图形
            menuItem.setGraphic(vBox);

            String finalTittle = tittle;

            //此监听返回下载进度
            downloadUtils.progressProperty().addListener((observableValue, oldValue, newValue) -> {
                progressBar.setProgress(newValue.doubleValue());
                //如果下载完成就往下载历史文件写入记录
                if (newValue.doubleValue() >= 1) {
                    //下载完成就取消多线程
                    downloadUtils.cancel();
                    //根据系统获取\
                    String property = System.getProperty("file.separator");
                    //下载历史文件路径
                    String path = "D:" + property + "Browser" + property + "download.txt";
                    File write = new File(path);
                    FileWriter fileWriter = new FileWriter(write, "UTF-8");
                    //写入记录
                    fileWriter.append(finalTittle + "&" + saveFile+"\n");
                    log.info("成功下载文件");
                    log.info("写入下载记录成功");
                }
            });
            //监听下载时的消息
            downloadUtils.messageProperty().addListener(new ChangeListener<String>() {
                @Override
                public void changed(ObservableValue<? extends String> observableValue, String oldValue, String newValue) {
                    msgLabel.setText(newValue);
                }
            });
            //打开文件夹
            open.setOnAction(new EventHandler<ActionEvent>() {
                @Override
                public void handle(ActionEvent actionEvent) {
                    Desktop desktop = Desktop.getDesktop();
                    try {
                        desktop.open(new File(saveFile.getParent()));
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            });
        }
    }
}

创建DownloadUtils

package com.kur.ban;

import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
/**
 * 此类为JavaFX多线程类
 * 继承Service重写方法
 */
public class DownloadUtils extends Service<Double> {
    private final StringProperty url = new SimpleStringProperty();
    private File saveFile;

    public String getUrl() {
        return url.get();
    }

    public void setUrl(String url) {
        this.url.set(url);
    }

    public File getSaveFile() {
        return saveFile;
    }

    public void setSaveFile(File saveFile) {
        this.saveFile = saveFile;
    }

    protected Task<Double> createTask() {
        final String newLoc = getUrl();
        final File saveFile = getSaveFile();
        return new Task<>() {
            protected Double call() throws Exception {
                //根据收到的网址返回HttpURLConnection
                HttpURLConnection urlConnection = (HttpURLConnection) new URL(newLoc).openConnection();
                //根据HttpURLConnection返回InputStream流
                InputStream inputStream = urlConnection.getInputStream();
                //输入流
                FileOutputStream outputStream = new FileOutputStream(saveFile);
                //获取要下载文件的总字节数
                int length = urlConnection.getContentLength();
                //每次下载的字节数
                int sum;
                //下载字节数的总和
                long downloadSize = 0;
                //进度条
                double progress = 0;
                byte[] bytes = new byte[4096];
                //下面就是读取流和输入流操作
                while ((sum = inputStream.read(bytes)) != -1) {
                    downloadSize += sum;
                    outputStream.write(bytes, 0, sum);
                    progress = downloadSize / (double) length;
                    
                    //更新Service类进度条方法的值
                    this.updateProgress(downloadSize, length);
                    if (progress <= 0.1) {
                        //更新Service类进消息方法的值
                        this.updateMessage("开始下载");
                    } else if (progress < 0.4) {

                        this.updateMessage("请耐心等待");
                    } else if (progress < 0.8) {

                        this.updateMessage("马上就好");
                    } else if (progress < 1) {

                        this.updateMessage("即将完成");
                    } else if (progress >= 1) {
                        this.updateMessage("下载成功");
                    }
                }
                inputStream.close();
                outputStream.close();
                return progress;
            }
        };
    }

}

css样式:alert.css

#sure{
    -fx-background-color: rgba(236, 245, 255, 1);
    -fx-background-radius: 5px 5px 5px 5px;
    -fx-border-color: rgba(179, 216, 255, 1) rgba(179, 216, 255, 1) rgba(179, 216, 255, 1) rgba(179, 216, 255, 1);
    -fx-border-radius: 5px 5px 5px 5px;
    -fx-text-fill: rgba(64, 158, 255, 1);
    -fx-font-size: 15px;
    -fx-padding: 5px 10px 5px 10px;
    -fx-cursor: HAND;
}
#close{
    -fx-background-color: rgba(236, 245, 255, 1);
    -fx-background-radius: 5px 5px 5px 5px;
    -fx-border-color: rgba(179, 216, 255, 1) rgba(179, 216, 255, 1) rgba(179, 216, 255, 1) rgba(179, 216, 255, 1);
    -fx-border-radius: 5px 5px 5px 5px;
    -fx-text-fill: rgba(64, 158, 255, 1);
    -fx-font-size: 15px;
    -fx-padding: 5px 10px 5px 10px;
    -fx-cursor: HAND;
}
#sure:hover {
    -fx-background-color: rgba(64, 158, 255, 1);
    -fx-border-color: rgba(64, 158, 255, 1) rgba(64, 158, 255, 1) rgba(64, 158, 255, 1) rgba(64, 158, 255, 1);
    -fx-text-fill: rgba(255, 255, 255, 1);
}
#close:hover {
    -fx-background-color: rgba(64, 158, 255, 1);
    -fx-border-color: rgba(64, 158, 255, 1) rgba(64, 158, 255, 1) rgba(64, 158, 255, 1) rgba(64, 158, 255, 1);
    -fx-text-fill: rgba(255, 255, 255, 1);
}
#sure:pressed {
    -fx-background-color: rgba(58, 142, 230, 1);
    -fx-border-color: rgba(58, 142, 230, 1) rgba(58, 142, 230, 1) rgba(58, 142, 230, 1) rgba(58, 142, 230, 1);
    -fx-text-fill: rgba(255, 255, 255, 1);
}
#close:pressed {
    -fx-background-color: rgba(58, 142, 230, 1);
    -fx-border-color: rgba(58, 142, 230, 1) rgba(58, 142, 230, 1) rgba(58, 142, 230, 1) rgba(58, 142, 230, 1);
    -fx-text-fill: rgba(255, 255, 255, 1);
}


#min{
    -fx-font-size:14px;
    -fx-text-fill:#303133;
}
#max{
    -fx-font-size:14px;
    -fx-text-fill:#303133;
}
#min > .radio{
    -fx-pref-width:16px;
    -fx-pref-height:16px;
    -fx-background-color: #F2F3F5;
    -fx-background-radius:8px;
    -fx-background-insets: 0;
    -fx-border-color:#D4D7DE;
    -fx-border-radius:8px;
}
#max > .radio{
    -fx-pref-width:16px;
    -fx-pref-height:16px;
    -fx-background-color: #F2F3F5;
    -fx-background-radius:8px;
    -fx-background-insets: 0;
    -fx-border-color:#D4D7DE;
    -fx-border-radius:8px;
}
#min > .radio > .dot{
    -fx-background-color: transparent;
    -fx-background-insets: 0;
    -fx-padding: 3px;
}
#max > .radio > .dot{
    -fx-background-color: transparent;
    -fx-background-insets: 0;
    -fx-padding: 3px;
}
#min:selected{
    -fx-text-fill:#5C80EF;
}
#max:selected{
    -fx-text-fill:#5C80EF;
}
#min:selected > .radio{
    -fx-background-color: #5C80EF;
    -fx-border-color:transparent;
}
#max:selected > .radio{
    -fx-background-color: #5C80EF;
    -fx-border-color:transparent;
}
#min:selected > .radio > .dot{
    -fx-background-insets: 0;
    -fx-background-color: rgb(255,255,255);
}
#max:selected > .radio > .dot{
    -fx-background-insets: 0;
    -fx-background-color: rgb(255,255,255);
}
.scene{
    -fx-background-color: rgba(236, 245, 255, 1);
    -fx-background-radius: 5px 5px 5px 5px;
}

button.css

#retreat{
    -fx-background-color: rgba(236, 245, 255, 1);
    -fx-background-radius: 5px 5px 5px 5px;
    -fx-border-color: rgba(179, 216, 255, 1) rgba(179, 216, 255, 1) rgba(179, 216, 255, 1) rgba(179, 216, 255, 1);
    -fx-border-radius: 5px 5px 5px 5px;
    -fx-text-fill: rgba(64, 158, 255, 1);
    -fx-cursor: HAND;
}
#retreat:hover {
    -fx-background-color: rgba(64, 158, 255, 1);
    -fx-border-color: rgba(64, 158, 255, 1) rgba(64, 158, 255, 1) rgba(64, 158, 255, 1) rgba(64, 158, 255, 1);
    -fx-text-fill: rgba(255, 255, 255, 1);
}
#retreat:pressed {
    -fx-background-color: rgba(58, 142, 230, 1);
    -fx-border-color: rgba(58, 142, 230, 1) rgba(58, 142, 230, 1) rgba(58, 142, 230, 1) rgba(58, 142, 230, 1);
    -fx-text-fill: rgba(255, 255, 255, 1);
}
#advance{
    -fx-background-color: rgba(236, 245, 255, 1);
    -fx-background-radius: 5px 5px 5px 5px;
    -fx-border-color: rgba(179, 216, 255, 1) rgba(179, 216, 255, 1) rgba(179, 216, 255, 1) rgba(179, 216, 255, 1);
    -fx-border-radius: 5px 5px 5px 5px;
    -fx-text-fill: rgba(64, 158, 255, 1);
    -fx-cursor: HAND;
}
#advance:hover {
    -fx-background-color: rgba(64, 158, 255, 1);
    -fx-border-color: rgba(64, 158, 255, 1) rgba(64, 158, 255, 1) rgba(64, 158, 255, 1) rgba(64, 158, 255, 1);
    -fx-text-fill: rgba(255, 255, 255, 1);
}
#advance:pressed {
    -fx-background-color: rgba(58, 142, 230, 1);
    -fx-border-color: rgba(58, 142, 230, 1) rgba(58, 142, 230, 1) rgba(58, 142, 230, 1) rgba(58, 142, 230, 1);
    -fx-text-fill: rgba(255, 255, 255, 1);
}
#refresh{
    -fx-background-color: rgba(236, 245, 255, 1);
    -fx-background-radius: 5px 5px 5px 5px;
    -fx-border-color: rgba(179, 216, 255, 1) rgba(179, 216, 255, 1) rgba(179, 216, 255, 1) rgba(179, 216, 255, 1);
    -fx-border-radius: 5px 5px 5px 5px;
    -fx-text-fill: rgba(64, 158, 255, 1);
    -fx-cursor: HAND;
}
#refresh:hover {
    -fx-background-color: rgba(64, 158, 255, 1);
    -fx-border-color: rgba(64, 158, 255, 1) rgba(64, 158, 255, 1) rgba(64, 158, 255, 1) rgba(64, 158, 255, 1);
    -fx-text-fill: rgba(255, 255, 255, 1);
}
#refresh:pressed {
    -fx-background-color: rgba(58, 142, 230, 1);
    -fx-border-color: rgba(58, 142, 230, 1) rgba(58, 142, 230, 1) rgba(58, 142, 230, 1) rgba(58, 142, 230, 1);
    -fx-text-fill: rgba(255, 255, 255, 1);
}
#addTab{
    -fx-background-color: rgba(236, 245, 255, 1);
    -fx-background-radius: 5px 5px 5px 5px;
    -fx-border-color: rgba(179, 216, 255, 1) rgba(179, 216, 255, 1) rgba(179, 216, 255, 1) rgba(179, 216, 255, 1);
    -fx-border-radius: 5px 5px 5px 5px;
    -fx-text-fill: rgba(64, 158, 255, 1);
    -fx-cursor: HAND;
}
#addTab:hover {
    -fx-background-color: rgba(64, 158, 255, 1);
    -fx-border-color: rgba(64, 158, 255, 1) rgba(64, 158, 255, 1) rgba(64, 158, 255, 1) rgba(64, 158, 255, 1);
    -fx-text-fill: rgba(255, 255, 255, 1);
}
#addTab:pressed {
    -fx-background-color: rgba(58, 142, 230, 1);
    -fx-border-color: rgba(58, 142, 230, 1) rgba(58, 142, 230, 1) rgba(58, 142, 230, 1) rgba(58, 142, 230, 1);
    -fx-text-fill: rgba(255, 255, 255, 1);
}
#go{
    -fx-background-color: rgba(236, 245, 255, 1);
    -fx-background-radius: 5px 5px 5px 5px;
    -fx-border-color: rgba(179, 216, 255, 1) rgba(179, 216, 255, 1) rgba(179, 216, 255, 1) rgba(179, 216, 255, 1);
    -fx-border-radius: 5px 5px 5px 5px;
    -fx-text-fill: rgba(64, 158, 255, 1);
    -fx-cursor: HAND;
}
#go:hover {
    -fx-background-color: rgba(64, 158, 255, 1);
    -fx-border-color: rgba(64, 158, 255, 1) rgba(64, 158, 255, 1) rgba(64, 158, 255, 1) rgba(64, 158, 255, 1);
    -fx-text-fill: rgba(255, 255, 255, 1);
}
#go:pressed {
    -fx-background-color: rgba(58, 142, 230, 1);
    -fx-border-color: rgba(58, 142, 230, 1) rgba(58, 142, 230, 1) rgba(58, 142, 230, 1) rgba(58, 142, 230, 1);
    -fx-text-fill: rgba(255, 255, 255, 1);
}
#download{
    -fx-background-color: rgba(236, 245, 255, 1);
    -fx-background-radius: 5px 5px 5px 5px;
    -fx-border-color: rgba(179, 216, 255, 1) rgba(179, 216, 255, 1) rgba(179, 216, 255, 1) rgba(179, 216, 255, 1);
    -fx-border-radius: 5px 5px 5px 5px;
    -fx-text-fill: rgba(64, 158, 255, 1);
    -fx-cursor: HAND;
}
#download:hover {
    -fx-background-color: rgba(64, 158, 255, 1);
    -fx-border-color: rgba(64, 158, 255, 1) rgba(64, 158, 255, 1) rgba(64, 158, 255, 1) rgba(64, 158, 255, 1);
    -fx-text-fill: rgba(255, 255, 255, 1);
}
#download:pressed {
    -fx-background-color: rgba(58, 142, 230, 1);
    -fx-border-color: rgba(58, 142, 230, 1) rgba(58, 142, 230, 1) rgba(58, 142, 230, 1) rgba(58, 142, 230, 1);
    -fx-text-fill: rgba(255, 255, 255, 1);
}

hbox.css

#hBox{
    -fx-spacing: 5px;
}

label.css

.label{
    -fx-text-fill: #130c0e;
}

listview.css

.list-view {
    -fx-border-color: rgba(193, 197, 205, 1) rgba(193, 197, 205, 1) rgba(193, 197, 205, 1) rgba(193, 197, 205, 1);
    -fx-border-width: 1px 1px 1px 1px;
    -fx-background-insets: 0px 0px 0px 0px;
}
.list-view .list-cell {
    -fx-background-color: rgba(255, 255, 255, 1);
    -fx-font-size: 15px;
    -fx-text-fill: rgba(117, 117, 117, 1);
    -fx-padding: 10px 0px 10px 5px;
    -fx-border-color: rgba(0, 0, 0, 0) rgba(0, 0, 0, 0) rgba(235, 238, 245, 1) rgba(0, 0, 0, 0);
}
.list-view .list-cell:odd {
    -fx-background-color: rgba(255, 255, 255, 1);
}
.list-view .list-cell:hover {
    -fx-background-color: rgba(245, 247, 250, 1);
}
.list-view:focused .list-cell:selected {
    -fx-background-color: rgba(236, 245, 255, 1);
    -fx-text-fill: rgba(117, 117, 117, 1);
}
.list-view .scroll-bar .decrement-arrow {
    -fx-min-width: 0px;
    -fx-min-height: 0px;
    -fx-pref-width: 0px;
    -fx-pref-height: 0px;
    visibility: hidden;
}
.list-view .scroll-bar .increment-arrow {
    -fx-min-width: 0px;
    -fx-min-height: 0px;
    -fx-pref-width: 0px;
    -fx-pref-height: 0px;
    visibility: hidden;
}
.list-view .scroll-bar .decrement-button {
    -fx-min-width: 0px;
    -fx-min-height: 0px;
    -fx-pref-width: 0px;
    -fx-pref-height: 0px;
    visibility: hidden;
}
.list-view .scroll-bar .increment-button {
    -fx-min-width: 0px;
    -fx-min-height: 0px;
    -fx-pref-width: 0px;
    -fx-pref-height: 0px;
    visibility: hidden;
}
.list-view .scroll-bar:vertical {
    -fx-padding: 0px 0px 0px 0px;
    -fx-pref-width: 9px;
    -fx-background-color: rgba(255, 255, 255, 1);
}
.list-view .scroll-bar:vertical .thumb {
    -fx-background-color: rgba(221, 222, 224, 1);
    -fx-background-insets: 0px 0px 0px 0px;
    -fx-background-radius: 5px 5px 5px 5px;
}
.list-view .scroll-bar:vertical .thumb:pressed {
    -fx-background-color: rgba(199, 201, 204, 1);
}
.list-view:focused {
    -fx-border-color: rgba(50, 150, 255, 1) rgba(50, 150, 255, 1) rgba(50, 150, 255, 1) rgba(50, 150, 255, 1);
}

menubar.css

#toolBar{
    -fx-background-color: rgba(236, 245, 255, 1);
    -fx-background-radius: 5px 5px 5px 5px;
    -fx-border-color: rgba(179, 216, 255, 1) rgba(179, 216, 255, 1) rgba(179, 216, 255, 1) rgba(179, 216, 255, 1);
    -fx-border-radius: 5px 5px 5px 5px;
    -fx-text-fill: rgba(64, 158, 255, 1);
    -fx-cursor: HAND;
    -fx-max-height: 40px;
    -fx-max-width: 58px;
    -fx-alignment: center;
}
#toolMenu{
    -fx-background-color: rgba(236, 245, 255, 1);
    -fx-background-radius: 5px 5px 5px 5px;
    -fx-border-color: rgba(179, 216, 255, 1) rgba(179, 216, 255, 1) rgba(179, 216, 255, 1) rgba(179, 216, 255, 1);
    -fx-border-radius: 5px 5px 5px 5px;
    -fx-text-fill: rgba(64, 158, 255, 1);
    -fx-cursor: HAND;
    -fx-alignment: center;
    -fx-border-width: 0px;
}
#toolMenu:hover {
    -fx-background-color: rgba(64, 158, 255, 1);
    -fx-border-color: rgba(64, 158, 255, 1) rgba(64, 158, 255, 1) rgba(64, 158, 255, 1) rgba(64, 158, 255, 1);
    -fx-border-radius: 5px 5px 5px 5px;
    -fx-background-radius: 5px 5px 5px 5px;
    -fx-text-fill: rgba(255, 255, 255, 1);
}
#toolMenu:pressed {
    -fx-background-color: rgba(58, 142, 230, 1);
    -fx-border-color: rgba(58, 142, 230, 1) rgba(58, 142, 230, 1) rgba(58, 142, 230, 1) rgba(58, 142, 230, 1);
    -fx-border-radius: 5px 5px 5px 5px;
    -fx-background-radius: 5px 5px 5px 5px;
    -fx-text-fill: rgba(255, 255, 255, 1);
}

#history{
    -fx-background-color: rgba(236, 245, 255, 1);
    -fx-background-radius: 5px 5px 5px 5px;
    -fx-border-color: rgba(179, 216, 255, 1) rgba(179, 216, 255, 1) rgba(179, 216, 255, 1) rgba(179, 216, 255, 1);
    -fx-text-fill: rgba(64, 158, 255, 1);
    -fx-cursor: HAND;
    -fx-border-radius: 5px 5px 5px 5px;
}
#history:hover{
    -fx-background-color: rgba(64, 158, 255, 1);
    -fx-border-color: rgba(64, 158, 255, 1) rgba(64, 158, 255, 1) rgba(64, 158, 255, 1) rgba(64, 158, 255, 1);
    -fx-text-fill: rgba(255, 255, 255, 1);
}
#history:pressed{
    -fx-background-color: rgba(58, 142, 230, 1);
    -fx-border-color: rgba(58, 142, 230, 1) rgba(58, 142, 230, 1) rgba(58, 142, 230, 1) rgba(58, 142, 230, 1);
    -fx-text-fill: rgba(255, 255, 255, 1);
}
#downloadMenuBar{
    -fx-background-color: rgba(236, 245, 255, 1);
    -fx-background-radius: 5px 5px 5px 5px;
    -fx-border-color: rgba(179, 216, 255, 1) rgba(179, 216, 255, 1) rgba(179, 216, 255, 1) rgba(179, 216, 255, 1);
    -fx-border-radius: 5px 5px 5px 5px;
    -fx-text-fill: rgba(64, 158, 255, 1);
    -fx-max-height: 40px;
    -fx-max-width: 68px;
    -fx-alignment: center;
}
#downloadMenu{
    -fx-background-color: rgba(236, 245, 255, 1);
    -fx-background-radius: 5px 5px 5px 5px;
    -fx-border-color: rgba(179, 216, 255, 1) rgba(179, 216, 255, 1) rgba(179, 216, 255, 1) rgba(179, 216, 255, 1);
    -fx-border-radius: 5px 5px 5px 5px;
    -fx-text-fill: rgba(64, 158, 255, 1);
    -fx-alignment: center;
    -fx-border-width: 0px;
    -fx-min-width: 68px;
    -fx-min-height: 40px;
}
.menu-item{
    -fx-background-color: rgba(236, 245, 255, 1);
    -fx-background-radius: 5px 5px 5px 5px;
    -fx-border-color: rgba(179, 216, 255, 1) rgba(179, 216, 255, 1) rgba(179, 216, 255, 1) rgba(179, 216, 255, 1);
    -fx-border-radius: 5px 5px 5px 5px;
}
.menu-item:hover{
    -fx-background-color: rgba(64, 158, 255, 1);
}

progressbar.css

.progress-bar {
    -fx-indeterminate-bar-length: 70;
    -fx-indeterminate-bar-animation-time: 1.5;
}

.progress-bar > .track {
    -fx-background-color: #F2F3F5;
    -fx-border-color: #D4D7DE;
    -fx-border-radius: 3px;
}

.progress-bar > .bar {
    -fx-pref-height: 6px;
    -fx-background-insets: 0;
    -fx-background-radius: 3px;
    -fx-background-color:#5C80EF;
}

tabpane.css

.tab-pane {
    -fx-border-color: rgba(193, 197, 205, 1) rgba(193, 197, 205, 1) rgba(193, 197, 205, 1) rgba(193, 197, 205, 1);
    -fx-border-radius: 5px 5px 5px 5px;
    -fx-border-width: 0px;
    -fx-tab-min-width: 100px;
    -fx-tab-max-width: 150px;
    -fx-tab-min-height: 30px;
}
.tab-pane .tab-header-background {
    -fx-background-color: rgba(0, 0, 0, 0);
    -fx-border-color: rgba(228, 231, 237, 1) rgba(228, 231, 237, 1) rgba(228, 231, 237, 1) rgba(228, 231, 237, 1);
    -fx-border-width: 0px 0px 0px 0px;
}
.tab-pane:top .tab-header-area {
    -fx-background-insets: 0px 0px 1px 0px;
    -fx-padding: 5px 2px 5px 0px;
}
.tab-pane:focused .tab:selected {
    -fx-border-color: rgba(64, 158, 255, 1) rgba(64, 158, 255, 1) rgba(64, 158, 255, 1) rgba(64, 158, 255, 1);
}
.tab-pane:focused .tab:selected .tab-label {
    -fx-text-fill: rgba(64, 158, 255, 1);
}
.tab-pane:focused .tab:hover .tab-label {
    -fx-text-fill: rgba(64, 158, 255, 1);
}
.tab-pane .tab {
    -fx-padding: 1px 16px 1px 16px;
    -fx-cursor: HAND;
    -fx-background-color: rgba(0, 0, 0, 0);
    -fx-border-width: 0px 0px 0px 0px;
    -fx-border-color: rgba(228, 231, 237, 1) rgba(228, 231, 237, 1) rgba(228, 231, 237, 1) rgba(228, 231, 237, 1);
}
.tab-pane .tab .tab-label {
    -fx-font-size: 15px;
}
.tab-pane .tab .focus-indicator {
    -fx-border-width: 0px 0px 3px 0px;
}

textfiled.css

#textFiled{
    -fx-text-fill: #303133;
    -fx-font-size: 14px;
    -fx-font-weight: 500;
    -fx-border-color: #D4D7DE;
    -fx-border-radius: 3px;
    -fx-background-radius: 3px;
    -fx-background-insets:0;
    -fx-background-color:transparent;
}

topbutton.css

#min{
    -fx-background-color: rgba(236, 245, 255, 1);
    -fx-background-radius: 5px 5px 5px 5px;
    -fx-border-color: rgba(179, 216, 255, 1) rgba(179, 216, 255, 1) rgba(179, 216, 255, 1) rgba(179, 216, 255, 1);
    -fx-border-radius: 5px 5px 5px 5px;
    -fx-text-fill: rgba(64, 158, 255, 1);
    -fx-font-size: 15px;
    -fx-padding: 5px 10px 5px 10px;
    -fx-cursor: HAND;
}
#max{
    -fx-background-color: rgba(236, 245, 255, 1);
    -fx-background-radius: 5px 5px 5px 5px;
    -fx-border-color: rgba(179, 216, 255, 1) rgba(179, 216, 255, 1) rgba(179, 216, 255, 1) rgba(179, 216, 255, 1);
    -fx-border-radius: 5px 5px 5px 5px;
    -fx-text-fill: rgba(64, 158, 255, 1);
    -fx-font-size: 15px;
    -fx-padding: 5px 10px 5px 10px;
    -fx-cursor: HAND;
}
#close{
    -fx-background-color: rgba(236, 245, 255, 1);
    -fx-background-radius: 5px 5px 5px 5px;
    -fx-border-color: rgba(179, 216, 255, 1) rgba(179, 216, 255, 1) rgba(179, 216, 255, 1) rgba(179, 216, 255, 1);
    -fx-border-radius: 5px 5px 5px 5px;
    -fx-text-fill: rgba(64, 158, 255, 1);
    -fx-font-size: 15px;
    -fx-padding: 5px 10px 5px 10px;
    -fx-cursor: HAND;
}
#min:hover {
    -fx-background-color: rgba(64, 158, 255, 1);
    -fx-border-color: rgba(64, 158, 255, 1) rgba(64, 158, 255, 1) rgba(64, 158, 255, 1) rgba(64, 158, 255, 1);
    -fx-text-fill: rgba(255, 255, 255, 1);
}
#max:hover {
    -fx-background-color: rgba(64, 158, 255, 1);
    -fx-border-color: rgba(64, 158, 255, 1) rgba(64, 158, 255, 1) rgba(64, 158, 255, 1) rgba(64, 158, 255, 1);
    -fx-text-fill: rgba(255, 255, 255, 1);
}
#close:hover {
    -fx-background-color: rgba(64, 158, 255, 1);
    -fx-border-color: rgba(64, 158, 255, 1) rgba(64, 158, 255, 1) rgba(64, 158, 255, 1) rgba(64, 158, 255, 1);
    -fx-text-fill: rgba(255, 255, 255, 1);
}
#min:pressed {
    -fx-background-color: rgba(58, 142, 230, 1);
    -fx-border-color: rgba(58, 142, 230, 1) rgba(58, 142, 230, 1) rgba(58, 142, 230, 1) rgba(58, 142, 230, 1);
    -fx-text-fill: rgba(255, 255, 255, 1);
}
#max:pressed {
    -fx-background-color: rgba(58, 142, 230, 1);
    -fx-border-color: rgba(58, 142, 230, 1) rgba(58, 142, 230, 1) rgba(58, 142, 230, 1) rgba(58, 142, 230, 1);
    -fx-text-fill: rgba(255, 255, 255, 1);
}
#close:pressed {
    -fx-background-color: rgba(58, 142, 230, 1);
    -fx-border-color: rgba(58, 142, 230, 1) rgba(58, 142, 230, 1) rgba(58, 142, 230, 1) rgba(58, 142, 230, 1);
    -fx-text-fill: rgba(255, 255, 255, 1);
}

tophbox.css

#topHBox{
    -fx-padding: 0px 0px 5px 0px;
    -fx-alignment: center;
    -fx-spacing: 10px;
}

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

库尔班Java之路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值